1// Copyright 2024 The BoringSSL Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15#include <openssl/base.h> 16 17#include <assert.h> 18#include <stdint.h> 19#include <string.h> 20 21#include "../../internal.h" 22#include "./address.h" 23#include "./params.h" 24#include "./thash.h" 25#include "./wots.h" 26 27 28// Implements Algorithm 5: chain function, page 18 29static void chain(uint8_t output[BCM_SLHDSA_SHA2_128S_N], 30 const uint8_t input[BCM_SLHDSA_SHA2_128S_N], uint32_t start, 31 uint32_t steps, const uint8_t pub_seed[BCM_SLHDSA_SHA2_128S_N], 32 uint8_t addr[32]) { 33 assert(start < SLHDSA_SHA2_128S_WOTS_W); 34 assert(steps < SLHDSA_SHA2_128S_WOTS_W); 35 36 OPENSSL_memcpy(output, input, BCM_SLHDSA_SHA2_128S_N); 37 38 for (size_t i = start; i < (start + steps) && i < SLHDSA_SHA2_128S_WOTS_W; 39 ++i) { 40 slhdsa_set_hash_addr(addr, i); 41 slhdsa_thash_f(output, output, pub_seed, addr); 42 } 43} 44 45static void slhdsa_wots_do_chain(uint8_t out[BCM_SLHDSA_SHA2_128S_N], 46 uint8_t sk_addr[32], uint8_t addr[32], 47 uint8_t value, 48 const uint8_t sk_seed[BCM_SLHDSA_SHA2_128S_N], 49 const uint8_t pub_seed[BCM_SLHDSA_SHA2_128S_N], 50 uint32_t chain_index) { 51 uint8_t tmp_sk[BCM_SLHDSA_SHA2_128S_N]; 52 slhdsa_set_chain_addr(sk_addr, chain_index); 53 slhdsa_thash_prf(tmp_sk, pub_seed, sk_seed, sk_addr); 54 slhdsa_set_chain_addr(addr, chain_index); 55 chain(out, tmp_sk, 0, value, pub_seed, addr); 56} 57 58// Implements Algorithm 6: wots_pkGen function, page 18 59void slhdsa_wots_pk_gen(uint8_t pk[BCM_SLHDSA_SHA2_128S_N], 60 const uint8_t sk_seed[BCM_SLHDSA_SHA2_128S_N], 61 const uint8_t pub_seed[BCM_SLHDSA_SHA2_128S_N], 62 uint8_t addr[32]) { 63 uint8_t wots_pk_addr[32], sk_addr[32]; 64 OPENSSL_memcpy(wots_pk_addr, addr, sizeof(wots_pk_addr)); 65 OPENSSL_memcpy(sk_addr, addr, sizeof(sk_addr)); 66 slhdsa_set_type(sk_addr, SLHDSA_SHA2_128S_ADDR_TYPE_WOTSPRF); 67 slhdsa_copy_keypair_addr(sk_addr, addr); 68 69 uint8_t tmp[SLHDSA_SHA2_128S_WOTS_BYTES]; 70 for (size_t i = 0; i < SLHDSA_SHA2_128S_WOTS_LEN; ++i) { 71 slhdsa_wots_do_chain(tmp + i * BCM_SLHDSA_SHA2_128S_N, sk_addr, addr, 72 SLHDSA_SHA2_128S_WOTS_W - 1, sk_seed, pub_seed, i); 73 } 74 75 // Compress pk 76 slhdsa_set_type(wots_pk_addr, SLHDSA_SHA2_128S_ADDR_TYPE_WOTSPK); 77 slhdsa_copy_keypair_addr(wots_pk_addr, addr); 78 slhdsa_thash_tl(pk, tmp, pub_seed, wots_pk_addr); 79} 80 81// Implements Algorithm 7: wots_sign function, page 20 82void slhdsa_wots_sign(uint8_t sig[SLHDSA_SHA2_128S_WOTS_BYTES], 83 const uint8_t msg[BCM_SLHDSA_SHA2_128S_N], 84 const uint8_t sk_seed[BCM_SLHDSA_SHA2_128S_N], 85 const uint8_t pub_seed[BCM_SLHDSA_SHA2_128S_N], 86 uint8_t addr[32]) { 87 // Compute checksum 88 static_assert(SLHDSA_SHA2_128S_WOTS_LEN1 == BCM_SLHDSA_SHA2_128S_N * 2); 89 uint16_t csum = 0; 90 for (size_t i = 0; i < BCM_SLHDSA_SHA2_128S_N; ++i) { 91 csum += SLHDSA_SHA2_128S_WOTS_W - 1 - (msg[i] >> 4); 92 csum += SLHDSA_SHA2_128S_WOTS_W - 1 - (msg[i] & 15); 93 } 94 95 // Compute chains 96 uint8_t sk_addr[32]; 97 OPENSSL_memcpy(sk_addr, addr, sizeof(sk_addr)); 98 slhdsa_set_type(sk_addr, SLHDSA_SHA2_128S_ADDR_TYPE_WOTSPRF); 99 slhdsa_copy_keypair_addr(sk_addr, addr); 100 101 uint32_t chain_index = 0; 102 for (size_t i = 0; i < BCM_SLHDSA_SHA2_128S_N; ++i) { 103 slhdsa_wots_do_chain(sig, sk_addr, addr, msg[i] >> 4, sk_seed, pub_seed, 104 chain_index++); 105 sig += BCM_SLHDSA_SHA2_128S_N; 106 107 slhdsa_wots_do_chain(sig, sk_addr, addr, msg[i] & 15, sk_seed, pub_seed, 108 chain_index++); 109 sig += BCM_SLHDSA_SHA2_128S_N; 110 } 111 112 // Include the SLHDSA_SHA2_128S_WOTS_LEN2 checksum values. 113 slhdsa_wots_do_chain(sig, sk_addr, addr, (csum >> 8) & 15, sk_seed, pub_seed, 114 chain_index++); 115 sig += BCM_SLHDSA_SHA2_128S_N; 116 slhdsa_wots_do_chain(sig, sk_addr, addr, (csum >> 4) & 15, sk_seed, pub_seed, 117 chain_index++); 118 sig += BCM_SLHDSA_SHA2_128S_N; 119 slhdsa_wots_do_chain(sig, sk_addr, addr, csum & 15, sk_seed, pub_seed, 120 chain_index++); 121} 122 123static void slhdsa_wots_pk_from_sig_do_chain( 124 uint8_t out[SLHDSA_SHA2_128S_WOTS_BYTES], uint8_t addr[32], 125 const uint8_t in[SLHDSA_SHA2_128S_WOTS_BYTES], uint8_t value, 126 const uint8_t pub_seed[BCM_SLHDSA_SHA2_128S_N], uint32_t chain_index) { 127 slhdsa_set_chain_addr(addr, chain_index); 128 chain(out + chain_index * BCM_SLHDSA_SHA2_128S_N, 129 in + chain_index * BCM_SLHDSA_SHA2_128S_N, value, 130 SLHDSA_SHA2_128S_WOTS_W - 1 - value, pub_seed, addr); 131} 132 133// Implements Algorithm 8: wots_pkFromSig function, page 21 134void slhdsa_wots_pk_from_sig(uint8_t pk[BCM_SLHDSA_SHA2_128S_N], 135 const uint8_t sig[SLHDSA_SHA2_128S_WOTS_BYTES], 136 const uint8_t msg[BCM_SLHDSA_SHA2_128S_N], 137 const uint8_t pub_seed[BCM_SLHDSA_SHA2_128S_N], 138 uint8_t addr[32]) { 139 // Compute checksum 140 static_assert(SLHDSA_SHA2_128S_WOTS_LEN1 == BCM_SLHDSA_SHA2_128S_N * 2); 141 uint16_t csum = 0; 142 for (size_t i = 0; i < BCM_SLHDSA_SHA2_128S_N; ++i) { 143 csum += SLHDSA_SHA2_128S_WOTS_W - 1 - (msg[i] >> 4); 144 csum += SLHDSA_SHA2_128S_WOTS_W - 1 - (msg[i] & 15); 145 } 146 147 uint8_t tmp[SLHDSA_SHA2_128S_WOTS_BYTES]; 148 uint8_t wots_pk_addr[32]; 149 OPENSSL_memcpy(wots_pk_addr, addr, sizeof(wots_pk_addr)); 150 151 uint32_t chain_index = 0; 152 static_assert(SLHDSA_SHA2_128S_WOTS_LEN1 == BCM_SLHDSA_SHA2_128S_N * 2); 153 for (size_t i = 0; i < BCM_SLHDSA_SHA2_128S_N; ++i) { 154 slhdsa_wots_pk_from_sig_do_chain(tmp, addr, sig, msg[i] >> 4, pub_seed, 155 chain_index++); 156 slhdsa_wots_pk_from_sig_do_chain(tmp, addr, sig, msg[i] & 15, pub_seed, 157 chain_index++); 158 } 159 160 slhdsa_wots_pk_from_sig_do_chain(tmp, addr, sig, csum >> 8, pub_seed, 161 chain_index++); 162 slhdsa_wots_pk_from_sig_do_chain(tmp, addr, sig, (csum >> 4) & 15, pub_seed, 163 chain_index++); 164 slhdsa_wots_pk_from_sig_do_chain(tmp, addr, sig, csum & 15, pub_seed, 165 chain_index++); 166 167 // Compress pk 168 slhdsa_set_type(wots_pk_addr, SLHDSA_SHA2_128S_ADDR_TYPE_WOTSPK); 169 slhdsa_copy_keypair_addr(wots_pk_addr, addr); 170 slhdsa_thash_tl(pk, tmp, pub_seed, wots_pk_addr); 171} 172