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/ct_utils.h>
15#include <botan/internal/hss_lms_utils.h>
16#include <botan/internal/int_utils.h>
21constexpr uint16_t D_PBLC = 0x8080;
22constexpr uint16_t D_MESG = 0x8181;
24constexpr uint16_t C_INDEX = 0xFFFD;
26class Chain_Generator {
32 void process(HashFunction& hash,
36 std::span<const uint8_t> in,
37 std::span<uint8_t> out) {
41 m_gen.set_i(chain_idx);
43 for(uint8_t j = start; j < end; ++j) {
45 m_gen.gen(out, hash, out);
50 PseudorandomKeyGeneration m_gen;
54uint8_t
byte(std::span<const uint8_t> S, uint32_t i) {
60uint8_t coef(std::span<const uint8_t> S, uint32_t i,
const LMOTS_Params& params) {
61 const uint8_t w_bit_mask = params.coef_max();
62 const uint8_t coef_byte =
byte(S, (i * params.w()) / 8);
63 const uint8_t shift = 8 - (params.w() * (i % (8 / params.w())) + params.w());
65 return w_bit_mask & (coef_byte >> shift);
69uint16_t checksum(
const LMOTS_Params& params, std::span<const uint8_t> S) {
71 for(uint32_t i = 0; i < (params.n() * 8 / params.w()); ++i) {
72 sum += params.coef_max() - coef(S, i, params);
77std::vector<uint8_t> gen_Q_with_cksm(
const LMOTS_Params& params,
80 std::span<const uint8_t> C,
82 std::vector<uint8_t> Q_with_cksm(params.n() +
sizeof(uint16_t));
83 BufferStuffer qwc_stuffer(Q_with_cksm);
84 const auto hash = params.hash();
85 hash->update(identifier);
90 auto Q_span = qwc_stuffer.next(params.n());
93 qwc_stuffer.append(
store_be(checksum(params, Q_span)));
104 return {
"SHA-256", 1};
106 return {
"SHA-256", 2};
108 return {
"SHA-256", 4};
110 return {
"SHA-256", 8};
112 return {
"Truncated(SHA-256,192)", 1};
114 return {
"Truncated(SHA-256,192)", 2};
116 return {
"Truncated(SHA-256,192)", 4};
118 return {
"Truncated(SHA-256,192)", 8};
120 return {
"SHAKE-256(256)", 1};
122 return {
"SHAKE-256(256)", 2};
124 return {
"SHAKE-256(256)", 4};
126 return {
"SHAKE-256(256)", 8};
128 return {
"SHAKE-256(192)", 1};
130 return {
"SHAKE-256(192)", 2};
132 return {
"SHAKE-256(192)", 4};
134 return {
"SHAKE-256(192)", 8};
145 if(
w != 1 &&
w != 2 &&
w != 4 &&
w != 8) {
149 if(
hash ==
"SHA-256") {
163 if(
hash ==
"Truncated(SHA-256,192)") {
177 if(
hash ==
"SHAKE-256(256)") {
191 if(
hash ==
"SHAKE-256(192)") {
211LMOTS_Params::LMOTS_Params(
LMOTS_Algorithm_Type algorithm_type, std::string_view hash_name, uint8_t w) :
212 m_algorithm_type(algorithm_type), m_w(w), m_hash_name(hash_name) {
214 m_n =
hash->output_length();
223 std::vector<uint8_t> C,
224 std::vector<uint8_t> y_buffer) :
225 m_algorithm_type(lmots_type), m_C(std::move(C)), m_y_buffer(std::move(y_buffer)) {
228 BufferSlicer y_slicer(m_y_buffer);
229 for(uint16_t i = 0; i < params.p(); ++i) {
230 m_y.push_back(y_slicer.take<
LMOTS_Node>(params.n()));
236 size_t total_remaining_bytes = slicer.
remaining();
239 throw Decoding_Error(
"Too few signature bytes while parsing LMOTS signature.");
247 if(total_remaining_bytes <
size(params)) {
248 throw Decoding_Error(
"Too few signature bytes while parsing LMOTS signature.");
270 for(uint16_t i = 0; i <
params.
p(); ++i) {
281 const auto C = sig_stuffer.
next(
params().n());
286 derive_random_C(C, *hash);
292 for(uint16_t i = 0; i <
params().
p(); ++i) {
293 const auto y_i = sig_stuffer.
next(
params().n());
294 const uint8_t a = coef(Q_with_cksm, i,
params());
295 chain_gen.process(*hash, i, 0, a,
chain_input(i), y_i);
300void LMOTS_Private_Key::derive_random_C(std::span<uint8_t> out,
HashFunction& hash)
const {
303 gen.set_q(
q().get());
307 gen.gen(out, hash, m_seed);
311 const auto pk_hash = lmots_sk.
params().hash();
316 Chain_Generator chain_gen(lmots_sk.
identifier(), lmots_sk.
q());
319 for(uint16_t i = 0; i < lmots_sk.
params().p(); ++i) {
321 pk_hash->update(tmp);
324 m_K = pk_hash->final<
LMOTS_K>();
335 const auto Q_with_cksm = gen_Q_with_cksm(params, identifier, q, sig.
C(), msg);
338 const auto pk_hash = params.hash();
339 pk_hash->update(identifier);
343 Chain_Generator chain_gen(identifier, q);
344 const auto hash = params.hash();
346 for(uint16_t i = 0; i < params.p(); ++i) {
347 const uint8_t a = coef(Q_with_cksm, i, params);
348 chain_gen.process(*hash, i, a, params.coef_max(), sig.
y(i), tmp);
349 pk_hash->update(tmp);
352 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
void update(const uint8_t in[], size_t length)
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()))
constexpr void unpoison(const T *p, size_t n)
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)