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

Use latest libff optimizations #382

Merged
merged 5 commits into from
Jul 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 4 additions & 32 deletions libzeth/core/field_element_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,41 +9,13 @@

namespace libzeth
{

/// WARNING: The following function assumes that the platform is little-endian
/// and that NAILS are NOT used. See Section 8.2 (page 68):
/// https://gmplib.org/gmp-man-6.2.0.pdf
///
/// In other words, we assume that:
/// - GMP_NUMB_BITS = GMP_LIMB_BITS and thus,
/// - GMP_NAIL_BITS = 0
///
/// Under these assumptions, bigints are layed out in memory with low-order
/// bytes first, occupying `FieldT::num_limbs * GMP_LIMB_BITS / 8` bytes. For
/// readability, this function returns the big-endian hex representation
/// (high-order byte first). If `prefix` is true, add the "0x" prefix.
template<typename FieldT>
std::string bigint_to_hex(
const libff::bigint<FieldT::num_limbs> &limbs, bool prefix = false);

/// WARNING: The following function assumes that the platform is little-endian
/// and that NAILS are NOT used. See Section 8.2 (page 68):
/// https://gmplib.org/gmp-man-6.2.0.pdf
///
/// In other words, we assume that:
/// - GMP_NUMB_BITS = GMP_LIMB_BITS and thus,
/// - GMP_NAIL_BITS = 0
///
/// Hex is read as most-significant-character-first (the natural ordering for
/// numbers), as generated by `bigint_to_hex`.
template<typename FieldT>
libff::bigint<FieldT::num_limbs> bigint_from_hex(const std::string &hex);

/// Convert a base/ground field element to a hexadecimal string.
/// Convert a base field element (single component) to a hexadecimal
/// string (without any JSON decoration such as '"').
template<typename FieldT>
std::string base_field_element_to_hex(const FieldT &field_el);

/// Convert an hexadecimal string to a base/ground field element
/// Convert a plain hex string (without any JSON decoration such as '"') to a
/// base field element (single component).
template<typename FieldT>
FieldT base_field_element_from_hex(const std::string &field_str);

Expand Down
170 changes: 15 additions & 155 deletions libzeth/core/field_element_utils.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -8,182 +8,42 @@
#include "libzeth/core/field_element_utils.hpp"
#include "libzeth/core/utils.hpp"

#include <boost/assert.hpp>
#include <assert.h>
#include <iomanip>

/// This file uses types and preprocessor variables defined in the `gmp.h`
/// header:
/// - `mp_size_t`
/// - `GMP_LIMB_BITS`
/// - `GMP_NAIL_BITS`

namespace libzeth
{

namespace internal
{

template<typename FieldT> class field_element_json
{
public:
/// Convert a field element to JSON
static void write(const FieldT &field_el, std::ostream &out_s)
{
// Note that we write components of extension fields
// highest-order-first.
out_s << '[';
size_t i = FieldT::tower_extension_degree - 1;
do {
out_s << field_element_to_json(field_el.coeffs[i]);
if (i > 0) {
out_s << ',';
}
} while (i-- > 0);
out_s << ']';
}

/// Read a field element from JSON
static void read(FieldT &field_el, std::istream &in_s)
{
// Read opening '[' char, then each component (highest-order-first)
// separated by ',' char, then a closing ']' char.

char sep;
in_s >> sep;
if (sep != '[') {
throw std::runtime_error("expected opening bracket");
}

size_t i = FieldT::tower_extension_degree - 1;
do {
field_element_read_json(field_el.coeffs[i], in_s);
if (i > 0) {
in_s >> sep;
if (sep != ',') {
throw std::runtime_error("expected comma separator");
}
}
} while (i-- > 0);

in_s >> sep;
if (sep != ']') {
throw std::runtime_error("expected closing bracket");
}
}
};

/// Implementation of field_element_json for the base-case of Fp_model
/// types.
template<mp_size_t n, const libff::bigint<n> &modulus>
class field_element_json<libff::Fp_model<n, modulus>>
{
public:
using Field = libff::Fp_model<n, modulus>;
static void write(const Field &field_el, std::ostream &out_s)
{
out_s << '"' << base_field_element_to_hex(field_el) << '"';
};
static void read(Field &field_el, std::istream &in_s)
{
char quote;
in_s >> quote;
if (quote != '"') {
throw std::runtime_error("expected json string");
}
std::string bigint_hex;
try {
std::getline(in_s, bigint_hex, '"');
} catch (...) {
throw std::runtime_error("json string not terminated");
}
field_el = base_field_element_from_hex<Field>(bigint_hex);
}
};

// Generic reader and write for fields and field extensions.
template<typename FieldT> class field_element_bytes
{
public:
static void write(const FieldT &field_el, std::ostream &out_s)
{
for (size_t i = 0; i < FieldT::tower_extension_degree; ++i) {
field_element_write_bytes(field_el.coeffs[i], out_s);
}
}
static void read(FieldT &field_el, std::istream &in_s)
{
for (size_t i = 0; i < FieldT::tower_extension_degree; ++i) {
field_element_read_bytes(field_el.coeffs[i], in_s);
}
}
};

/// Implementation of field_element_bytes for the base-case of Fp_model types.
/// Big-endian bigint values (i.e. not in montgomery form).
template<mp_size_t n, const libff::bigint<n> &modulus>
class field_element_bytes<libff::Fp_model<n, modulus>>
{
public:
using Field = libff::Fp_model<n, modulus>;
static void write(const Field &field_el, std::ostream &out_s)
{
// Convert to bigint, reverse bytes in-place, and write to stream.
const libff::bigint<n> bi = field_el.as_bigint();
std::reverse((char *)(&bi), (char *)(&bi + 1));
out_s.write((const char *)(&bi.data[0]), sizeof(bi));
}
static void read(Field &field_el, std::istream &in_s)
{
// Read bigint from stream, reverse bytes in-place and convert to field
// element.
libff::bigint<n> res;
in_s.read((char *)(&res.data[0]), sizeof(res));
std::reverse((char *)(&res), (char *)(&res + 1));
field_el = Field(res);
}
};

} // namespace internal

template<typename FieldT>
std::string bigint_to_hex(
const libff::bigint<FieldT::num_limbs> &limbs, bool prefix)
{
return bytes_to_hex_reversed(&limbs.data[0], sizeof(limbs.data), prefix);
}

template<typename FieldT>
libff::bigint<FieldT::num_limbs> bigint_from_hex(const std::string &hex)
{
libff::bigint<FieldT::num_limbs> res;
hex_to_bytes_reversed(hex, &res.data[0], sizeof(res.data));
return res;
}

template<typename FieldT>
std::string base_field_element_to_hex(const FieldT &field_el)
{
// Serialize a "ground/base" field element
BOOST_ASSERT(FieldT::extension_degree() == 1);
return bigint_to_hex<FieldT>(field_el.as_bigint(), true);
static_assert(
FieldT::extension_degree() == 1, "only valid on base/ground fields");
return libff::bigint_to_hex(field_el.as_bigint(), true);
}

template<typename FieldT>
FieldT base_field_element_from_hex(const std::string &hex)
{
return FieldT(bigint_from_hex<FieldT>(hex));
static_assert(
FieldT::extension_degree() == 1, "only valid on base/ground fields");
using BigIntT =
typename std::decay<decltype(((FieldT *)nullptr)->mont_repr)>::type;
BigIntT v;
libff::bigint_from_hex(v, hex);
return FieldT(v);
}

template<typename FieldT>
void field_element_write_json(const FieldT &el, std::ostream &out_s)
{
internal::field_element_json<FieldT>::write(el, out_s);
libff::field_write<libff::encoding_json, libff::form_plain>(el, out_s);
}

template<typename FieldT>
void field_element_read_json(FieldT &el, std::istream &in_s)
{
internal::field_element_json<FieldT>::read(el, in_s);
libff::field_read<libff::encoding_json, libff::form_plain>(el, in_s);
}

template<typename FieldT> std::string field_element_to_json(const FieldT &el)
Expand All @@ -207,13 +67,13 @@ FieldT field_element_from_json(const std::string &json)
template<typename FieldT>
void field_element_write_bytes(const FieldT &el, std::ostream &out_s)
{
internal::field_element_bytes<FieldT>::write(el, out_s);
libff::field_write<libff::encoding_binary, libff::form_plain>(el, out_s);
}

template<typename FieldT>
void field_element_read_bytes(FieldT &el, std::istream &in_s)
{
internal::field_element_bytes<FieldT>::read(el, in_s);
libff::field_read<libff::encoding_binary, libff::form_plain>(el, in_s);
}

} // namespace libzeth
Expand Down
4 changes: 2 additions & 2 deletions libzeth/core/multi_exp.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ GroupT multi_exp(
typename std::vector<FieldT>::const_iterator fs_end)
{
const libff::multi_exp_method Method = libff::multi_exp_method_BDLO12;
return libff::multi_exp_with_mixed_addition<GroupT, FieldT, Method>(
return libff::multi_exp_filter_one_zero<GroupT, FieldT, Method>(
gs_start, gs_end, fs_start, fs_end, 1);
}

Expand All @@ -30,7 +30,7 @@ GroupT multi_exp(const std::vector<GroupT> &gs, const libff::Fr_vector<ppT> &fs)

using Fr = libff::Fr<ppT>;
const libff::multi_exp_method Method = libff::multi_exp_method_BDLO12;
return libff::multi_exp_with_mixed_addition<GroupT, Fr, Method>(
return libff::multi_exp_filter_one_zero<GroupT, Fr, Method>(
gs.begin(), gs.begin() + fs.size(), fs.begin(), fs.end(), 1);
}

Expand Down
1 change: 0 additions & 1 deletion libzeth/mpc/groth16/mpc_utils.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#define __ZETH_MPC_GROTH16_MPC_UTILS_TCC__

#include "libzeth/core/evaluator_from_lagrange.hpp"
#include "libzeth/core/multi_exp.hpp"
#include "libzeth/core/utils.hpp"
#include "libzeth/mpc/groth16/mpc_utils.hpp"
#include "libzeth/mpc/groth16/phase2.hpp"
Expand Down
10 changes: 8 additions & 2 deletions libzeth/mpc/groth16/phase2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,14 @@ srs_mpc_phase2_challenge<ppT> srs_mpc_dummy_phase2(
size_t num_inputs);

/// Given the output from all phases of the MPC, create the proving and
/// verification keys for the given circuit.
template<typename ppT>
/// verification keys for the given circuit. If BaseForm =
/// libff::multi_exp_base_form_special, all arrays are converted to special
/// form for more efficient proving (This will happen naturally as a side
/// effect of (de)serialization, and hence this batch conversion is disabled by
/// default).
template<
typename ppT,
libff::multi_exp_base_form BaseForm = libff::multi_exp_base_form_normal>
libsnark::r1cs_gg_ppzksnark_keypair<ppT> mpc_create_key_pair(
srs_powersoftau<ppT> &&pot,
srs_mpc_layer_L1<ppT> &&layer1,
Expand Down
10 changes: 9 additions & 1 deletion libzeth/mpc/groth16/phase2.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ srs_mpc_phase2_challenge<ppT> srs_mpc_dummy_phase2(
return srs_mpc_phase2_compute_challenge(std::move(response_1));
}

template<typename ppT>
template<typename ppT, libff::multi_exp_base_form BaseForm>
libsnark::r1cs_gg_ppzksnark_keypair<ppT> mpc_create_key_pair(
srs_powersoftau<ppT> &&pot,
srs_mpc_layer_L1<ppT> &&layer1,
Expand Down Expand Up @@ -762,6 +762,14 @@ libsnark::r1cs_gg_ppzksnark_keypair<ppT> mpc_create_key_pair(
layer2.delta_g2,
libsnark::accumulation_vector<G1>(std::move(ABC_0), std::move(ABC_i)));

// Convert all arrays to special form, if requested.
if (BaseForm == libff::multi_exp_base_form_special) {
libff::batch_to_special(layer1.A_g1);
libff::batch_to_special(B_i);
libff::batch_to_special(layer2.H_g1);
libff::batch_to_special(layer2.L_g1);
}

libsnark::r1cs_gg_ppzksnark_proving_key<ppT> pk(
G1(pot.alpha_tau_powers_g1[0]),
G1(pot.beta_tau_powers_g1[0]),
Expand Down
4 changes: 2 additions & 2 deletions libzeth/serialization/proto_utils.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ template<typename ppT>
void pairing_parameters_to_proto(zeth_proto::PairingParameters &pp_proto)
{
pp_proto.set_name(pp_name<ppT>());
pp_proto.set_r(bigint_to_hex<libff::Fr<ppT>>(libff::Fr<ppT>::mod));
pp_proto.set_q(bigint_to_hex<libff::Fq<ppT>>(libff::Fq<ppT>::mod));
pp_proto.set_r(libff::bigint_to_hex(libff::Fr<ppT>::mod));
pp_proto.set_q(libff::bigint_to_hex(libff::Fq<ppT>::mod));
*pp_proto.mutable_generator_g1() =
point_g1_affine_to_proto<ppT>(libff::G1<ppT>::one());
*pp_proto.mutable_generator_g2() =
Expand Down
6 changes: 2 additions & 4 deletions libzeth/serialization/r1cs_serialization.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ void constraints_write_json(
out_s << "{";
out_s << "\"index\":" << lt.index << ",";
out_s << "\"value\":"
<< "\"" + bigint_to_hex<FieldT>(lt.coeff.as_bigint(), true)
<< "\"";
<< "\"" + base_field_element_to_hex(lt.coeff) << "\"";
out_s << "}";
count++;
}
Expand Down Expand Up @@ -152,8 +151,7 @@ std::ostream &r1cs_write_json(

out_s << "{\n";
out_s << "\"scalar_field_characteristic\":"
<< "\"" + bigint_to_hex<FieldT>(FieldT::field_char(), true)
<< "\",\n";
<< "\"" + libff::bigint_to_hex(FieldT::field_char(), true) << "\",\n";
out_s << "\"num_variables\":" << r1cs.num_variables() << ",\n";
out_s << "\"num_constraints\":" << r1cs.num_constraints() << ",\n";
out_s << "\"num_inputs\": " << r1cs.num_inputs() << ",\n";
Expand Down
6 changes: 2 additions & 4 deletions libzeth/tests/core/ec_operation_data_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ template<typename ppT> void operation_test_data()
std::stringstream binary_stream;

std::cout << " Fr:";
std::cout << "\n r: "
<< bigint_to_hex<libff::Fr<ppT>>(libff::Fr<ppT>::mod);
std::cout << "\n r: " << libff::bigint_to_hex(libff::Fr<ppT>::mod);

std::cout << "\n 1: ";
field_element_write_json(fr_1, std::cout);
Expand All @@ -69,8 +68,7 @@ template<typename ppT> void operation_test_data()
field_element_write_bytes(fr_minus_2, binary_stream);

std::cout << " Fq:";
std::cout << "\n q: "
<< bigint_to_hex<libff::Fq<ppT>>(libff::Fq<ppT>::mod);
std::cout << "\n q: " << libff::bigint_to_hex(libff::Fq<ppT>::mod);

std::cout << "\n G1:";
std::cout << "\n 1: ";
Expand Down
Loading