Fix libsnark dependency build.

This changes libsnark to build in-place, instead of copying first to
a build directory. Previously, modifications made to the original
sources wouldn't get rebuilt without a 'make clean' because users
would be pointing to the copies.

This closes #2689.
This commit is contained in:
syd
2017-11-24 13:54:17 -05:00
parent 7888624f74
commit a55c186a74
119 changed files with 114 additions and 119 deletions

View File

@@ -0,0 +1,42 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef DIGEST_SELECTOR_GADGET_HPP_
#define DIGEST_SELECTOR_GADGET_HPP_
#include <vector>
#include "gadgetlib1/gadgets/basic_gadgets.hpp"
#include "gadgetlib1/gadgets/hashes/hash_io.hpp"
namespace libsnark {
template<typename FieldT>
class digest_selector_gadget : public gadget<FieldT> {
public:
size_t digest_size;
digest_variable<FieldT> input;
pb_linear_combination<FieldT> is_right;
digest_variable<FieldT> left;
digest_variable<FieldT> right;
digest_selector_gadget(protoboard<FieldT> &pb,
const size_t digest_size,
const digest_variable<FieldT> &input,
const pb_linear_combination<FieldT> &is_right,
const digest_variable<FieldT> &left,
const digest_variable<FieldT> &right,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
} // libsnark
#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc"
#endif // DIGEST_SELECTOR_GADGET_HPP_

View File

@@ -0,0 +1,62 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef DIGEST_SELECTOR_GADGET_TCC_
#define DIGEST_SELECTOR_GADGET_TCC_
namespace libsnark {
template<typename FieldT>
digest_selector_gadget<FieldT>::digest_selector_gadget(protoboard<FieldT> &pb,
const size_t digest_size,
const digest_variable<FieldT> &input,
const pb_linear_combination<FieldT> &is_right,
const digest_variable<FieldT> &left,
const digest_variable<FieldT> &right,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix), digest_size(digest_size), input(input), is_right(is_right), left(left), right(right)
{
}
template<typename FieldT>
void digest_selector_gadget<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < digest_size; ++i)
{
/*
input = is_right * right + (1-is_right) * left
input - left = is_right(right - left)
*/
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(is_right, right.bits[i] - left.bits[i], input.bits[i] - left.bits[i]),
FMT(this->annotation_prefix, " propagate_%zu", i));
}
}
template<typename FieldT>
void digest_selector_gadget<FieldT>::generate_r1cs_witness()
{
is_right.evaluate(this->pb);
assert(this->pb.lc_val(is_right) == FieldT::one() || this->pb.lc_val(is_right) == FieldT::zero());
if (this->pb.lc_val(is_right) == FieldT::one())
{
for (size_t i = 0; i < digest_size; ++i)
{
this->pb.val(right.bits[i]) = this->pb.val(input.bits[i]);
}
}
else
{
for (size_t i = 0; i < digest_size; ++i)
{
this->pb.val(left.bits[i]) = this->pb.val(input.bits[i]);
}
}
}
} // libsnark
#endif // DIGEST_SELECTOR_GADGET_TCC_

View File

@@ -0,0 +1,63 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef HASH_IO_HPP_
#define HASH_IO_HPP_
#include <cstddef>
#include <vector>
#include "gadgetlib1/gadgets/basic_gadgets.hpp"
namespace libsnark {
template<typename FieldT>
class digest_variable : public gadget<FieldT> {
public:
size_t digest_size;
pb_variable_array<FieldT> bits;
digest_variable<FieldT>(protoboard<FieldT> &pb,
const size_t digest_size,
const std::string &annotation_prefix);
digest_variable<FieldT>(protoboard<FieldT> &pb,
const size_t digest_size,
const pb_variable_array<FieldT> &partial_bits,
const pb_variable<FieldT> &padding,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness(const bit_vector& contents);
bit_vector get_digest() const;
};
template<typename FieldT>
class block_variable : public gadget<FieldT> {
public:
size_t block_size;
pb_variable_array<FieldT> bits;
block_variable(protoboard<FieldT> &pb,
const size_t block_size,
const std::string &annotation_prefix);
block_variable(protoboard<FieldT> &pb,
const std::vector<pb_variable_array<FieldT> > &parts,
const std::string &annotation_prefix);
block_variable(protoboard<FieldT> &pb,
const digest_variable<FieldT> &left,
const digest_variable<FieldT> &right,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness(const bit_vector& contents);
bit_vector get_block() const;
};
} // libsnark
#include "gadgetlib1/gadgets/hashes/hash_io.tcc"
#endif // HASH_IO_HPP_

View File

@@ -0,0 +1,105 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef HASH_IO_TCC_
#define HASH_IO_TCC_
namespace libsnark {
template<typename FieldT>
digest_variable<FieldT>::digest_variable(protoboard<FieldT> &pb,
const size_t digest_size,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix), digest_size(digest_size)
{
bits.allocate(pb, digest_size, FMT(this->annotation_prefix, " bits"));
}
template<typename FieldT>
digest_variable<FieldT>::digest_variable(protoboard<FieldT> &pb,
const size_t digest_size,
const pb_variable_array<FieldT> &partial_bits,
const pb_variable<FieldT> &padding,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix), digest_size(digest_size)
{
assert(bits.size() <= digest_size);
bits = partial_bits;
while (bits.size() != digest_size)
{
bits.emplace_back(padding);
}
}
template<typename FieldT>
void digest_variable<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < digest_size; ++i)
{
generate_boolean_r1cs_constraint<FieldT>(this->pb, bits[i], FMT(this->annotation_prefix, " bits_%zu", i));
}
}
template<typename FieldT>
void digest_variable<FieldT>::generate_r1cs_witness(const bit_vector& contents)
{
bits.fill_with_bits(this->pb, contents);
}
template<typename FieldT>
bit_vector digest_variable<FieldT>::get_digest() const
{
return bits.get_bits(this->pb);
}
template<typename FieldT>
block_variable<FieldT>::block_variable(protoboard<FieldT> &pb,
const size_t block_size,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix), block_size(block_size)
{
bits.allocate(pb, block_size, FMT(this->annotation_prefix, " bits"));
}
template<typename FieldT>
block_variable<FieldT>::block_variable(protoboard<FieldT> &pb,
const std::vector<pb_variable_array<FieldT> > &parts,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix)
{
for (auto &part : parts)
{
bits.insert(bits.end(), part.begin(), part.end());
}
}
template<typename FieldT>
block_variable<FieldT>::block_variable(protoboard<FieldT> &pb,
const digest_variable<FieldT> &left,
const digest_variable<FieldT> &right,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix)
{
assert(left.bits.size() == right.bits.size());
block_size = 2 * left.bits.size();
bits.insert(bits.end(), left.bits.begin(), left.bits.end());
bits.insert(bits.end(), right.bits.begin(), right.bits.end());
}
template<typename FieldT>
void block_variable<FieldT>::generate_r1cs_witness(const bit_vector& contents)
{
bits.fill_with_bits(this->pb, contents);
}
template<typename FieldT>
bit_vector block_variable<FieldT>::get_block() const
{
return bits.get_bits(this->pb);
}
} // libsnark
#endif // HASH_IO_TCC_

View File

