9#include <botan/internal/lm_ots.h>
11#include <botan/exceptn.h>
12#include <botan/strong_type.h>
13#include <botan/internal/bit_ops.h>
14#include <botan/internal/hss_lms_utils.h>
15#include <botan/internal/int_utils.h>
20constexpr uint16_t D_PBLC = 0x8080;
21constexpr uint16_t D_MESG = 0x8181;
23constexpr uint16_t C_INDEX = 0xFFFD;
25class Chain_Generator {
31 void process(HashFunction& hash,
35 std::span<const uint8_t> in,
36 std::span<uint8_t> out) {
40 m_gen.set_i(chain_idx);
42 for(uint8_t j = start; j < end; ++j) {
44 m_gen.gen(out, hash, out);
49 PseudorandomKeyGeneration m_gen;
53uint8_t
byte(std::span<const uint8_t> S, uint32_t i) {
59uint8_t coef(std::span<const uint8_t> S, uint32_t i,
const LMOTS_Params& params) {
60 const uint8_t w_bit_mask = params.coef_max();
61 const uint8_t coef_byte =
byte(S, (i * params.w()) / 8);
62 const uint8_t shift = 8 - (params.w() * (i % (8 / params.w())) + params.w());
64 return w_bit_mask & (coef_byte >> shift);
68uint16_t checksum(
const LMOTS_Params& params, std::span<const uint8_t> S) {
70 for(uint32_t i = 0; i < (params.n() * 8 / params.w()); ++i) {
71 sum += params.coef_max() - coef(S, i, params);
76std::vector<uint8_t> gen_Q_with_cksm(
const LMOTS_Params& params,
79 std::span<const uint8_t> C,
81 std::vector<uint8_t> Q_with_cksm(params.n() +
sizeof(uint16_t));
82 BufferStuffer qwc_stuffer(Q_with_cksm);
83 const auto hash = params.hash();
84 hash->update(identifier);
89 auto Q_span = qwc_stuffer.next(params.n());
92 qwc_stuffer.append(
store_be(checksum(params, Q_span)));
103 return {
"SHA-256", 1};
105 return {
"SHA-256", 2};
107 return {
"SHA-256", 4};
109 return {
"SHA-256", 8};
111 return {
"Truncated(SHA-256,192)", 1};
113 return {
"Truncated(SHA-256,192)", 2};
115 return {
"Truncated(SHA-256,192)", 4};
117 return {
"Truncated(SHA-256,192)", 8};
119 return {
"SHAKE-256(256)", 1};
121 return {
"SHAKE-256(256)", 2};
123 return {
"SHAKE-256(256)", 4};
125 return {
"SHAKE-256(256)", 8};
127 return {
"SHAKE-256(192)", 1};
129 return {
"SHAKE-256(192)", 2};
131 return {
"SHAKE-256(192)", 4};
133 return {
"SHAKE-256(192)", 8};
144 if(
w != 1 &&
w != 2 &&
w != 4 &&
w != 8) {
148 if(
hash ==
"SHA-256") {
162 if(
hash ==
"Truncated(SHA-256,192)") {
176 if(
hash ==
"SHAKE-256(256)") {
190 if(
hash ==
"SHAKE-256(192)") {
210LMOTS_Params::LMOTS_Params(
LMOTS_Algorithm_Type algorithm_type, std::string_view hash_name, uint8_t w) :
211 m_algorithm_type(algorithm_type), m_w(w), m_hash_name(hash_name) {
213 m_n =
hash->output_length();
222 std::vector<uint8_t> C,
223 std::vector<uint8_t> y_buffer) :
224 m_algorithm_type(lmots_type), m_C(std::move(C)), m_y_buffer(std::move(y_buffer)) {
227 BufferSlicer y_slicer(m_y_buffer);
228 for(uint16_t i = 0; i < params.p(); ++i) {
229 m_y.push_back(y_slicer.take<
LMOTS_Node>(params.n()));
235 size_t total_remaining_bytes = slicer.
remaining();
238 throw Decoding_Error(
"Too few signature bytes while parsing LMOTS signature.");
246 if(total_remaining_bytes <
size(params)) {
247 throw Decoding_Error(
"Too few signature bytes while parsing LMOTS signature.");
269 for(uint16_t i = 0; i <
params.
p(); ++i) {
280 const auto C = sig_stuffer.
next(
params().n());
285 derive_random_C(C, *hash);
290 for(uint16_t i = 0; i <
params().
p(); ++i) {
292 const uint8_t a = coef(Q_with_cksm, i,
params());
293 chain_gen.process(*hash, i, 0, a,
chain_input(i), y_i);
298void LMOTS_Private_Key::derive_random_C(std::span<uint8_t> out,
HashFunction& hash)
const {
301 gen.set_q(
q().get());
305 gen.gen(out, hash, m_seed);
309 const auto pk_hash = lmots_sk.
params().
hash();
314 Chain_Generator chain_gen(lmots_sk.
identifier(), lmots_sk.
q());
317 for(uint16_t i = 0; i < lmots_sk.
params().p(); ++i) {
319 pk_hash->update(tmp);
322 m_K = pk_hash->final<
LMOTS_K>();
333 const auto Q_with_cksm = gen_Q_with_cksm(params, identifier, q, sig.
C(), msg);
336 const auto pk_hash = params.hash();
337 pk_hash->update(identifier);
341 Chain_Generator chain_gen(identifier, q);
342 const auto hash = params.hash();
344 for(uint16_t i = 0; i < params.p(); ++i) {
345 const uint8_t a = coef(Q_with_cksm, i, params);
346 chain_gen.process(*hash, i, a, params.coef_max(), sig.
y(i), tmp);
347 pk_hash->update(tmp);
350 return pk_hash->final<
LMOTS_K>();
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ARG_CHECK(expr, msg)
std::span< const uint8_t > take(const size_t count)
auto copy_as_vector(const size_t count)
Helper class to ease in-place marshalling of concatenated fixed-length values.
constexpr void append(std::span< const uint8_t > buffer)
constexpr std::span< uint8_t > next(size_t bytes)
constexpr bool full() const
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
static LMOTS_Params create_or_throw(LMOTS_Algorithm_Type type)
Create the LM-OTS parameters from a known algorithm type.
uint8_t coef_max() const
The maximum the winternitz coefficients can have.
std::unique_ptr< HashFunction > hash() const
Construct a new hash instance for the OTS instance.
size_t n() const
The number of bytes of the output of the hash function.
uint8_t w() const
The width (in bits) of the Winternitz coefficients.
const std::string & hash_name() const
Name of the hash function to use.
uint16_t p() const
The number of n-byte string elements that make up the LM-OTS signature.
Representation of an LMOTS private key.
const LMOTS_Node & chain_input(uint16_t chain_idx) const
The secret chain input at a given chain index. (x[] in RFC 8554 4.2).
void sign(StrongSpan< LMOTS_Signature_Bytes > out_sig, const LMS_Message &msg) const
Generate a new LMOTS signature.
LMOTS_Private_Key(const LMOTS_Params ¶ms, const LMS_Identifier &identifier, LMS_Tree_Node_Idx q, const LMS_Seed &seed)
Derive a LMOTS private key for a given seed.
LMOTS_Public_Key(const LMOTS_Private_Key &lmots_sk)
Derivivation of an LMOTS public key using an LMOTS_Private_Key as defined in RFC 8554 4....
Representation of a LM-OTS signature.
static size_t size(const LMOTS_Params ¶ms)
The expected size of the signature.
StrongSpan< const LMOTS_Node > y(uint16_t chain_idx) const
Returns the part of the signature for chain_idx.
LMOTS_Algorithm_Type algorithm_type() const
Returns the LM-OTS algorithm type.
static LMOTS_Signature from_bytes_or_throw(BufferSlicer &slicer)
Parse a LM-OTS signature.
std::span< const uint8_t > C() const
The n-byte randomizer of the signature.
Base class for LMOTS private and public key. Contains the parameters for the specific OTS instance.
const LMS_Identifier & identifier() const
The LMS identifier of the LMS tree containing this OTS instance ('I' in RFC 8554)
LMS_Tree_Node_Idx q() const
The index of the LMS tree leaf associated with this OTS instance.
const LMOTS_Params & params() const
The LMOTS parameters.
Helper class used to derive secret values based in the pseudorandom key generation described in RFC 8...
void set_i(uint16_t i)
Specify the value for the u16str(i) hash input field.
void set_j(uint8_t j)
Specify the value for the u8str(j) hash input field.
T gen(HashFunction &hash, std::span< const uint8_t > seed) const
Create a hash value using the preconfigured prefix and a seed.
void set_q(uint32_t q)
Specify the value for the u32str(q) hash input field.
decltype(auto) size() const noexcept(noexcept(this->m_span.size()))
LMOTS_K lmots_compute_pubkey_from_sig(const LMOTS_Signature &sig, const LMS_Message &msg, const LMS_Identifier &identifier, LMS_Tree_Node_Idx q)
Compute a public key candidate for an OTS-signature-message pair and the OTS instance parameters.
constexpr RT checked_cast_to(AT i)
constexpr size_t high_bit(T n)
Strong< std::vector< uint8_t >, struct LMS_Identifier_ > LMS_Identifier
The identifier of an LMS tree (I in RFC 8554)
LMOTS_Algorithm_Type
Enum of available LM-OTS algorithm types.
constexpr T ceil_division(T a, T b)
Strong< secure_vector< uint8_t >, struct LMOTS_Node_ > LMOTS_Node
One node within one LM-OTS hash chain.
Strong< std::vector< uint8_t >, struct LMS_Message_ > LMS_Message
A message that is signed with an LMS tree.
Strong< uint32_t, struct LMS_Tree_Node_Idx_, EnableArithmeticWithPlainNumber > LMS_Tree_Node_Idx
The index of a node within a specific LMS tree layer.
constexpr void copy_mem(T *out, const T *in, size_t n)
constexpr auto store_be(ParamTs &&... params)
constexpr auto load_be(ParamTs &&... params)