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

Caphash optimization #45

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
3 changes: 3 additions & 0 deletions libiop/algebra/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ void bitreverse_vector(std::vector<T> &a);
template<typename T>
std::vector<T> random_vector(const std::size_t count);

template<typename T, typename U>
bool compare_first(const std::pair<T, U> &a, const std::pair<T, U> &b);

template<typename T>
std::vector<T> all_subset_sums(const std::vector<T> &basis, const T& shift = 0)
#if defined(__clang__)
Expand Down
6 changes: 6 additions & 0 deletions libiop/algebra/utils.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ std::vector<T> random_vector(const std::size_t count)
return result;
}

template<typename T, typename U>
bool compare_first(const std::pair<T, U> &a, const std::pair<T, U> &b)
{
return a.first < b.first;
}

template<typename FieldT>
std::vector<FieldT> random_FieldT_vector(const std::size_t count)
{
Expand Down
2 changes: 2 additions & 0 deletions libiop/bcs/bcs_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ template<typename FieldT, typename MT_hash_type>
struct bcs_transformation_parameters {
std::size_t security_parameter; /* TODO: possibly revisit in the future */
bcs_hash_type hash_enum;
std::size_t cap_size;

pow_parameters pow_params_;

std::shared_ptr<hashchain<FieldT, MT_hash_type>> hashchain_;
std::shared_ptr<leafhash<FieldT, MT_hash_type>> leafhasher_;
two_to_one_hash_function<MT_hash_type> compression_hasher;
cap_hash_function<MT_hash_type> cap_hasher;
};

template<typename FieldT, typename MT_hash_type>
Expand Down
27 changes: 16 additions & 11 deletions libiop/bcs/bcs_common.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -471,9 +471,11 @@ void bcs_protocol<FieldT, MT_root_hash>::seal_interaction_registrations()
size,
this->parameters_.leafhasher_,
this->parameters_.compression_hasher,
this->parameters_.cap_hasher,
this->digest_len_bytes_,
make_zk,
this->parameters_.security_parameter);
this->parameters_.security_parameter,
this->parameters_.cap_size);
this->Merkle_trees_.emplace_back(MT);
}
}
Expand Down Expand Up @@ -710,7 +712,7 @@ void print_detailed_transcript_data(

const size_t digest_len_bytes = 2 * (params.security_parameter / 8);
const size_t field_size = (libff::log_of_field_size_helper<FieldT>(FieldT::zero()) + 7) / 8;
std::vector<size_t> two_to_one_hashes_by_round;
std::vector<size_t> internal_hash_complexity_by_round;
std::vector<size_t> leaf_hashes_by_round;
std::vector<size_t> zk_hashes_by_round;
std::vector<size_t> IOP_size_by_round;
Expand All @@ -724,6 +726,7 @@ void print_detailed_transcript_data(
MT_size,
params.leafhasher_,
params.compression_hasher,
params.cap_hasher,
digest_len_bytes,
false,
params.security_parameter);
Expand All @@ -741,10 +744,9 @@ void print_detailed_transcript_data(
query_positions.emplace_back(MT_position);
}
}
size_t num_two_to_one_hashes_in_round =
MT.count_hashes_to_verify_set_membership_proof(
query_positions);
two_to_one_hashes_by_round.emplace_back(num_two_to_one_hashes_in_round);
size_t internal_hash_complexity_in_round =
MT.count_internal_hash_complexity_to_verify_set_membership(query_positions);
internal_hash_complexity_by_round.emplace_back(internal_hash_complexity_in_round);
const size_t num_values_per_leaf = transcript.query_responses_[round][0].size();
const size_t num_leaves = transcript.query_responses_[round].size();
leaf_hashes_by_round.emplace_back(num_values_per_leaf * num_leaves);
Expand Down Expand Up @@ -788,14 +790,17 @@ void print_detailed_transcript_data(

printf("\n");
printf("total prover messages size: %lu\n", total_prover_message_size);
const size_t total_two_to_one_hashes = std::accumulate(
two_to_one_hashes_by_round.begin(), two_to_one_hashes_by_round.end(), 0);
const size_t total_internal_hash_complexity = std::accumulate(
internal_hash_complexity_by_round.begin(), internal_hash_complexity_by_round.end(), 0);
const size_t total_leaves_hashed = std::accumulate(
leaf_hashes_by_round.begin(), leaf_hashes_by_round.end(), 0);
const size_t total_zk_hashes = std::accumulate(
zk_hashes_by_round.begin(), zk_hashes_by_round.end(), 0);
const size_t total_hashes = total_two_to_one_hashes + total_leaves_hashed + total_zk_hashes;
printf("total two to one hashes: %lu\n", total_two_to_one_hashes);
/* Since each two-to-one hash is counted as two units, we divide by 2 here to make it consistent.
It would be nice to take into account how many leaves are hashed, but we are unfortunately
not provided this information. */
const size_t total_hashes = total_internal_hash_complexity / 2 + total_leaves_hashed + total_zk_hashes;
printf("total internal hash complexity: %lu\n", total_internal_hash_complexity);
printf("total leaves hashed: %lu\n", total_leaves_hashed);
printf("total hashes: %lu\n", total_hashes);
printf("\n");
Expand All @@ -808,7 +813,7 @@ void print_detailed_transcript_data(
printf("MT_depth %lu\n", MT_depths[round]);
printf("IOP size: %lu bytes\n", IOP_size_by_round[round]);
printf("BCS size: %lu bytes\n", BCS_size_by_round[round]);
printf("number of two to one hashes: %lu\n", two_to_one_hashes_by_round[round]);
printf("internal hash complexity: %lu\n", internal_hash_complexity_by_round[round]);
printf("number of leaves hashed: %lu\n", leaf_hashes_by_round[round]);
if (make_zk[round])
{
Expand Down
7 changes: 4 additions & 3 deletions libiop/bcs/common_bcs_parameters.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ bcs_transformation_parameters<FieldT, MT_root_hash> default_bcs_params(
params.hash_enum = hash_type;
/* TODO: Push setting leaf hash into internal BCS code. Currently 2 is fine, as leaf size is internally unused. */
const size_t leaf_size = 2;
params.leafhasher_ = get_leafhash<FieldT, MT_root_hash>(hash_type, security_parameter, leaf_size);
params.cap_size = 2;
params.leafhasher_ = get_leafhash<MT_root_hash, FieldT>(hash_type, security_parameter, leaf_size);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this just a bug before?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I switched the order to be consistent with similar functions

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still believe the template ordering before was right

Copy link
Member

@ValarDragon ValarDragon Jul 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see, you switched the template ordering of the internal command. Currently there are inconsistent orderings throughout, I believe the old <FieldT, MT_root_hash> was consistently used everywhere. We should consistently be using one or the other, I don't really have a preference for which one.

Copy link
Contributor Author

@alexander-zw alexander-zw Jul 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I switched all instances of the leaf hash functions to be the same as the hashchain. If you insist, I can change it back, but it is currently consistent as well.

params.compression_hasher = get_two_to_one_hash<MT_root_hash, FieldT>(hash_type, security_parameter);
params.hashchain_ =
get_hashchain<FieldT, MT_root_hash>(hash_type, security_parameter);
params.cap_hasher = get_cap_hash<MT_root_hash, FieldT>(hash_type, security_parameter);
params.hashchain_ = get_hashchain<FieldT, MT_root_hash>(hash_type, security_parameter);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed above, we are switching <FieldT, MT_root_hash> to <MT_root_hash, FieldT> in leafhasher (now cap_hasher here).

Do we want to apply the same refactoring to hashchain? We probably should do that in a separate PR for ease of testing.

Copy link
Contributor Author

@alexander-zw alexander-zw Sep 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'd prefer to keep it the same for this PR, unless it causes merge conflicts

Copy link
Contributor Author

@alexander-zw alexander-zw Sep 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's acceptable, I'd like to keep them both the current order for now. We can refactor both at the same time in a future PR. This PR is already quite big, and it's been a long time since I wrote this so I don't remember all the context


// Work per hash. Todo generalize this w/ proper explanations of work amounts
const size_t work_per_hash = (hash_type == 1) ? 1 : 128;
Expand Down
8 changes: 6 additions & 2 deletions libiop/bcs/hashing/algebraic_sponge.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,15 @@ class algebraic_hashchain : public hashchain<FieldT, MT_root_type>
void absorb_internal(const typename libff::enable_if<std::is_same<MT_root_type, FieldT>::value, MT_root_type>::type new_input);
};

/** The algebraic_vector_hash is used for both the algebraic leaf hash and cap hash. */
template<typename FieldT>
class algebraic_leafhash : public leafhash<FieldT, FieldT>
class algebraic_vector_hash : public leafhash<FieldT, FieldT>
{
protected:
std::shared_ptr<algebraic_sponge<FieldT>> sponge_;

public:
algebraic_leafhash(
algebraic_vector_hash(
std::shared_ptr<algebraic_sponge<FieldT>> sponge,
size_t security_parameter);
FieldT hash(const std::vector<FieldT> &leaf);
Expand All @@ -115,6 +116,9 @@ class algebraic_leafhash : public leafhash<FieldT, FieldT>
const zk_salt_type &zk_salt);
};

template<typename FieldT>
using algebraic_leafhash = algebraic_vector_hash<FieldT>;

template<typename FieldT>
class algebraic_two_to_one_hash
{
Expand Down
6 changes: 3 additions & 3 deletions libiop/bcs/hashing/algebraic_sponge.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ MT_root_type algebraic_hashchain<FieldT, MT_root_type>::squeeze_root_type()
}

template<typename FieldT>
algebraic_leafhash<FieldT>::algebraic_leafhash(
algebraic_vector_hash<FieldT>::algebraic_vector_hash(
std::shared_ptr<algebraic_sponge<FieldT>> sponge,
size_t security_parameter) :
sponge_(sponge->new_sponge())
Expand All @@ -218,7 +218,7 @@ algebraic_leafhash<FieldT>::algebraic_leafhash(
}

template<typename FieldT>
FieldT algebraic_leafhash<FieldT>::hash(
FieldT algebraic_vector_hash<FieldT>::hash(
const std::vector<FieldT> &leaf)
{
this->sponge_->absorb(leaf);
Expand All @@ -228,7 +228,7 @@ FieldT algebraic_leafhash<FieldT>::hash(
}

template<typename FieldT>
FieldT algebraic_leafhash<FieldT>::zk_hash(
FieldT algebraic_vector_hash<FieldT>::zk_hash(
const std::vector<FieldT> &leaf,
const zk_salt_type &zk_salt)
{
Expand Down
31 changes: 30 additions & 1 deletion libiop/bcs/hashing/blake2b.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ binary_hash_digest blake2b_two_to_one_hash(const binary_hash_digest &first,
const binary_hash_digest &second,
const std::size_t digest_len_bytes)
{
/* binary_hash_digest is a C++ string pointer so we need to sum them since they are not
contiguous in memory. */
const binary_hash_digest first_plus_second = first + second;

binary_hash_digest result(digest_len_bytes, 'X');
Expand All @@ -47,6 +49,33 @@ binary_hash_digest blake2b_two_to_one_hash(const binary_hash_digest &first,
return result;
}

binary_hash_digest blake2b_many_to_one_hash(const std::vector<binary_hash_digest> &data,
const std::size_t digest_len_bytes)
{
/* binary_hash_digest is a C++ string pointer so we need to sum them since they are not
contiguous in memory. */
binary_hash_digest input = data[0];
for (int i = 1; i < data.size(); i++)
{
input += data[i];
}

binary_hash_digest result(digest_len_bytes, 'X');

/* see https://download.libsodium.org/doc/hashing/generic_hashing.html */
const int status = crypto_generichash_blake2b((unsigned char*)&result[0],
digest_len_bytes,
(result.empty() ? NULL : (unsigned char*)&input[0]),
alexander-zw marked this conversation as resolved.
Show resolved Hide resolved
input.size(),
NULL, 0);
if (status != 0)
{
throw std::runtime_error("Got non-zero status from crypto_generichash_blake2b. (Is digest_len_bytes correct?)");
}

return result;
}

std::size_t blake2b_integer_randomness_extractor(const binary_hash_digest &root,
const std::size_t index,
const std::size_t upper_bound)
Expand All @@ -73,4 +102,4 @@ std::size_t blake2b_integer_randomness_extractor(const binary_hash_digest &root,
return result % upper_bound;
}

}
} // namespace libiop
13 changes: 10 additions & 3 deletions libiop/bcs/hashing/blake2b.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ class blake2b_leafhash : public leafhash<FieldT, binary_hash_digest>
const zk_salt_type &zk_salt);
};

/* Many-to-one hash which takes in a vector of field elements.
Behavior undefined when data is empty. */
template<typename FieldT>
binary_hash_digest blake2b_field_element_hash(const std::vector<FieldT> &data,
const std::size_t digest_len_bytes);
Expand All @@ -73,11 +75,16 @@ std::size_t blake2b_integer_randomness_extractor(const binary_hash_digest &root,
const std::size_t upper_bound);

binary_hash_digest blake2b_zk_element_hash(const std::vector<uint8_t> &first,
const std::size_t digest_len_bytes);
const std::size_t digest_len_bytes);

binary_hash_digest blake2b_two_to_one_hash(const binary_hash_digest &first,
const binary_hash_digest &second,
const std::size_t digest_len_bytes);
const binary_hash_digest &second,
const std::size_t digest_len_bytes);

/* Many-to-one hash which takes in a vector of binary_hash_digest.
Behavior undefined when data is empty. */
binary_hash_digest blake2b_many_to_one_hash(const std::vector<binary_hash_digest> &data,
const std::size_t digest_len_bytes);

} // namespace libiop

Expand Down
6 changes: 2 additions & 4 deletions libiop/bcs/hashing/blake2b.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,8 @@ binary_hash_digest blake2b_leafhash<FieldT>::zk_hash(
// don't we need to make them in canonical form first?
template<typename FieldT>
binary_hash_digest blake2b_field_element_hash(const std::vector<FieldT> &data,
const std::size_t digest_len_bytes)
const std::size_t digest_len_bytes)
{

binary_hash_digest result(digest_len_bytes, 'X');

/* see https://download.libsodium.org/doc/hashing/generic_hashing.html */
Expand All @@ -155,7 +154,6 @@ binary_hash_digest blake2b_field_element_hash(const std::vector<FieldT> &data,
throw std::runtime_error("Got non-zero status from crypto_generichash_blake2b. (Is digest_len_bytes correct?)");
}


return result;
}

Expand Down Expand Up @@ -256,4 +254,4 @@ std::vector<FieldT> blake2b_FieldT_randomness_extractor(const binary_hash_digest
return result;
}

}
} // namespace libiop
3 changes: 3 additions & 0 deletions libiop/bcs/hashing/dummy_algebraic_hash.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ FieldT dummy_algebraic_two_to_one_hash(
const FieldT &second,
const std::size_t digest_len_bytes);