@@ -0,0 +1,160 @@
/** @file
*****************************************************************************
Declaration of interfaces for auxiliary gadgets for the SHA256 gadget.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SHA256_AUX_HPP_
#define SHA256_AUX_HPP_
#include "gadgetlib1/gadgets/basic_gadgets.hpp"
namespace libsnark {
template<typename FieldT>
class lastbits_gadget : public gadget<FieldT> {
public:
pb_variable<FieldT> X;
size_t X_bits;
pb_variable<FieldT> result;
pb_linear_combination_array<FieldT> result_bits;
pb_linear_combination_array<FieldT> full_bits;
std::shared_ptr<packing_gadget<FieldT> > unpack_bits;
std::shared_ptr<packing_gadget<FieldT> > pack_result;
lastbits_gadget(protoboard<FieldT> &pb,
const pb_variable<FieldT> &X,
const size_t X_bits,
const pb_variable<FieldT> &result,
const pb_linear_combination_array<FieldT> &result_bits,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
template<typename FieldT>
class XOR3_gadget : public gadget<FieldT> {
private:
pb_variable<FieldT> tmp;
public:
pb_linear_combination<FieldT> A;
pb_linear_combination<FieldT> B;
pb_linear_combination<FieldT> C;
bool assume_C_is_zero;
pb_linear_combination<FieldT> out;
XOR3_gadget(protoboard<FieldT> &pb,
const pb_linear_combination<FieldT> &A,
const pb_linear_combination<FieldT> &B,
const pb_linear_combination<FieldT> &C,
const bool assume_C_is_zero,
const pb_linear_combination<FieldT> &out,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
template<typename FieldT>
class small_sigma_gadget : public gadget<FieldT> {
private:
pb_variable_array<FieldT> W;
pb_variable<FieldT> result;
public:
pb_variable_array<FieldT> result_bits;
std::vector<std::shared_ptr<XOR3_gadget<FieldT> > > compute_bits;
std::shared_ptr<packing_gadget<FieldT> > pack_result;
small_sigma_gadget(protoboard<FieldT> &pb,
const pb_variable_array<FieldT> &W,
const pb_variable<FieldT> &result,
const size_t rot1,
const size_t rot2,
const size_t shift,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
template<typename FieldT>
class big_sigma_gadget : public gadget<FieldT> {
private:
pb_linear_combination_array<FieldT> W;
pb_variable<FieldT> result;
public:
pb_variable_array<FieldT> result_bits;
std::vector<std::shared_ptr<XOR3_gadget<FieldT> > > compute_bits;
std::shared_ptr<packing_gadget<FieldT> > pack_result;
big_sigma_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &W,
const pb_variable<FieldT> &result,
const size_t rot1,
const size_t rot2,
const size_t rot3,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
template<typename FieldT>
class choice_gadget : public gadget<FieldT> {
private:
pb_variable_array<FieldT> result_bits;
public:
pb_linear_combination_array<FieldT> X;
pb_linear_combination_array<FieldT> Y;
pb_linear_combination_array<FieldT> Z;
pb_variable<FieldT> result;
std::shared_ptr<packing_gadget<FieldT> > pack_result;
choice_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &X,
const pb_linear_combination_array<FieldT> &Y,
const pb_linear_combination_array<FieldT> &Z,
const pb_variable<FieldT> &result, const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
template<typename FieldT>
class majority_gadget : public gadget<FieldT> {
private:
pb_variable_array<FieldT> result_bits;
std::shared_ptr<packing_gadget<FieldT> > pack_result;
public:
pb_linear_combination_array<FieldT> X;
pb_linear_combination_array<FieldT> Y;
pb_linear_combination_array<FieldT> Z;
pb_variable<FieldT> result;
majority_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &X,
const pb_linear_combination_array<FieldT> &Y,
const pb_linear_combination_array<FieldT> &Z,
const pb_variable<FieldT> &result,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
} // libsnark
#include "gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc"
#endif // SHA256_AUX_HPP_

View File

@@ -0,0 +1,297 @@
/** @file
*****************************************************************************
Implementation of interfaces for auxiliary gadgets for the SHA256 gadget.
See sha256_aux.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SHA256_AUX_TCC_
#define SHA256_AUX_TCC_
namespace libsnark {
template<typename FieldT>
lastbits_gadget<FieldT>::lastbits_gadget(protoboard<FieldT> &pb,
const pb_variable<FieldT> &X,
const size_t X_bits,
const pb_variable<FieldT> &result,
const pb_linear_combination_array<FieldT> &result_bits,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
X(X),
X_bits(X_bits),
result(result),
result_bits(result_bits)
{
full_bits = result_bits;
for (size_t i = result_bits.size(); i < X_bits; ++i)
{
pb_variable<FieldT> full_bits_overflow;
full_bits_overflow.allocate(pb, FMT(this->annotation_prefix, " full_bits_%zu", i));
full_bits.emplace_back(full_bits_overflow);
}
unpack_bits.reset(new packing_gadget<FieldT>(pb, full_bits, X, FMT(this->annotation_prefix, " unpack_bits")));
pack_result.reset(new packing_gadget<FieldT>(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result")));
}
template<typename FieldT>
void lastbits_gadget<FieldT>::generate_r1cs_constraints()
{
unpack_bits->generate_r1cs_constraints(true);
pack_result->generate_r1cs_constraints(false);
}
template<typename FieldT>
void lastbits_gadget<FieldT>::generate_r1cs_witness()
{
unpack_bits->generate_r1cs_witness_from_packed();
pack_result->generate_r1cs_witness_from_bits();
}
template<typename FieldT>
XOR3_gadget<FieldT>::XOR3_gadget(protoboard<FieldT> &pb,
const pb_linear_combination<FieldT> &A,
const pb_linear_combination<FieldT> &B,
const pb_linear_combination<FieldT> &C,
const bool assume_C_is_zero,
const pb_linear_combination<FieldT> &out,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
A(A),
B(B),
C(C),
assume_C_is_zero(assume_C_is_zero),
out(out)
{
if (!assume_C_is_zero)
{
tmp.allocate(pb, FMT(this->annotation_prefix, " tmp"));
}
}
template<typename FieldT>
void XOR3_gadget<FieldT>::generate_r1cs_constraints()
{
/*
tmp = A + B - 2AB i.e. tmp = A xor B
out = tmp + C - 2tmp C i.e. out = tmp xor C
*/
if (assume_C_is_zero)
{
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(2*A, B, A + B - out), FMT(this->annotation_prefix, " implicit_tmp_equals_out"));
}
else
{
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(2*A, B, A + B - tmp), FMT(this->annotation_prefix, " tmp"));
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(2 * tmp, C, tmp + C - out), FMT(this->annotation_prefix, " out"));
}
}
template<typename FieldT>
void XOR3_gadget<FieldT>::generate_r1cs_witness()
{
if (assume_C_is_zero)
{
this->pb.lc_val(out) = this->pb.lc_val(A) + this->pb.lc_val(B) - FieldT(2) * this->pb.lc_val(A) * this->pb.lc_val(B);
}
else
{
this->pb.val(tmp) = this->pb.lc_val(A) + this->pb.lc_val(B) - FieldT(2) * this->pb.lc_val(A) * this->pb.lc_val(B);
this->pb.lc_val(out) = this->pb.val(tmp) + this->pb.lc_val(C) - FieldT(2) * this->pb.val(tmp) * this->pb.lc_val(C);
}
}
#define SHA256_GADGET_ROTR(A, i, k) A[((i)+(k)) % 32]
/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
template<typename FieldT>
small_sigma_gadget<FieldT>::small_sigma_gadget(protoboard<FieldT> &pb,
const pb_variable_array<FieldT> &W,
const pb_variable<FieldT> &result,
const size_t rot1,
const size_t rot2,
const size_t shift,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
W(W),
result(result)
{
result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits"));
compute_bits.resize(32);
for (size_t i = 0; i < 32; ++i)
{
compute_bits[i].reset(new XOR3_gadget<FieldT>(pb, SHA256_GADGET_ROTR(W, i, rot1), SHA256_GADGET_ROTR(W, i, rot2),
(i + shift < 32 ? W[i+shift] : ONE),
(i + shift >= 32), result_bits[i],
FMT(this->annotation_prefix, " compute_bits_%zu", i)));
}
pack_result.reset(new packing_gadget<FieldT>(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result")));
}
template<typename FieldT>
void small_sigma_gadget<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < 32; ++i)
{
compute_bits[i]->generate_r1cs_constraints();
}
pack_result->generate_r1cs_constraints(false);
}
template<typename FieldT>
void small_sigma_gadget<FieldT>::generate_r1cs_witness()
{
for (size_t i = 0; i < 32; ++i)
{
compute_bits[i]->generate_r1cs_witness();
}
pack_result->generate_r1cs_witness_from_bits();
}
template<typename FieldT>
big_sigma_gadget<FieldT>::big_sigma_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &W,
const pb_variable<FieldT> &result,
const size_t rot1,
const size_t rot2,
const size_t rot3,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
W(W),
result(result)
{
result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits"));
compute_bits.resize(32);
for (size_t i = 0; i < 32; ++i)
{
compute_bits[i].reset(new XOR3_gadget<FieldT>(pb, SHA256_GADGET_ROTR(W, i, rot1), SHA256_GADGET_ROTR(W, i, rot2), SHA256_GADGET_ROTR(W, i, rot3), false, result_bits[i],
FMT(this->annotation_prefix, " compute_bits_%zu", i)));
}
pack_result.reset(new packing_gadget<FieldT>(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result")));
}
template<typename FieldT>
void big_sigma_gadget<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < 32; ++i)
{
compute_bits[i]->generate_r1cs_constraints();
}
pack_result->generate_r1cs_constraints(false);
}
template<typename FieldT>
void big_sigma_gadget<FieldT>::generate_r1cs_witness()
{
for (size_t i = 0; i < 32; ++i)
{
compute_bits[i]->generate_r1cs_witness();
}
pack_result->generate_r1cs_witness_from_bits();
}
/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
template<typename FieldT>
choice_gadget<FieldT>::choice_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &X,
const pb_linear_combination_array<FieldT> &Y,
const pb_linear_combination_array<FieldT> &Z,
const pb_variable<FieldT> &result, const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
X(X),
Y(Y),
Z(Z),
result(result)
{
result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits"));
pack_result.reset(new packing_gadget<FieldT>(pb, result_bits, result, FMT(this->annotation_prefix, " result")));
}
template<typename FieldT>
void choice_gadget<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < 32; ++i)
{
/*
result = x * y + (1-x) * z
result - z = x * (y - z)
*/
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(X[i], Y[i] - Z[i], result_bits[i] - Z[i]), FMT(this->annotation_prefix, " result_bits_%zu", i));
}
pack_result->generate_r1cs_constraints(false);
}
template<typename FieldT>
void choice_gadget<FieldT>::generate_r1cs_witness()
{
for (size_t i = 0; i < 32; ++i)
{
this->pb.val(result_bits[i]) = this->pb.lc_val(X[i]) * this->pb.lc_val(Y[i]) + (FieldT::one() - this->pb.lc_val(X[i])) * this->pb.lc_val(Z[i]);
}
pack_result->generate_r1cs_witness_from_bits();
}
/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
template<typename FieldT>
majority_gadget<FieldT>::majority_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &X,
const pb_linear_combination_array<FieldT> &Y,
const pb_linear_combination_array<FieldT> &Z,
const pb_variable<FieldT> &result,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
X(X),
Y(Y),
Z(Z),
result(result)
{
result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits"));
pack_result.reset(new packing_gadget<FieldT>(pb, result_bits, result, FMT(this->annotation_prefix, " result")));
}
template<typename FieldT>
void majority_gadget<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < 32; ++i)
{
/*
2*result + aux = x + y + z
x, y, z, aux -- bits
aux = x + y + z - 2*result
*/
generate_boolean_r1cs_constraint<FieldT>(this->pb, result_bits[i], FMT(this->annotation_prefix, " result_%zu", i));
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(X[i] + Y[i] + Z[i] - 2 * result_bits[i],
1 - (X[i] + Y[i] + Z[i] - 2 * result_bits[i]),
0),
FMT(this->annotation_prefix, " result_bits_%zu", i));
}
pack_result->generate_r1cs_constraints(false);
}
template<typename FieldT>
void majority_gadget<FieldT>::generate_r1cs_witness()
{
for (size_t i = 0; i < 32; ++i)
{
const long v = (this->pb.lc_val(X[i]) + this->pb.lc_val(Y[i]) + this->pb.lc_val(Z[i])).as_ulong();
this->pb.val(result_bits[i]) = FieldT(v / 2);
}
pack_result->generate_r1cs_witness_from_bits();
}
} // libsnark
#endif // SHA256_AUX_TCC_

