Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blake2s review #81

Merged
merged 11 commits into from
Oct 2, 2019
56 changes: 47 additions & 9 deletions src/circuits/blake2s/blake2s_comp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,68 @@ namespace libzeth
const size_t BLAKE2s_digest_size = 256;
const size_t BLAKE2s_block_size = 512;

/// Number of words composing the state of BLAKE2s
const size_t BLAKE2s_word_number = 16;
/// Bit-length of the words composing the state of BLAKE2s
const size_t BLAKE2s_word_size = 32;

/// BLAKE2s_256_comp is the gadget implementing the BLAKE2s
/// compression function for digests of length 256
template<typename FieldT>
class BLAKE2s_256_comp : public libsnark::gadget<FieldT>
{
private:
// Section 2.1 of https://blake2.net/blake2.pdf specifies that BLAKE2s has
// 10 rounds
static const int rounds = 10;
std::array<std::array<FieldT, 32>, 8> h;
std::array<std::array<FieldT, 32>, 2> t;
std::array<libsnark::pb_variable_array<FieldT>, 16> block;
std::array<std::array<libsnark::pb_variable_array<FieldT>, 16>, rounds + 1>

// Finalization flags. See Section 2.3 of https://blake2.net/blake2.pdf
// We do a single call to the compression function: the first block is the
// last. Thus, f0 is set to xFF
const std::array<FieldT, BLAKE2s_word_size> f0 = {
1, 1, 1, 1, 1, 1, 1, 1, // FF
1, 1, 1, 1, 1, 1, 1, 1, // FF
1, 1, 1, 1, 1, 1, 1, 1, // FF
1, 1, 1, 1, 1, 1, 1, 1 // FF
};

// We use the sequential mode, f1 is set to x00
const std::array<FieldT, BLAKE2s_word_size> f1 = {
0, 0, 0, 0, 0, 0, 0, 0, // 00
0, 0, 0, 0, 0, 0, 0, 0, // 00
0, 0, 0, 0, 0, 0, 0, 0, // 00
0, 0, 0, 0, 0, 0, 0, 0 // 00
};

// Chaining values
std::array<std::array<FieldT, BLAKE2s_word_size>, 8> h;

// Low and High words of the offset
std::array<std::array<FieldT, BLAKE2s_word_size>, 2> t;

std::array<libsnark::pb_variable_array<FieldT>, BLAKE2s_word_number> block;
std::array<
std::array<libsnark::pb_variable_array<FieldT>, BLAKE2s_word_number>,
rounds + 1>
v;
std::array<std::array<libsnark::pb_variable_array<FieldT>, 16>, rounds>
std::array<
std::array<libsnark::pb_variable_array<FieldT>, BLAKE2s_word_number>,
rounds>
v_temp;
std::array<libsnark::pb_variable_array<FieldT>, 8> output_bytes;
libsnark::block_variable<FieldT> input_block;
libsnark::digest_variable<FieldT> output;

std::array<std::vector<g_primitive<FieldT>>, 10> g_arrays;
// Array of mixing functions G used in each rounds in the compression
// function
std::array<std::vector<g_primitive<FieldT>>, rounds> g_arrays;
std::vector<xor_constant_gadget<FieldT>> xor_vector;

// TODO: Remove ZERO and pass it in the constructor
libsnark::pb_variable<FieldT> ZERO;

public:
std::array<std::array<FieldT, 32>, 8> IV;
std::array<std::array<FieldT, BLAKE2s_word_size>, 8> IV;
std::array<std::array<uint, 16>, 10> sigma;

BLAKE2s_256_comp(
Expand All @@ -59,12 +97,12 @@ class BLAKE2s_256_comp : public libsnark::gadget<FieldT>

static size_t expected_constraints(const bool ensure_output_bitness);

// Helper functions
// Helper functions to initialize the compression function parameters
void setup_constants();
void setup_h();
void setup_counter(size_t len_input_block);
void setup_v();
void setup_gadgets();
void setup_mixing_gadgets();
};

} // namespace libzeth
Expand Down
40 changes: 23 additions & 17 deletions src/circuits/blake2s/blake2s_comp.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,46 @@ BLAKE2s_256_comp<FieldT>::BLAKE2s_256_comp(
, output(output)
{
// Allocate and format the 16 input block variable
for (size_t i = 0; i < 16; i++) {
for (size_t i = 0; i < BLAKE2s_word_number; i++) {
block[i].allocate(
pb, 32, FMT(this->annotation_prefix, " block_%zu", i));
pb,
BLAKE2s_word_size,
FMT(this->annotation_prefix, " block_%zu", i));
}

// Setup constants, parameters and first state
// Setup constants, hash parameters and initialize the state
ZERO.allocate(pb, FMT(this->annotation_prefix, " ZERO"));
BLAKE2s_256_comp<FieldT>::setup_constants();
BLAKE2s_256_comp<FieldT>::setup_h();

// Allocate the states
// Allocate the state variables
for (size_t i = 0; i < rounds + 1; i++) {
for (size_t j = 0; j < 16; j++) {
for (size_t j = 0; j < BLAKE2s_word_number; j++) {
v[i][j].allocate(
this->pb,
32,
BLAKE2s_word_size,
FMT(this->annotation_prefix, " v_%zu", i * rounds + j));
}
}
for (size_t i = 0; i < rounds; i++) {
for (size_t j = 0; j < 16; j++) {
for (size_t j = 0; j < BLAKE2s_word_number; j++) {
v_temp[i][j].allocate(
this->pb,
32,
BLAKE2s_word_size,
FMT(this->annotation_prefix, " v_temp_%zu", i * rounds + j));
}
}

// Allocate output bytes (before swapping endianness and appending)
for (size_t i = 0; i < 8; i++) {
output_bytes[i].allocate(
pb, 32, FMT(this->annotation_prefix, " output_byte_%zu", i));
pb,
BLAKE2s_word_size,
FMT(this->annotation_prefix, " output_byte_%zu", i));
}

setup_gadgets();
// Set up the g_primitive gadgets used in the compression function
setup_mixing_gadgets();
};

template<typename FieldT>
Expand All @@ -74,31 +79,32 @@ void BLAKE2s_256_comp<FieldT>::generate_r1cs_constraints(

template<typename FieldT> void BLAKE2s_256_comp<FieldT>::generate_r1cs_witness()
{
// Format two 256 bit long big endian inputs into one 512 long little endian
// Format two 256-bit long big endian inputs into one 512 long little endian
// input (with padding if necessary)
size_t input_size = input_block.bits.size();
// We do not use block_size because the value might not be entered
//(c.f. block_variable<FieldT>::block_variable(protoboard<FieldT> &pb,
// (c.f. block_variable<FieldT>::block_variable(protoboard<FieldT> &pb,
// const
// std::vector<pb_variable_array<FieldT> >
// std::vector<pb_variable_array<FieldT>>
// &parts, const std::string
// &annotation_prefix) )
// &annotation_prefix))

// Push the block variable in local to be swapped
std::vector<FieldT> padded_input;
for (size_t i = 0; i < input_size; i++) {
padded_input.push_back(this->pb.val(input_block.bits[i]));
}

// [SANITY CHECK] Pad if necessary
// [SANITY CHECK] Pad if necessary (if input_size < BLAKE2s_block_size)
for (size_t i = 0; i < BLAKE2s_block_size - input_size; i++) {
padded_input.push_back(FieldT("0"));
}

// Allocate and format the 16 input block variable
for (size_t i = 0; i < 16; i++) {
for (size_t i = 0; i < BLAKE2s_word_number; i++) {
std::vector<FieldT> temp_vector(
padded_input.begin() + 32 * i, padded_input.begin() + 32 * (i + 1));
padded_input.begin() + BLAKE2s_word_size * i,
padded_input.begin() + BLAKE2s_word_size * (i + 1));
std::vector<FieldT> swapped_vector = swap_byte_endianness(temp_vector);
block[i].fill_with_field_elements(this->pb, swapped_vector);
}
Expand Down
Loading