Skip to content

Commit

Permalink
Refactor poseidon usage
Browse files Browse the repository at this point in the history
  • Loading branch information
x-mass committed Apr 12, 2024
1 parent b8dc491 commit c1d371f
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,19 +104,19 @@ namespace nil {

while( true ) {
transcript_type tmp_transcript = transcript;
tmp_transcript(proof_of_work);
tmp_transcript(std::array<typename FieldType::value_type, 1>{proof_of_work});
result = integral_type(tmp_transcript.template challenge<FieldType>().data);
if ((result & mask) == 0)
break;
proof_of_work++;
}
transcript(proof_of_work);
transcript(std::array<typename FieldType::value_type, 1>{proof_of_work});
result = integral_type(transcript.template challenge<FieldType>().data);
return proof_of_work;
}

static inline bool verify(transcript_type &transcript, value_type proof_of_work, std::size_t GrindingBits=16) {
transcript(proof_of_work);
transcript(std::array<typename FieldType::value_type, 1>{proof_of_work});
integral_type mask =
(GrindingBits > 0 ?
((integral_type(1) << GrindingBits) - 1) << (FieldType::modulus_bits - GrindingBits)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ namespace nil {

// TODO: KZG fixed_values_commitments are vector<uint8_t>
// need operator<<(ostream,vector<uint8_t>)?
ss << constraint_system_with_params_hash /*<< " " << fixed_values_commitment*/;
ss << constraint_system_with_params_hash[0] /*<< " " << fixed_values_commitment*/; // HACK
return ss.str();
}
};
Expand Down
126 changes: 85 additions & 41 deletions include/nil/crypto3/zk/transcript/fiat_shamir.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,19 @@
#include <nil/marshalling/algorithms/pack.hpp>
#include <nil/crypto3/marshalling/algebra/types/field_element.hpp>

#include <nil/crypto3/hash/type_traits.hpp>
#include <nil/crypto3/hash/algorithm/hash.hpp>
#include <nil/crypto3/hash/sha2.hpp>
#include <nil/crypto3/hash/keccak.hpp>
#include <nil/crypto3/hash/poseidon.hpp>
#include <nil/crypto3/hash/sha2.hpp>
#include <nil/crypto3/hash/type_traits.hpp>
#include <nil/crypto3/hash/type_traits.hpp>

#include <nil/crypto3/algebra/curves/pallas.hpp>
#include <nil/crypto3/algebra/fields/arithmetic_params/pallas.hpp>
#include <nil/crypto3/hash/poseidon.hpp>

#include <nil/crypto3/hash/detail/poseidon/kimchi_constants.hpp>
#include <nil/crypto3/hash/detail/poseidon/original_constants.hpp>
#include <nil/crypto3/hash/detail/poseidon/poseidon_policy.hpp>
#include <nil/crypto3/hash/detail/poseidon/poseidon_permutation.hpp>
#include <nil/crypto3/hash/detail/poseidon/poseidon_sponge.hpp>
#include <nil/crypto3/hash/detail/block_stream_processor.hpp>
#include <nil/crypto3/algebra/type_traits.hpp>

#include <nil/crypto3/multiprecision/cpp_int.hpp>

namespace nil {
namespace crypto3 {
namespace zk {
Expand Down Expand Up @@ -88,10 +84,18 @@ namespace nil {

template<typename TAny>
void operator()(TAny data) {
nil::marshalling::status_type status;
typename hash_type::construction::type::block_type byte_data =
nil::marshalling::pack(data, status);
acc(byte_data);
if constexpr (algebra::is_field_element<typename hash_type::word_type>::value) {
BOOST_STATIC_ASSERT_MSG(
algebra::is_field_element<TAny>::value,
"Hash type consumes field elements, but provided value is not a field element"
);
acc(data);
} else {
nil::marshalling::status_type status;
typename hash_type::construction::type::block_type byte_data =
nil::marshalling::pack(data, status);
acc(byte_data);
}
}

template<typename ChallengesType::challenges_ids ChallengeId, typename FieldType>
Expand Down Expand Up @@ -127,7 +131,6 @@ namespace nil {
}
};


template<typename Hash, typename Enable = void>
struct fiat_shamir_heuristic_sequential
{
Expand Down Expand Up @@ -196,55 +199,95 @@ namespace nil {
typename hash_type::digest_type state;
};

// Specialize for posseidon.
// Specialize for Nil Posseidon.
template<typename Hash>
struct fiat_shamir_heuristic_sequential<
Hash,
typename std::enable_if_t<crypto3::hashes::is_poseidon<Hash>::value>> {

typedef Hash hash_type;
using field_type = nil::crypto3::algebra::curves::pallas::base_field_type;
using poseidon_policy = nil::crypto3::hashes::detail::mina_poseidon_policy<field_type>;
using permutation_type = nil::crypto3::hashes::detail::poseidon_permutation<poseidon_policy>;
using state_type = typename permutation_type::state_type;

fiat_shamir_heuristic_sequential() {
Hash,
typename std::enable_if_t<
nil::crypto3::hashes::is_specialization_of<
nil::crypto3::hashes::nil_poseidon,
Hash
>::value
>
> {
// Differences from other hashes fiat_shamir_heuristic_sequential are:
// challenge(), int_challange(), no-args ctor and last_call_was_challenge_ field

using hash_type = Hash;

fiat_shamir_heuristic_sequential() : state{0} {
}

template<typename InputRange>
fiat_shamir_heuristic_sequential(const InputRange &r) {
if(r.size() != 0) {
sponge.absorb(hash<hash_type>(r));
}
fiat_shamir_heuristic_sequential(const InputRange &r) : state(hash<hash_type>(r)) {
}

template<typename InputIterator>
fiat_shamir_heuristic_sequential(InputIterator first, InputIterator last) {
sponge.absorb(hash<hash_type>(first, last));
}

void operator()(const typename hash_type::digest_type input) {
sponge.absorb(input);
fiat_shamir_heuristic_sequential(InputIterator first, InputIterator last) :
state(hash<hash_type>(first, last)) {
}

template<typename InputRange>
void operator()(const InputRange &r) {
sponge.absorb(hash<hash_type>(r));
auto acc_convertible = hash<hash_type>(state);
state = accumulators::extract::hash<hash_type>(
hash<hash_type>(r, static_cast<accumulator_set<hash_type> &>(acc_convertible)));
last_call_was_challenge_ = false;
}

template<typename InputIterator>
void operator()(InputIterator first, InputIterator last) {
sponge.absorb(hash<hash_type>(first, last));
auto acc_convertible = hash<hash_type>(state);
state = accumulators::extract::hash<hash_type>(
hash<hash_type>(first, last, static_cast<accumulator_set<hash_type> &>(acc_convertible)));
last_call_was_challenge_ = false;
}

template<typename Field>
typename Field::value_type challenge() {
return sponge.squeeze();
// After refactoring an attempt to remove this Nil Poseidon specialization was made.
// The difference between challenge() for other hashes and for Nil Poseidon is
// how the second challenge is produced. For the first call things are the same:
// we feed the result A (aka state in current code) of hash from operator() to hash, it
// puts A to sponge_state[1] (read about nil_poseidon_sponge, if you're wondered why not
// sponge_state[0]), then calls squeeze(). But for the second challenge thigs are
// different: other hashes feed state B to hash again (in case of Nil Poseidon state will
// be put to sponge_state[1]), but here we just run squeeze() (B is located in sponge_state[0]).
std::cout << "in challange, state before extraction: " << std::endl;
for (const auto& el : state) {
std::cout << el << std::endl;
}

if (last_call_was_challenge_) {
// In case previous called func was challenge() as well, we want to
// mimic sequential squeeze() calls
typename hash_type::construction::type::state_type sponge_state{};
std::move(state.begin(), state.end(), sponge_state.begin());
typename hash_type::construction::type sponge{
typename hash_type::construction::type::state_type{sponge_state}
};
state = sponge.digest();
} else {
accumulator_set<hash_type> acc;
for (auto& el : state) {
acc(std::move(el));
}
state = accumulators::extract::hash<hash_type>(acc);
}

std::cout << "in challange, state after extraction: " << std::endl;
for (const auto& el : state) {
std::cout << el << std::endl;
}
nil::marshalling::status_type status;
nil::crypto3::multiprecision::cpp_int raw_result = nil::marshalling::pack(state, status);
last_call_was_challenge_ = true;
return raw_result;
}

template<typename Integral>
Integral int_challenge() {
auto c = challenge<field_type>();
auto c = challenge<typename hash_type::policy_type::field_type>();

nil::crypto3::multiprecision::cpp_int intermediate_result =
c.data.template convert_to<nil::crypto3::multiprecision::cpp_int>();
Expand Down Expand Up @@ -272,7 +315,8 @@ namespace nil {
}

private:
hashes::detail::poseidon_sponge_construction<typename Hash::policy_type> sponge;
typename hash_type::digest_type state;
bool last_call_was_challenge_ = false; // Ctors call absorb
};

} // namespace transcript
Expand Down
2 changes: 1 addition & 1 deletion test/commitment/proof_of_work.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE(pow_poseidon_basic_test) {
BOOST_ASSERT(pow_type::verify(old_transcript_1, result, 9));

// manually reimplement verify to ensure that changes in implementation didn't break it
old_transcript_2(result);
old_transcript_2(std::vector<nil::crypto3::algebra::fields::pallas_base_field::value_type>{result});
auto chal = old_transcript_2.template challenge<field_type>();
BOOST_ASSERT((integral_type(chal.data) & expected_mask) == 0);

Expand Down
9 changes: 6 additions & 3 deletions test/transcript/transcript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <nil/crypto3/algebra/curves/alt_bn128.hpp>
#include <nil/crypto3/algebra/fields/arithmetic_params/alt_bn128.hpp>

#include <nil/crypto3/hash/block_to_field_elements_wrapper.hpp>
#include <nil/crypto3/hash/poseidon.hpp>
#include <nil/crypto3/hash/keccak.hpp>

Expand Down Expand Up @@ -71,10 +72,12 @@ BOOST_AUTO_TEST_SUITE(zk_poseidon_transcript_test_suite)
BOOST_AUTO_TEST_CASE(zk_poseidon_transcript_init_test) {
using curve_type = algebra::curves::pallas;
using field_type = typename curve_type::base_field_type;
using poseidon_type = hashes::poseidon<nil::crypto3::hashes::detail::mina_poseidon_policy<field_type>>;
using poseidon_type = hashes::nil_poseidon<nil::crypto3::hashes::detail::mina_poseidon_policy<field_type>>;

std::vector<std::uint8_t> init_blob {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
transcript::fiat_shamir_heuristic_sequential<poseidon_type> tr(init_blob);
transcript::fiat_shamir_heuristic_sequential<poseidon_type> tr{
hashes::block_to_field_elements_wrapper<field_type, std::vector<std::uint8_t>>(init_blob)
};
auto ch1 = tr.challenge<field_type>();
auto ch2 = tr.challenge<field_type>();
int ch_int = tr.int_challenge<int>();
Expand All @@ -87,7 +90,7 @@ BOOST_AUTO_TEST_CASE(zk_poseidon_transcript_init_test) {
BOOST_AUTO_TEST_CASE(zk_poseidon_transcript_no_init_test) {
using curve_type = algebra::curves::pallas;
using field_type = typename curve_type::base_field_type;
using poseidon_type = hashes::poseidon<nil::crypto3::hashes::detail::mina_poseidon_policy<field_type>>;
using poseidon_type = hashes::nil_poseidon<nil::crypto3::hashes::detail::mina_poseidon_policy<field_type>>;

transcript::fiat_shamir_heuristic_sequential<poseidon_type> tr;
auto ch1 = tr.challenge<field_type>();
Expand Down

0 comments on commit c1d371f

Please sign in to comment.