View File

@@ -0,0 +1,108 @@
/** @file
*****************************************************************************
Declaration of interfaces for gadgets for the SHA256 message schedule and round function.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SHA256_COMPONENTS_HPP_
#define SHA256_COMPONENTS_HPP_
#include "gadgetlib1/gadgets/basic_gadgets.hpp"
#include "gadgetlib1/gadgets/hashes/hash_io.hpp"
#include "gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp"
namespace libsnark {
const size_t SHA256_digest_size = 256;
const size_t SHA256_block_size = 512;
template<typename FieldT>
pb_linear_combination_array<FieldT> SHA256_default_IV(protoboard<FieldT> &pb);
template<typename FieldT>
class sha256_message_schedule_gadget : public gadget<FieldT> {
public:
std::vector<pb_variable_array<FieldT> > W_bits;
std::vector<std::shared_ptr<packing_gadget<FieldT> > > pack_W;
std::vector<pb_variable<FieldT> > sigma0;
std::vector<pb_variable<FieldT> > sigma1;
std::vector<std::shared_ptr<small_sigma_gadget<FieldT> > > compute_sigma0;
std::vector<std::shared_ptr<small_sigma_gadget<FieldT> > > compute_sigma1;
std::vector<pb_variable<FieldT> > unreduced_W;
std::vector<std::shared_ptr<lastbits_gadget<FieldT> > > mod_reduce_W;
public:
pb_variable_array<FieldT> M;
pb_variable_array<FieldT> packed_W;
sha256_message_schedule_gadget(protoboard<FieldT> &pb,
const pb_variable_array<FieldT> &M,
const pb_variable_array<FieldT> &packed_W,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
template<typename FieldT>
class sha256_round_function_gadget : public gadget<FieldT> {
public:
pb_variable<FieldT> sigma0;
pb_variable<FieldT> sigma1;
std::shared_ptr<big_sigma_gadget<FieldT> > compute_sigma0;
std::shared_ptr<big_sigma_gadget<FieldT> > compute_sigma1;
pb_variable<FieldT> choice;
pb_variable<FieldT> majority;
std::shared_ptr<choice_gadget<FieldT> > compute_choice;
std::shared_ptr<majority_gadget<FieldT> > compute_majority;
pb_variable<FieldT> packed_d;
std::shared_ptr<packing_gadget<FieldT> > pack_d;
pb_variable<FieldT> packed_h;
std::shared_ptr<packing_gadget<FieldT> > pack_h;
pb_variable<FieldT> unreduced_new_a;
pb_variable<FieldT> unreduced_new_e;
std::shared_ptr<lastbits_gadget<FieldT> > mod_reduce_new_a;
std::shared_ptr<lastbits_gadget<FieldT> > mod_reduce_new_e;
pb_variable<FieldT> packed_new_a;
pb_variable<FieldT> packed_new_e;
public:
pb_linear_combination_array<FieldT> a;
pb_linear_combination_array<FieldT> b;
pb_linear_combination_array<FieldT> c;
pb_linear_combination_array<FieldT> d;
pb_linear_combination_array<FieldT> e;
pb_linear_combination_array<FieldT> f;
pb_linear_combination_array<FieldT> g;
pb_linear_combination_array<FieldT> h;
pb_variable<FieldT> W;
long K;
pb_linear_combination_array<FieldT> new_a;
pb_linear_combination_array<FieldT> new_e;
sha256_round_function_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &a,
const pb_linear_combination_array<FieldT> &b,
const pb_linear_combination_array<FieldT> &c,
const pb_linear_combination_array<FieldT> &d,
const pb_linear_combination_array<FieldT> &e,
const pb_linear_combination_array<FieldT> &f,
const pb_linear_combination_array<FieldT> &g,
const pb_linear_combination_array<FieldT> &h,
const pb_variable<FieldT> &W,
const long &K,
const pb_linear_combination_array<FieldT> &new_a,
const pb_linear_combination_array<FieldT> &new_e,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
} // libsnark
#include "gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc"
#endif // SHA256_COMPONENTS_HPP_

View File

@@ -0,0 +1,250 @@
/** @file
*****************************************************************************
Implementation of interfaces for gadgets for the SHA256 message schedule and round function.
See sha256_components.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SHA256_COMPONENTS_TCC_
#define SHA256_COMPONENTS_TCC_
namespace libsnark {
const unsigned long SHA256_K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
const unsigned long SHA256_H[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
template<typename FieldT>
pb_linear_combination_array<FieldT> SHA256_default_IV(protoboard<FieldT> &pb)
{
pb_linear_combination_array<FieldT> result;
result.reserve(SHA256_digest_size);
for (size_t i = 0; i < SHA256_digest_size; ++i)
{
int iv_val = (SHA256_H[i / 32] >> (31-(i % 32))) & 1;
pb_linear_combination<FieldT> iv_element;
iv_element.assign(pb, iv_val * ONE);
iv_element.evaluate(pb);
result.emplace_back(iv_element);
}
return result;
}
template<typename FieldT>
sha256_message_schedule_gadget<FieldT>::sha256_message_schedule_gadget(protoboard<FieldT> &pb,
const pb_variable_array<FieldT> &M,
const pb_variable_array<FieldT> &packed_W,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
M(M),
packed_W(packed_W)
{
W_bits.resize(64);
pack_W.resize(16);
for (size_t i = 0; i < 16; ++i)
{
W_bits[i] = pb_variable_array<FieldT>(M.rbegin() + (15-i) * 32, M.rbegin() + (16-i) * 32);
pack_W[i].reset(new packing_gadget<FieldT>(pb, W_bits[i], packed_W[i], FMT(this->annotation_prefix, " pack_W_%zu", i)));
}
/* NB: some of those will be un-allocated */
sigma0.resize(64);
sigma1.resize(64);
compute_sigma0.resize(64);
compute_sigma1.resize(64);
unreduced_W.resize(64);
mod_reduce_W.resize(64);
for (size_t i = 16; i < 64; ++i)
{
/* allocate result variables for sigma0/sigma1 invocations */
sigma0[i].allocate(pb, FMT(this->annotation_prefix, " sigma0_%zu", i));
sigma1[i].allocate(pb, FMT(this->annotation_prefix, " sigma1_%zu", i));
/* compute sigma0/sigma1 */
compute_sigma0[i].reset(new small_sigma_gadget<FieldT>(pb, W_bits[i-15], sigma0[i], 7, 18, 3, FMT(this->annotation_prefix, " compute_sigma0_%zu", i)));
compute_sigma1[i].reset(new small_sigma_gadget<FieldT>(pb, W_bits[i-2], sigma1[i], 17, 19, 10, FMT(this->annotation_prefix, " compute_sigma1_%zu", i)));
/* unreduced_W = sigma0(W_{i-15}) + sigma1(W_{i-2}) + W_{i-7} + W_{i-16} before modulo 2^32 */
unreduced_W[i].allocate(pb, FMT(this->annotation_prefix, "unreduced_W_%zu", i));
/* allocate the bit representation of packed_W[i] */
W_bits[i].allocate(pb, 32, FMT(this->annotation_prefix, " W_bits_%zu", i));
/* and finally reduce this into packed and bit representations */
mod_reduce_W[i].reset(new lastbits_gadget<FieldT>(pb, unreduced_W[i], 32+2, packed_W[i], W_bits[i], FMT(this->annotation_prefix, " mod_reduce_W_%zu", i)));
}
}
template<typename FieldT>
void sha256_message_schedule_gadget<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < 16; ++i)
{
pack_W[i]->generate_r1cs_constraints(false); // do not enforce bitness here; caller be aware.
}
for (size_t i = 16; i < 64; ++i)
{
compute_sigma0[i]->generate_r1cs_constraints();
compute_sigma1[i]->generate_r1cs_constraints();
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1,
sigma0[i] + sigma1[i] + packed_W[i-16] + packed_W[i-7],
unreduced_W[i]),
FMT(this->annotation_prefix, " unreduced_W_%zu", i));
mod_reduce_W[i]->generate_r1cs_constraints();
}
}
template<typename FieldT>
void sha256_message_schedule_gadget<FieldT>::generate_r1cs_witness()
{
for (size_t i = 0; i < 16; ++i)
{
pack_W[i]->generate_r1cs_witness_from_bits();
}
for (size_t i = 16; i < 64; ++i)
{
compute_sigma0[i]->generate_r1cs_witness();
compute_sigma1[i]->generate_r1cs_witness();
this->pb.val(unreduced_W[i]) = this->pb.val(sigma0[i]) + this->pb.val(sigma1[i]) + this->pb.val(packed_W[i-16]) + this->pb.val(packed_W[i-7]);
mod_reduce_W[i]->generate_r1cs_witness();
}
}
template<typename FieldT>
sha256_round_function_gadget<FieldT>::sha256_round_function_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &a,
const pb_linear_combination_array<FieldT> &b,
const pb_linear_combination_array<FieldT> &c,
const pb_linear_combination_array<FieldT> &d,
const pb_linear_combination_array<FieldT> &e,
const pb_linear_combination_array<FieldT> &f,
const pb_linear_combination_array<FieldT> &g,
const pb_linear_combination_array<FieldT> &h,
const pb_variable<FieldT> &W,
const long &K,
const pb_linear_combination_array<FieldT> &new_a,
const pb_linear_combination_array<FieldT> &new_e,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
a(a),
b(b),
c(c),
d(d),
e(e),
f(f),
g(g),
h(h),
W(W),
K(K),
new_a(new_a),
new_e(new_e)
{
/* compute sigma0 and sigma1 */
sigma0.allocate(pb, FMT(this->annotation_prefix, " sigma0"));
sigma1.allocate(pb, FMT(this->annotation_prefix, " sigma1"));
compute_sigma0.reset(new big_sigma_gadget<FieldT>(pb, a, sigma0, 2, 13, 22, FMT(this->annotation_prefix, " compute_sigma0")));
compute_sigma1.reset(new big_sigma_gadget<FieldT>(pb, e, sigma1, 6, 11, 25, FMT(this->annotation_prefix, " compute_sigma1")));
/* compute choice */
choice.allocate(pb, FMT(this->annotation_prefix, " choice"));
compute_choice.reset(new choice_gadget<FieldT>(pb, e, f, g, choice, FMT(this->annotation_prefix, " compute_choice")));
/* compute majority */
majority.allocate(pb, FMT(this->annotation_prefix, " majority"));
compute_majority.reset(new majority_gadget<FieldT>(pb, a, b, c, majority, FMT(this->annotation_prefix, " compute_majority")));
/* pack d */
packed_d.allocate(pb, FMT(this->annotation_prefix, " packed_d"));
pack_d.reset(new packing_gadget<FieldT>(pb, d, packed_d, FMT(this->annotation_prefix, " pack_d")));
/* pack h */
packed_h.allocate(pb, FMT(this->annotation_prefix, " packed_h"));
pack_h.reset(new packing_gadget<FieldT>(pb, h, packed_h, FMT(this->annotation_prefix, " pack_h")));
/* compute the actual results for the round */
unreduced_new_a.allocate(pb, FMT(this->annotation_prefix, " unreduced_new_a"));
unreduced_new_e.allocate(pb, FMT(this->annotation_prefix, " unreduced_new_e"));
packed_new_a.allocate(pb, FMT(this->annotation_prefix, " packed_new_a"));
packed_new_e.allocate(pb, FMT(this->annotation_prefix, " packed_new_e"));
mod_reduce_new_a.reset(new lastbits_gadget<FieldT>(pb, unreduced_new_a, 32+3, packed_new_a, new_a, FMT(this->annotation_prefix, " mod_reduce_new_a")));
mod_reduce_new_e.reset(new lastbits_gadget<FieldT>(pb, unreduced_new_e, 32+3, packed_new_e, new_e, FMT(this->annotation_prefix, " mod_reduce_new_e")));
}
template<typename FieldT>
void sha256_round_function_gadget<FieldT>::generate_r1cs_constraints()
{
compute_sigma0->generate_r1cs_constraints();
compute_sigma1->generate_r1cs_constraints();
compute_choice->generate_r1cs_constraints();
compute_majority->generate_r1cs_constraints();
pack_d->generate_r1cs_constraints(false);
pack_h->generate_r1cs_constraints(false);
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1,
packed_h + sigma1 + choice + K + W + sigma0 + majority,
unreduced_new_a),
FMT(this->annotation_prefix, " unreduced_new_a"));
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1,
packed_d + packed_h + sigma1 + choice + K + W,
unreduced_new_e),
FMT(this->annotation_prefix, " unreduced_new_e"));
mod_reduce_new_a->generate_r1cs_constraints();
mod_reduce_new_e->generate_r1cs_constraints();
}
template<typename FieldT>
void sha256_round_function_gadget<FieldT>::generate_r1cs_witness()
{
compute_sigma0->generate_r1cs_witness();
compute_sigma1->generate_r1cs_witness();
compute_choice->generate_r1cs_witness();
compute_majority->generate_r1cs_witness();
pack_d->generate_r1cs_witness_from_bits();
pack_h->generate_r1cs_witness_from_bits();
this->pb.val(unreduced_new_a) = this->pb.val(packed_h) + this->pb.val(sigma1) + this->pb.val(choice) + FieldT(K) + this->pb.val(W) + this->pb.val(sigma0) + this->pb.val(majority);
this->pb.val(unreduced_new_e) = this->pb.val(packed_d) + this->pb.val(packed_h) + this->pb.val(sigma1) + this->pb.val(choice) + FieldT(K) + this->pb.val(W);
mod_reduce_new_a->generate_r1cs_witness();
mod_reduce_new_e->generate_r1cs_witness();
}
} // libsnark
#endif // SHA256_COMPONENTS_TCC_

