Skip to content

Commit

Permalink
Apply 1st review suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
atreiber94 committed Oct 17, 2023
1 parent a3e531c commit 4aaec3c
Show file tree
Hide file tree
Showing 11 changed files with 186 additions and 180 deletions.
26 changes: 11 additions & 15 deletions src/lib/pubkey/frodokem/frodo_constants.cpp
Original file line number Diff line number Diff line change
@@ -1,30 +1,26 @@
/*
* FrodoKEM modes and constants
* Based on the MIT licensed reference implementation by the designers
* (https://github.com/microsoft/PQCrypto-LWEKE/tree/master/src)
*
* The Fellowship of the FrodoKEM:
* (C) 2023 Jack Lloyd
* 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
* FrodoKEM modes and constants
* Based on the MIT licensed reference implementation by the designers
* (https://github.com/microsoft/PQCrypto-LWEKE/tree/master/src)
*
* The Fellowship of the FrodoKEM:
* (C) 2023 Jack Lloyd
* 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/internal/frodo_constants.h>

#include <botan/xof.h>

namespace Botan {

FrodoKEMConstants::FrodoKEMConstants(FrodoKEMMode mode) : m_mode(mode) {
FrodoKEMConstants::FrodoKEMConstants(FrodoKEMMode mode) : m_mode(mode), m_len_a(128), m_n_bar(8) {
#if !defined(BOTAN_HAS_AES)
BOTAN_ARG_CHECK(!mode.is_aes(), "cannot instantiate AES-based FrodoKEM: This build does not support AES");
#endif

//Common for all parameter sets:
m_n_bar = 8;
m_len_a = 128;

if(mode.is_ephemeral()) {
m_len_salt = 0;
}
Expand Down
32 changes: 16 additions & 16 deletions src/lib/pubkey/frodokem/frodo_constants.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/*
* FrodoKEM constants
* Based on the MIT licensed reference implementation by the designers
* (https://github.com/microsoft/PQCrypto-LWEKE/tree/master/src)
*
* The Fellowship of the FrodoKEM:
* (C) 2023 Jack Lloyd
* 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
* FrodoKEM constants
* Based on the MIT licensed reference implementation by the designers
* (https://github.com/microsoft/PQCrypto-LWEKE/tree/master/src)
*
* The Fellowship of the FrodoKEM:
* (C) 2023 Jack Lloyd
* 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#ifndef BOTAN_FRODOKEM_CONSTANTS_H_
#define BOTAN_FRODOKEM_CONSTANTS_H_
Expand Down Expand Up @@ -46,9 +46,9 @@ class BOTAN_TEST_API FrodoKEMConstants {

size_t n() const { return m_n; }

size_t b() const { return m_b; }
size_t b() const { return m_b; } // extracted bits

size_t d() const { return m_d; } //D = logq
size_t d() const { return m_d; } // D = logq

size_t n_bar() const { return m_n_bar; }

Expand All @@ -62,7 +62,7 @@ class BOTAN_TEST_API FrodoKEMConstants {

size_t len_ct_bytes() const {
return (m_d * m_n * m_n_bar + m_d * m_n_bar * m_n_bar + m_len_salt) / 8;
} //Ciphertext length in bytes
} // Ciphertext length in bytes

size_t len_public_key_bytes() const { return (m_len_a + (m_d * m_n * m_n_bar)) / 8; }

Expand All @@ -84,14 +84,14 @@ class BOTAN_TEST_API FrodoKEMConstants {

private:
FrodoKEMMode m_mode;
size_t m_nist_strength; //len_sec
size_t m_nist_strength;
size_t m_len_salt;
size_t m_len_se;
size_t m_len_a;
size_t m_b; //extracted bits
size_t m_b;
size_t m_n;
size_t m_n_bar;
size_t m_d; //log_q
size_t m_d;

std::vector<uint16_t> m_cdf_table; // Distribution table T_chi

Expand Down
68 changes: 18 additions & 50 deletions src/lib/pubkey/frodokem/frodo_matrix.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
/*
* FrodoKEM matrix logic
* Based on the MIT licensed reference implementation by the designers
* (https://github.com/microsoft/PQCrypto-LWEKE/tree/master/src)
*
* The Fellowship of the FrodoKEM:
* (C) 2023 Jack Lloyd
* 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
* FrodoKEM matrix logic
* Based on the MIT licensed reference implementation by the designers
* (https://github.com/microsoft/PQCrypto-LWEKE/tree/master/src)
*
* The Fellowship of the FrodoKEM:
* (C) 2023 Jack Lloyd
* 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/internal/frodo_matrix.h>

#include <botan/assert.h>
#include <botan/frodokem.h>
Expand All @@ -20,7 +22,6 @@
#include <botan/internal/bit_ops.h>
#include <botan/internal/ct_utils.h>
#include <botan/internal/frodo_constants.h>
#include <botan/internal/frodo_matrix.h>
#include <botan/internal/loadstor.h>
#include <botan/internal/shake_xof.h>
#include <botan/internal/stl_util.h>
Expand All @@ -38,8 +39,8 @@ namespace Botan {

namespace {

std::vector<uint16_t> make_elements_vector(const FrodoMatrix::Dimensions& dimensions) {
return std::vector<uint16_t>(static_cast<size_t>(std::get<0>(dimensions)) * std::get<1>(dimensions));
secure_vector<uint16_t> make_elements_vector(const FrodoMatrix::Dimensions& dimensions) {
return secure_vector<uint16_t>(static_cast<size_t>(std::get<0>(dimensions)) * std::get<1>(dimensions));
}

std::function<void(std::span<uint8_t> out, uint16_t i)> make_row_generator(const FrodoKEMConstants& constants,
Expand Down Expand Up @@ -96,9 +97,6 @@ std::function<void(std::span<uint8_t> out, uint16_t i)> make_row_generator(const
FrodoMatrix FrodoMatrix::sample(const FrodoKEMConstants& constants,
const Dimensions& dimensions,
StrongSpan<const FrodoSampleR> r) {
// Creates a matrix with n samples from the noise distribution which requires 16 bits to sample.
// The distribution is specified by its CDF.
// Input: pseudo-random values (2*n bytes) passed in r.
BOTAN_ASSERT_NOMSG(r.size() % 2 == 0);
const auto n = r.size() / 2;

Expand Down Expand Up @@ -131,10 +129,6 @@ FrodoMatrix FrodoMatrix::mul_add_as_plus_e(const FrodoKEMConstants& constants,
const FrodoMatrix& s,
const FrodoMatrix& e,
StrongSpan<const FrodoSeedA> seed_a) {
// Generate-and-multiply: generate matrix A (N x N) row-wise, multiply by s on the right.
// Inputs: s^T (N_BAR x N), e (N x N_BAR), seed for matrix A
// Output: The elements of the FrodoMatrix will correspond to A*s + e (N x N_BAR).

BOTAN_ASSERT(std::get<0>(e.dimensions()) == std::get<1>(s.dimensions()) &&
std::get<1>(e.dimensions()) == std::get<0>(s.dimensions()),
"FrodoMatrix dimension mismatch of E and S");
Expand Down Expand Up @@ -195,11 +189,6 @@ FrodoMatrix FrodoMatrix::mul_add_sa_plus_e(const FrodoKEMConstants& constants,
const FrodoMatrix& s,
const FrodoMatrix& e,
StrongSpan<const FrodoSeedA> seed_a) {
// Generate-and-multiply: generate matrix A (N x N) column-wise, multiply by s' on the left.
// Inputs: s', e' (N_BAR x N)
// Output: out = s'*A + e' (N_BAR x N)
// The matrix multiplication uses the row-wise blocking and packing (RWCF) approach described in: J.W. Bos, M. Ofner, J. Renes,
// T. Schneider, C. van Vredendaal, "The Matrix Reloaded: Multiplication Strategies in FrodoKEM". https://eprint.iacr.org/2021/711
BOTAN_ASSERT(std::get<0>(e.dimensions()) == std::get<0>(s.dimensions()) &&
std::get<1>(e.dimensions()) == std::get<1>(s.dimensions()),
"FrodoMatrix dimension mismatch of E and S");
Expand Down Expand Up @@ -258,9 +247,6 @@ FrodoMatrix FrodoMatrix::mul_add_sb_plus_e(const FrodoKEMConstants& constants,
const FrodoMatrix& b,
const FrodoMatrix& s,
const FrodoMatrix& e) {
// Multiply by s on the left
// Inputs: b (N x N_BAR), s (N_BAR x N), e (N_BAR x N_BAR)
// Output: out = s*b + e (N_BAR x N_BAR). The existing elements are overwritten and a self reference is returned.
BOTAN_ASSERT(std::get<0>(b.dimensions()) == std::get<1>(s.dimensions()) &&
std::get<1>(b.dimensions()) == std::get<0>(s.dimensions()),
"FrodoMatrix dimension mismatch of B and S");
Expand Down Expand Up @@ -308,12 +294,7 @@ FrodoMatrix FrodoMatrix::encode(const FrodoKEMConstants& constants, StrongSpan<c
return FrodoMatrix(dimensions, std::move(elements));
}

FrodoMatrix FrodoMatrix::add(const FrodoKEMConstants& constants,
const FrodoMatrix& a,
const FrodoMatrix& b) { // Add a and b
// Inputs: a, b (N_BAR x N_BAR)
// Output: c = a + b

FrodoMatrix FrodoMatrix::add(const FrodoKEMConstants& constants, const FrodoMatrix& a, const FrodoMatrix& b) {
// Addition is defined for n_bar x n_bar matrices only
BOTAN_ASSERT_NOMSG(a.dimensions() == b.dimensions());
BOTAN_ASSERT_NOMSG(std::get<0>(a.dimensions()) == constants.n_bar() &&
Expand All @@ -328,12 +309,7 @@ FrodoMatrix FrodoMatrix::add(const FrodoKEMConstants& constants,
return FrodoMatrix(a.dimensions(), std::move(elements));
}

FrodoMatrix FrodoMatrix::sub(const FrodoKEMConstants& constants,
const FrodoMatrix& a,
const FrodoMatrix& b) { // Subtract a and b
// Inputs: a, b (N_BAR x N_BAR)
// Output: c = a - b

FrodoMatrix FrodoMatrix::sub(const FrodoKEMConstants& constants, const FrodoMatrix& a, const FrodoMatrix& b) {
// Subtraction is defined for n_bar x n_bar matrices only
BOTAN_ASSERT_NOMSG(a.dimensions() == b.dimensions());
BOTAN_ASSERT_NOMSG(std::get<0>(a.dimensions()) == constants.n_bar() &&
Expand All @@ -357,11 +333,7 @@ bool FrodoMatrix::constant_time_compare(const FrodoMatrix& other) const {
sizeof(decltype(m_elements)::value_type) * m_elements.size());
}

FrodoMatrix FrodoMatrix::mul_bs(const FrodoKEMConstants& constants,
const FrodoMatrix& b,
const FrodoMatrix& s) { // Multiply by s on the right
// Inputs: b (N_BAR x N), s^T (N_BAR x N)
// Output: out = b*s (N_BAR x N_BAR)
FrodoMatrix FrodoMatrix::mul_bs(const FrodoKEMConstants& constants, const FrodoMatrix& b, const FrodoMatrix& s) {
Dimensions dimensions = {constants.n_bar(), constants.n_bar()};
auto elements = make_elements_vector(dimensions);

Expand All @@ -382,7 +354,6 @@ FrodoMatrix FrodoMatrix::mul_bs(const FrodoKEMConstants& constants,
}

void FrodoMatrix::pack(const FrodoKEMConstants& constants, StrongSpan<FrodoPackedMatrix> out) const {
// Pack m_elements into a output buffer, copying lsb = D = log2 q bits from each input element.
const size_t outlen = packed_size(constants);
BOTAN_ASSERT_NOMSG(out.size() == outlen);

Expand Down Expand Up @@ -468,9 +439,6 @@ FrodoPlaintext FrodoMatrix::decode(const FrodoKEMConstants& constants) const {
FrodoMatrix FrodoMatrix::unpack(const FrodoKEMConstants& constants,
const Dimensions& dimensions,
StrongSpan<const FrodoPackedMatrix> packed_bytes) {
// Unpack the input char vector into the 16 bit m_elements vector, copying lsb bits
// for each output element from input. outlen must be at least ceil(inlen * 8 / lsb).
// m_elements is allocated here.
const uint8_t lsb = static_cast<uint8_t>(constants.d());
const size_t inlen = packed_bytes.size();
const size_t outlen = static_cast<size_t>(std::get<0>(dimensions)) * std::get<1>(dimensions);
Expand Down Expand Up @@ -526,7 +494,7 @@ FrodoMatrix FrodoMatrix::unpack(const FrodoKEMConstants& constants,
}

FrodoMatrix FrodoMatrix::deserialize(const Dimensions& dimensions, StrongSpan<const FrodoSerializedMatrix> bytes) {
std::vector<uint16_t> elements = make_elements_vector(dimensions);
auto elements = make_elements_vector(dimensions);
BOTAN_ASSERT_NOMSG(elements.size() * 2 == bytes.size());
load_le<uint16_t>(elements.data(), bytes.data(), elements.size());
return FrodoMatrix(dimensions, std::move(elements));
Expand Down
86 changes: 57 additions & 29 deletions src/lib/pubkey/frodokem/frodo_matrix.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/*
* FrodoKEM matrix logic
* Based on the MIT licensed reference implementation by the designers
* (https://github.com/microsoft/PQCrypto-LWEKE/tree/master/src)
*
* The Fellowship of the FrodoKEM:
* (C) 2023 Jack Lloyd
* 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
* FrodoKEM matrix logic
* Based on the MIT licensed reference implementation by the designers
* (https://github.com/microsoft/PQCrypto-LWEKE/tree/master/src)
*
* The Fellowship of the FrodoKEM:
* (C) 2023 Jack Lloyd
* 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#ifndef BOTAN_FRODOKEM_MATRIX_H_
#define BOTAN_FRODOKEM_MATRIX_H_
Expand Down Expand Up @@ -43,41 +43,73 @@ class FrodoMatrix {
return out;
}

void pack(const FrodoKEMConstants& constants,
StrongSpan<FrodoPackedMatrix> out) const; //Section 7.3 of spec
// Pack m_elements into a output buffer, copying lsb = D = log2 q bits from each input element.
// Section 7.3 of spec
void pack(const FrodoKEMConstants& constants, StrongSpan<FrodoPackedMatrix> out) const;

FrodoSerializedMatrix serialize() const;

FrodoPlaintext decode(const FrodoKEMConstants& constants) const;

// Unpack the input FrodoPackedMatrix into the 16 bit m_elements vector, copying d bits
// for each output element from input. outlen must be at least ceil(inlen * 8 / d).
// m_elements is allocated here.
static FrodoMatrix unpack(const FrodoKEMConstants& constants,
const Dimensions& dimensions,
StrongSpan<const FrodoPackedMatrix> packed_bytes);

static FrodoMatrix deserialize(const Dimensions& dimensions, StrongSpan<const FrodoSerializedMatrix> bytes);

static FrodoMatrix encode(const FrodoKEMConstants& constants,
StrongSpan<const FrodoPlaintext> in); //Section 7.2 of spec
StrongSpan<const FrodoPlaintext> in); // Section 7.2 of spec

// Creates a matrix with n samples from the noise distribution which requires 16 bits to sample.
// The distribution is specified by its CDF.
// Input: pseudo-random values (2*n bytes) passed in r.
// Section 7.5 of spec
static FrodoMatrix sample(const FrodoKEMConstants& constants,
const Dimensions& dimensions,
StrongSpan<const FrodoSampleR> r);

static FrodoMatrix sample(
const FrodoKEMConstants& constants,
const Dimensions& dimensions,
StrongSpan<const FrodoSampleR> r); // Matrix sampling from the error distribution, Section 7.5 of spec
// Generate-and-multiply: generate matrix A (N x N) row-wise, multiply by s on the right.
// Inputs: s^T (N_BAR x N), e (N x N_BAR), seed for matrix A
// Output: The elements of the FrodoMatrix will correspond to A*s + e (N x N_BAR).
static FrodoMatrix mul_add_as_plus_e(const FrodoKEMConstants& constants,
const FrodoMatrix& s,
const FrodoMatrix& e,
StrongSpan<const FrodoSeedA> seed_a); //A*s + e
StrongSpan<const FrodoSeedA> seed_a);

// Generate-and-multiply: generate matrix A (N x N) column-wise, multiply by s' on the left.
// Inputs: s', e' (N_BAR x N)
// Output: out = s'*A + e' (N_BAR x N)
// The matrix multiplication uses the row-wise blocking and packing (RWCF) approach described in: J.W. Bos, M. Ofner, J. Renes,
// T. Schneider, C. van Vredendaal, "The Matrix Reloaded: Multiplication Strategies in FrodoKEM". https://eprint.iacr.org/2021/711
static FrodoMatrix mul_add_sa_plus_e(const FrodoKEMConstants& constants,
const FrodoMatrix& s,
const FrodoMatrix& e,
StrongSpan<const FrodoSeedA> seed_a); //s*A + e
StrongSpan<const FrodoSeedA> seed_a);

// Multiply by s on the left
// Inputs: b (N x N_BAR), s (N_BAR x N), e (N_BAR x N_BAR)
// Output: out = s*b + e (N_BAR x N_BAR). The existing elements are overwritten and a self reference is returned.
static FrodoMatrix mul_add_sb_plus_e(const FrodoKEMConstants& constants,
const FrodoMatrix& b,
const FrodoMatrix& s,
const FrodoMatrix& e); //s*B + e
static FrodoMatrix mul_bs(const FrodoKEMConstants& constants,
const FrodoMatrix& b_p,
const FrodoMatrix& s); // B * s
const FrodoMatrix& e);

// Multiply by s on the right
// Inputs: b (N_BAR x N), s^T (N_BAR x N)
// Output: out = b*s (N_BAR x N_BAR)
static FrodoMatrix mul_bs(const FrodoKEMConstants& constants, const FrodoMatrix& b_p, const FrodoMatrix& s);

// Add a and b
// Inputs: a, b (N_BAR x N_BAR)
// Output: c = a + b
static FrodoMatrix add(const FrodoKEMConstants& constants, const FrodoMatrix& a, const FrodoMatrix& b);

// Subtract a and b
// Inputs: a, b (N_BAR x N_BAR)
// Output: c = a - b
static FrodoMatrix sub(const FrodoKEMConstants& constants, const FrodoMatrix& a, const FrodoMatrix& b);

Dimensions dimensions() const { return {m_dim1, m_dim2}; }
Expand All @@ -89,18 +121,14 @@ class FrodoMatrix {
void reduce(const FrodoKEMConstants& constants);

private:
FrodoMatrix(const Dimensions& dimensions, std::vector<uint16_t> elements) :
FrodoMatrix(const Dimensions& dimensions, secure_vector<uint16_t> elements) :
m_dim1(std::get<0>(dimensions)), m_dim2(std::get<1>(dimensions)), m_elements(std::move(elements)) {}

private:
size_t m_dim1;
size_t m_dim2;

// This may hold sensitive information (e.g. S and E matrices), though
// it is not modeled as a secure_vector (because it's uint16_t).
//
// TODO: consider allowing to use secure_vector for this
std::vector<uint16_t> m_elements;
secure_vector<uint16_t> m_elements;
};

} // namespace Botan
Expand Down
Loading

0 comments on commit 4aaec3c

Please sign in to comment.