template<typename FieldT>
FieldT dummy_algebraic_cap_hash(const std::vector<FieldT> &data, const std::size_t digest_len_bytes);

} // namespace libiop

#include "libiop/bcs/hashing/dummy_algebraic_hash.tcc"
Expand Down
14 changes: 13 additions & 1 deletion libiop/bcs/hashing/dummy_algebraic_hash.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ FieldT dummy_algebraic_leafhash<FieldT>::hash(const std::vector<FieldT> &leaf)
FieldT sum = FieldT::zero();
for (size_t i = 0; i < leaf.size(); i++)
{
sum += FieldT(i) * leaf[i];
sum += FieldT(i + 1) * leaf[i]; // Add one, otherwise the 0th index is unused.
}
return sum;
}
Expand Down Expand Up @@ -147,4 +147,16 @@ FieldT dummy_algebraic_two_to_one_hash(
return FieldT(2) * first + second;
}

template<typename FieldT>
FieldT dummy_algebraic_cap_hash(const std::vector<FieldT> &data, const std::size_t digest_len_bytes)
{
FieldT sum = FieldT::zero();
for (size_t i = 0; i < data.size(); i++)
{
sum += FieldT(i + 1) * data[i]; // Add one, otherwise the 0th index is unused.
}

return sum;
}

}
9 changes: 6 additions & 3 deletions libiop/bcs/hashing/hash_enum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,18 @@ static const char* bcs_hash_type_names[] = {"", "blake2b", "poseidon with Starkw
template<typename FieldT, typename MT_root_type>
std::shared_ptr<hashchain<FieldT, MT_root_type>> get_hashchain(bcs_hash_type hash_type, size_t security_parameter);

template<typename FieldT, typename leaf_hash_type>
template<typename leaf_hash_type, typename FieldT>
std::shared_ptr<leafhash<FieldT, leaf_hash_type>> get_leafhash(
const bcs_hash_type hash_type,
const size_t security_parameter,
const bcs_hash_type hash_type,
const size_t security_parameter,
const size_t leaf_size);

template<typename hash_type, typename FieldT>
two_to_one_hash_function<hash_type> get_two_to_one_hash(const bcs_hash_type hash_enum, const size_t security_parameter);

template<typename hash_type, typename FieldT>
cap_hash_function<hash_type> get_cap_hash(const bcs_hash_type hash_enum, const size_t security_parameter);

}
#include "libiop/bcs/hashing/hash_enum.tcc"

Expand Down
Loading