View File

@@ -0,0 +1,98 @@
/** @file
*****************************************************************************
Declaration of interfaces for top-level SHA256 gadgets.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SHA256_GADGET_HPP_
#define SHA256_GADGET_HPP_
#include "common/data_structures/merkle_tree.hpp"
#include "gadgetlib1/gadgets/basic_gadgets.hpp"
#include "gadgetlib1/gadgets/hashes/hash_io.hpp"
#include "gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp"
namespace libsnark {
/**
* Gadget for the SHA256 compression function.
*/
template<typename FieldT>
class sha256_compression_function_gadget : public gadget<FieldT> {
public:
std::vector<pb_linear_combination_array<FieldT> > round_a;
std::vector<pb_linear_combination_array<FieldT> > round_b;
std::vector<pb_linear_combination_array<FieldT> > round_c;
std::vector<pb_linear_combination_array<FieldT> > round_d;
std::vector<pb_linear_combination_array<FieldT> > round_e;
std::vector<pb_linear_combination_array<FieldT> > round_f;
std::vector<pb_linear_combination_array<FieldT> > round_g;
std::vector<pb_linear_combination_array<FieldT> > round_h;
pb_variable_array<FieldT> packed_W;
std::shared_ptr<sha256_message_schedule_gadget<FieldT> > message_schedule;
std::vector<sha256_round_function_gadget<FieldT> > round_functions;
pb_variable_array<FieldT> unreduced_output;
pb_variable_array<FieldT> reduced_output;
std::vector<lastbits_gadget<FieldT> > reduce_output;
public:
pb_linear_combination_array<FieldT> prev_output;
pb_variable_array<FieldT> new_block;
digest_variable<FieldT> output;
sha256_compression_function_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &prev_output,
const pb_variable_array<FieldT> &new_block,
const digest_variable<FieldT> &output,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
/**
* Gadget for the SHA256 compression function, viewed as a 2-to-1 hash
* function, and using the same initialization vector as in SHA256
* specification. Thus, any collision for
* sha256_two_to_one_hash_gadget trivially extends to a collision for
* full SHA256 (by appending the same padding).
*/
template<typename FieldT>
class sha256_two_to_one_hash_gadget : public gadget<FieldT> {
public:
typedef bit_vector hash_value_type;
typedef merkle_authentication_path merkle_authentication_path_type;
std::shared_ptr<sha256_compression_function_gadget<FieldT> > f;
sha256_two_to_one_hash_gadget(protoboard<FieldT> &pb,
const digest_variable<FieldT> &left,
const digest_variable<FieldT> &right,
const digest_variable<FieldT> &output,
const std::string &annotation_prefix);
sha256_two_to_one_hash_gadget(protoboard<FieldT> &pb,
const size_t block_length,
const block_variable<FieldT> &input_block,
const digest_variable<FieldT> &output,
const std::string &annotation_prefix);
void generate_r1cs_constraints(const bool ensure_output_bitness=true); // TODO: ignored for now
void generate_r1cs_witness();
static size_t get_block_len();
static size_t get_digest_len();
static bit_vector get_hash(const bit_vector &input);
static size_t expected_constraints(const bool ensure_output_bitness=true); // TODO: ignored for now
};
} // libsnark
#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc"
#endif // SHA256_GADGET_HPP_

