Original HUSH source code based on ZEC 1.0.8 . For historical purposes only! https://hush.is
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

297 lines
11 KiB

/** @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_