View File

@@ -0,0 +1,230 @@
/** @file
*****************************************************************************
Implementation of interfaces for top-level SHA256 gadgets.
See sha256_gadget.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SHA256_GADGET_TCC_
#define SHA256_GADGET_TCC_
namespace libsnark {
template<typename FieldT>
sha256_compression_function_gadget<FieldT>::sha256_compression_function_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &prev_output,
const pb_variable_array<FieldT> &new_block,
const digest_variable<FieldT> &output,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
prev_output(prev_output),
new_block(new_block),
output(output)
{
/* message schedule and inputs for it */
packed_W.allocate(pb, 64, FMT(this->annotation_prefix, " packed_W"));
message_schedule.reset(new sha256_message_schedule_gadget<FieldT>(pb, new_block, packed_W, FMT(this->annotation_prefix, " message_schedule")));
/* initalize */
round_a.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 7*32, prev_output.rbegin() + 8*32));
round_b.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 6*32, prev_output.rbegin() + 7*32));
round_c.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 5*32, prev_output.rbegin() + 6*32));
round_d.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 4*32, prev_output.rbegin() + 5*32));
round_e.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 3*32, prev_output.rbegin() + 4*32));
round_f.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 2*32, prev_output.rbegin() + 3*32));
round_g.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 1*32, prev_output.rbegin() + 2*32));
round_h.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 0*32, prev_output.rbegin() + 1*32));
/* do the rounds */
for (size_t i = 0; i < 64; ++i)
{
round_h.push_back(round_g[i]);
round_g.push_back(round_f[i]);
round_f.push_back(round_e[i]);
round_d.push_back(round_c[i]);
round_c.push_back(round_b[i]);
round_b.push_back(round_a[i]);
pb_variable_array<FieldT> new_round_a_variables;
new_round_a_variables.allocate(pb, 32, FMT(this->annotation_prefix, " new_round_a_variables_%zu", i+1));
round_a.emplace_back(new_round_a_variables);
pb_variable_array<FieldT> new_round_e_variables;
new_round_e_variables.allocate(pb, 32, FMT(this->annotation_prefix, " new_round_e_variables_%zu", i+1));
round_e.emplace_back(new_round_e_variables);
round_functions.push_back(sha256_round_function_gadget<FieldT>(pb,
round_a[i], round_b[i], round_c[i], round_d[i],
round_e[i], round_f[i], round_g[i], round_h[i],
packed_W[i], SHA256_K[i], round_a[i+1], round_e[i+1],
FMT(this->annotation_prefix, " round_functions_%zu", i)));
}
/* finalize */
unreduced_output.allocate(pb, 8, FMT(this->annotation_prefix, " unreduced_output"));
reduced_output.allocate(pb, 8, FMT(this->annotation_prefix, " reduced_output"));
for (size_t i = 0; i < 8; ++i)
{
reduce_output.push_back(lastbits_gadget<FieldT>(pb,
unreduced_output[i],
32+1,
reduced_output[i],
pb_variable_array<FieldT>(output.bits.rbegin() + (7-i) * 32, output.bits.rbegin() + (8-i) * 32),
FMT(this->annotation_prefix, " reduce_output_%zu", i)));
}
}
template<typename FieldT>
void sha256_compression_function_gadget<FieldT>::generate_r1cs_constraints()
{
message_schedule->generate_r1cs_constraints();
for (size_t i = 0; i < 64; ++i)
{
round_functions[i].generate_r1cs_constraints();
}
for (size_t i = 0; i < 4; ++i)
{
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1,
round_functions[3-i].packed_d + round_functions[63-i].packed_new_a,
unreduced_output[i]),
FMT(this->annotation_prefix, " unreduced_output_%zu", i));
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1,
round_functions[3-i].packed_h + round_functions[63-i].packed_new_e,
unreduced_output[4+i]),
FMT(this->annotation_prefix, " unreduced_output_%zu", 4+i));
}
for (size_t i = 0; i < 8; ++i)
{
reduce_output[i].generate_r1cs_constraints();
}
}
template<typename FieldT>
void sha256_compression_function_gadget<FieldT>::generate_r1cs_witness()
{
message_schedule->generate_r1cs_witness();
#ifdef DEBUG
printf("Input:\n");
for (size_t j = 0; j < 16; ++j)
{
printf("%lx ", this->pb.val(packed_W[j]).as_ulong());
}
printf("\n");
#endif
for (size_t i = 0; i < 64; ++i)
{
round_functions[i].generate_r1cs_witness();
}
for (size_t i = 0; i < 4; ++i)
{
this->pb.val(unreduced_output[i]) = this->pb.val(round_functions[3-i].packed_d) + this->pb.val(round_functions[63-i].packed_new_a);
this->pb.val(unreduced_output[4+i]) = this->pb.val(round_functions[3-i].packed_h) + this->pb.val(round_functions[63-i].packed_new_e);
}
for (size_t i = 0; i < 8; ++i)
{
reduce_output[i].generate_r1cs_witness();
}
#ifdef DEBUG
printf("Output:\n");
for (size_t j = 0; j < 8; ++j)
{
printf("%lx ", this->pb.val(reduced_output[j]).as_ulong());
}
printf("\n");
#endif
}
template<typename FieldT>
sha256_two_to_one_hash_gadget<FieldT>::sha256_two_to_one_hash_gadget(protoboard<FieldT> &pb,
const digest_variable<FieldT> &left,
const digest_variable<FieldT> &right,
const digest_variable<FieldT> &output,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix)
{
/* concatenate block = left || right */
pb_variable_array<FieldT> block;
block.insert(block.end(), left.bits.begin(), left.bits.end());
block.insert(block.end(), right.bits.begin(), right.bits.end());
/* compute the hash itself */
f.reset(new sha256_compression_function_gadget<FieldT>(pb, SHA256_default_IV<FieldT>(pb), block, output, FMT(this->annotation_prefix, " f")));
}
template<typename FieldT>
sha256_two_to_one_hash_gadget<FieldT>::sha256_two_to_one_hash_gadget(protoboard<FieldT> &pb,
const size_t block_length,
const block_variable<FieldT> &input_block,
const digest_variable<FieldT> &output,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix)
{
assert(block_length == SHA256_block_size);
assert(input_block.bits.size() == block_length);
f.reset(new sha256_compression_function_gadget<FieldT>(pb, SHA256_default_IV<FieldT>(pb), input_block.bits, output, FMT(this->annotation_prefix, " f")));
}
template<typename FieldT>
void sha256_two_to_one_hash_gadget<FieldT>::generate_r1cs_constraints(const bool ensure_output_bitness)
{
UNUSED(ensure_output_bitness);
f->generate_r1cs_constraints();
}
template<typename FieldT>
void sha256_two_to_one_hash_gadget<FieldT>::generate_r1cs_witness()
{
f->generate_r1cs_witness();
}
template<typename FieldT>
size_t sha256_two_to_one_hash_gadget<FieldT>::get_block_len()
{
return SHA256_block_size;
}
template<typename FieldT>
size_t sha256_two_to_one_hash_gadget<FieldT>::get_digest_len()
{
return SHA256_digest_size;
}
template<typename FieldT>
bit_vector sha256_two_to_one_hash_gadget<FieldT>::get_hash(const bit_vector &input)
{
protoboard<FieldT> pb;
block_variable<FieldT> input_variable(pb, SHA256_block_size, "input");
digest_variable<FieldT> output_variable(pb, SHA256_digest_size, "output");
sha256_two_to_one_hash_gadget<FieldT> f(pb, SHA256_block_size, input_variable, output_variable, "f");
input_variable.generate_r1cs_witness(input);
f.generate_r1cs_witness();
return output_variable.get_digest();
}
template<typename FieldT>
size_t sha256_two_to_one_hash_gadget<FieldT>::expected_constraints(const bool ensure_output_bitness)
{
UNUSED(ensure_output_bitness);
return 27280; /* hardcoded for now */
}
} // libsnark
#endif // SHA256_GADGET_TCC_

View File

@@ -0,0 +1,55 @@
#!/usr/bin/env python
##
# @author This file is part of libsnark, developed by SCIPR Lab
# and contributors (see AUTHORS).
# @copyright MIT license (see LICENSE file)
import random
import pypy_sha256 # PyPy's implementation of SHA256 compression function; see copyright and authorship notice within.
BLOCK_LEN = 512
BLOCK_BYTES = BLOCK_LEN // 8
HASH_LEN = 256
HASH_BYTES = HASH_LEN // 8
def gen_random_bytes(n):
return [random.randint(0, 255) for i in xrange(n)]
def words_to_bytes(arr):
return sum(([x >> 24, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff] for x in arr), [])
def bytes_to_words(arr):
l = len(arr)
assert l % 4 == 0
return [(arr[i*4 + 3] << 24) + (arr[i*4+2] << 16) + (arr[i*4+1] << 8) + arr[i*4] for i in xrange(l//4)]
def cpp_val(s, log_radix=32):
if log_radix == 8:
hexfmt = '0x%02x'
elif log_radix == 32:
hexfmt = '0x%08x'
s = bytes_to_words(s)
else:
raise
return 'int_list_to_bits({%s}, %d)' % (', '.join(hexfmt % x for x in s), log_radix)
def H_bytes(x):
assert len(x) == BLOCK_BYTES
state = pypy_sha256.sha_init()
state['data'] = words_to_bytes(bytes_to_words(x))
pypy_sha256.sha_transform(state)
return words_to_bytes(bytes_to_words(words_to_bytes(state['digest'])))
def generate_sha256_gadget_tests():
left = gen_random_bytes(HASH_BYTES)
right = gen_random_bytes(HASH_BYTES)
hash = H_bytes(left + right)
print "const bit_vector left_bv = %s;" % cpp_val(left)
print "const bit_vector right_bv = %s;" % cpp_val(right)
print "const bit_vector hash_bv = %s;" % cpp_val(hash)
if __name__ == '__main__':
random.seed(0) # for reproducibility
generate_sha256_gadget_tests()

View File

@@ -0,0 +1,263 @@
#!/usr/bin/env python
#
# SHA256 compression function implementation below is a verbatim copy of PyPy's implementation from
# https://bitbucket.org/pypy/pypy/raw/f1f064b3faf1e012f7a9a9ab08f18074637ebe8a/lib_pypy/_sha256.py .
#
# It is licensed under the MIT license and copyright PyPy Copyright holders 2003-2015
# See https://bitbucket.org/pypy/pypy/src/tip/LICENSE for the full copyright notice.
#
SHA_BLOCKSIZE = 64
SHA_DIGESTSIZE = 32
def new_shaobject():
return {
'digest': [0]*8,
'count_lo': 0,
'count_hi': 0,
'data': [0]* SHA_BLOCKSIZE,
'local': 0,
'digestsize': 0
}
ROR = lambda x, y: (((x & 0xffffffff) >> (y & 31)) | (x << (32 - (y & 31)))) & 0xffffffff
Ch = lambda x, y, z: (z ^ (x & (y ^ z)))
Maj = lambda x, y, z: (((x | y) & z) | (x & y))
S = lambda x, n: ROR(x, n)
R = lambda x, n: (x & 0xffffffff) >> n
Sigma0 = lambda x: (S(x, 2) ^ S(x, 13) ^ S(x, 22))
Sigma1 = lambda x: (S(x, 6) ^ S(x, 11) ^ S(x, 25))
Gamma0 = lambda x: (S(x, 7) ^ S(x, 18) ^ R(x, 3))
Gamma1 = lambda x: (S(x, 17) ^ S(x, 19) ^ R(x, 10))
def sha_transform(sha_info):
W = []
d = sha_info['data']
for i in range(0,16):
W.append( (d[4*i]<<24) + (d[4*i+1]<<16) + (d[4*i+2]<<8) + d[4*i+3])
for i in range(16,64):
W.append( (Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]) & 0xffffffff )
ss = sha_info['digest'][:]
def RND(a,b,c,d,e,f,g,h,i,ki):
t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i];
t1 = Sigma0(a) + Maj(a, b, c);
d += t0;
h = t0 + t1;
return d & 0xffffffff, h & 0xffffffff
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],0,0x428a2f98);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],1,0x71374491);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],2,0xb5c0fbcf);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],3,0xe9b5dba5);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],4,0x3956c25b);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],5,0x59f111f1);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],6,0x923f82a4);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],7,0xab1c5ed5);
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],8,0xd807aa98);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],9,0x12835b01);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],10,0x243185be);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],11,0x550c7dc3);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],12,0x72be5d74);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],13,0x80deb1fe);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],14,0x9bdc06a7);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],15,0xc19bf174);
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],16,0xe49b69c1);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],17,0xefbe4786);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],18,0x0fc19dc6);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],19,0x240ca1cc);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],20,0x2de92c6f);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],21,0x4a7484aa);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],22,0x5cb0a9dc);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],23,0x76f988da);
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],24,0x983e5152);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],25,0xa831c66d);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],26,0xb00327c8);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],27,0xbf597fc7);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],28,0xc6e00bf3);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],29,0xd5a79147);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],30,0x06ca6351);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],31,0x14292967);
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],32,0x27b70a85);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],33,0x2e1b2138);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],34,0x4d2c6dfc);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],35,0x53380d13);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],36,0x650a7354);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],37,0x766a0abb);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],38,0x81c2c92e);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],39,0x92722c85);
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],40,0xa2bfe8a1);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],41,0xa81a664b);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],42,0xc24b8b70);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],43,0xc76c51a3);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],44,0xd192e819);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],45,0xd6990624);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],46,0xf40e3585);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],47,0x106aa070);
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],48,0x19a4c116);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],49,0x1e376c08);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],50,0x2748774c);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],51,0x34b0bcb5);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],52,0x391c0cb3);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],53,0x4ed8aa4a);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],54,0x5b9cca4f);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],55,0x682e6ff3);
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],56,0x748f82ee);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],57,0x78a5636f);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],58,0x84c87814);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],59,0x8cc70208);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],60,0x90befffa);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],61,0xa4506ceb);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],62,0xbef9a3f7);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],63,0xc67178f2);
dig = []
for i, x in enumerate(sha_info['digest']):
dig.append( (x + ss[i]) & 0xffffffff )
sha_info['digest'] = dig
def sha_init():
sha_info = new_shaobject()
sha_info['digest'] = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19]
sha_info['count_lo'] = 0
sha_info['count_hi'] = 0
sha_info['local'] = 0
sha_info['digestsize'] = 32
return sha_info
def sha224_init():
sha_info = new_shaobject()
sha_info['digest'] = [0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4]
sha_info['count_lo'] = 0
sha_info['count_hi'] = 0
sha_info['local'] = 0
sha_info['digestsize'] = 28
return sha_info
def sha_update(sha_info, buffer):
if isinstance(buffer, str):
raise TypeError("Unicode strings must be encoded before hashing")
count = len(buffer)
buffer_idx = 0
clo = (sha_info['count_lo'] + (count << 3)) & 0xffffffff
if clo < sha_info['count_lo']:
sha_info['count_hi'] += 1
sha_info['count_lo'] = clo
sha_info['count_hi'] += (count >> 29)
if sha_info['local']:
i = SHA_BLOCKSIZE - sha_info['local']
if i > count:
i = count
# copy buffer
sha_info['data'][sha_info['local']:sha_info['local']+i] = buffer[buffer_idx:buffer_idx+i]
count -= i
buffer_idx += i
sha_info['local'] += i
if sha_info['local'] == SHA_BLOCKSIZE:
sha_transform(sha_info)
sha_info['local'] = 0
else:
return
while count >= SHA_BLOCKSIZE:
# copy buffer
sha_info['data'] = list(buffer[buffer_idx:buffer_idx + SHA_BLOCKSIZE])
count -= SHA_BLOCKSIZE
buffer_idx += SHA_BLOCKSIZE
sha_transform(sha_info)
# copy buffer
pos = sha_info['local']
sha_info['data'][pos:pos+count] = buffer[buffer_idx:buffer_idx + count]
sha_info['local'] = count
def sha_final(sha_info):
lo_bit_count = sha_info['count_lo']
hi_bit_count = sha_info['count_hi']
count = (lo_bit_count >> 3) & 0x3f
sha_info['data'][count] = 0x80;
count += 1
if count > SHA_BLOCKSIZE - 8:
# zero the bytes in data after the count
sha_info['data'] = sha_info['data'][:count] + ([0] * (SHA_BLOCKSIZE - count))
sha_transform(sha_info)
# zero bytes in data
sha_info['data'] = [0] * SHA_BLOCKSIZE
else:
sha_info['data'] = sha_info['data'][:count] + ([0] * (SHA_BLOCKSIZE - count))
sha_info['data'][56] = (hi_bit_count >> 24) & 0xff
sha_info['data'][57] = (hi_bit_count >> 16) & 0xff
sha_info['data'][58] = (hi_bit_count >> 8) & 0xff
sha_info['data'][59] = (hi_bit_count >> 0) & 0xff
sha_info['data'][60] = (lo_bit_count >> 24) & 0xff
sha_info['data'][61] = (lo_bit_count >> 16) & 0xff
sha_info['data'][62] = (lo_bit_count >> 8) & 0xff
sha_info['data'][63] = (lo_bit_count >> 0) & 0xff
sha_transform(sha_info)
dig = []
for i in sha_info['digest']:
dig.extend([ ((i>>24) & 0xff), ((i>>16) & 0xff), ((i>>8) & 0xff), (i & 0xff) ])
return ''.join([chr(i) for i in dig])
class sha256(object):
digest_size = digestsize = SHA_DIGESTSIZE
block_size = SHA_BLOCKSIZE
def __init__(self, s=None):
self._sha = sha_init()
if s:
sha_update(self._sha, s)
def update(self, s):
sha_update(self._sha, s)
def digest(self):
return sha_final(self._sha.copy())[:self._sha['digestsize']]
def hexdigest(self):
return ''.join(['%.2x' % ord(i) for i in self.digest()])
def copy(self):
new = sha256.__new__(sha256)
new._sha = self._sha.copy()
return new
class sha224(sha256):
digest_size = digestsize = 28
def __init__(self, s=None):
self._sha = sha224_init()
if s:
sha_update(self._sha, s)
def copy(self):
new = sha224.__new__(sha224)
new._sha = self._sha.copy()
return new
def test():
a_str = "just a test string"
assert 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' == sha256().hexdigest()
assert 'd7b553c6f09ac85d142415f857c5310f3bbbe7cdd787cce4b985acedd585266f' == sha256(a_str).hexdigest()
assert '8113ebf33c97daa9998762aacafe750c7cefc2b2f173c90c59663a57fe626f21' == sha256(a_str*7).hexdigest()
s = sha256(a_str)
s.update(a_str)
assert '03d9963e05a094593190b6fc794cb1a3e1ac7d7883f0b5855268afeccc70d461' == s.hexdigest()
if __name__ == "__main__":
test()

View File

@@ -0,0 +1,48 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include "common/default_types/ec_pp.hpp"
#include "common/utils.hpp"
#include "common/profiling.hpp"
#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp"
#include <gtest/gtest.h>
using namespace libsnark;
template<typename FieldT>
void test_two_to_one()
{
protoboard<FieldT> pb;
digest_variable<FieldT> left(pb, SHA256_digest_size, "left");
digest_variable<FieldT> right(pb, SHA256_digest_size, "right");
digest_variable<FieldT> output(pb, SHA256_digest_size, "output");
sha256_two_to_one_hash_gadget<FieldT> f(pb, left, right, output, "f");
f.generate_r1cs_constraints();
printf("Number of constraints for sha256_two_to_one_hash_gadget: %zu\n", pb.num_constraints());
const bit_vector left_bv = int_list_to_bits({0x426bc2d8, 0x4dc86782, 0x81e8957a, 0x409ec148, 0xe6cffbe8, 0xafe6ba4f, 0x9c6f1978, 0xdd7af7e9}, 32);
const bit_vector right_bv = int_list_to_bits({0x038cce42, 0xabd366b8, 0x3ede7e00, 0x9130de53, 0x72cdf73d, 0xee825114, 0x8cb48d1b, 0x9af68ad0}, 32);
const bit_vector hash_bv = int_list_to_bits({0xeffd0b7f, 0x1ccba116, 0x2ee816f7, 0x31c62b48, 0x59305141, 0x990e5c0a, 0xce40d33d, 0x0b1167d1}, 32);
left.generate_r1cs_witness(left_bv);
right.generate_r1cs_witness(right_bv);
f.generate_r1cs_witness();
output.generate_r1cs_witness(hash_bv);
EXPECT_TRUE(pb.is_satisfied());
}
TEST(gadgetlib1, sha256)
{
start_profiling();
default_ec_pp::init_public_params();
test_two_to_one<Fr<default_ec_pp> >();
}