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

Implemented padding at the stage of block_to_field_wrapper #280

Merged
merged 2 commits into from
Jan 27, 2025
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
10 changes: 5 additions & 5 deletions crypto3/libs/hash/example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@
# http://www.boost.org/LICENSE_1_0.txt
#---------------------------------------------------------------------------#

macro(define_algebra_example name)
add_executable(algebra_${name}_example ${name}.cpp)
target_link_libraries(algebra_${name}_example PRIVATE
macro(define_hash_example name)
add_executable(hash_${name}_example ${name}.cpp)
target_link_libraries(hash_${name}_example PRIVATE
${CMAKE_WORKSPACE_NAME}_hash

crypto3::multiprecision
Boost::random
)

set_target_properties(algebra_${name}_example PROPERTIES CXX_STANDARD 20)
set_target_properties(hash_${name}_example PROPERTIES CXX_STANDARD 20)
endmacro()

set(EXAMPLES_NAMES
"hashes")

foreach(EXAMPLE_NAME ${EXAMPLES_NAMES})
define_algebra_example(${EXAMPLE_NAME})
define_hash_example(${EXAMPLE_NAME})
endforeach()
58 changes: 57 additions & 1 deletion crypto3/libs/hash/example/hashes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
#include <nil/crypto3/algebra/fields/bls12/scalar_field.hpp>
#include <type_traits>

#include <nil/crypto3/hash/detail/poseidon/poseidon_policy.hpp>
#include <nil/crypto3/hash/block_to_field_elements_wrapper.hpp>
#include "nil/crypto3/algebra/fields/pallas/scalar_field.hpp"

using namespace nil::crypto3::hashes;

template<typename hash_type, typename enable = void>
Expand Down Expand Up @@ -64,9 +68,60 @@ struct hash_usage_example<hash_type, typename std::enable_if<is_poseidon<hash_ty

typename policy::digest_type result = nil::crypto3::hash<hash_type>(field_input);
std::cout << result << std::endl;

}
};

template<typename hash_type>
struct poseidon_bytes_vector_example
{
static void run()
{
using policy = typename hash_type::policy_type;
using field_type = typename policy::field_type;
std::string input =
"Once upon a midnight dreary, while I pondered, weak and weary,\n"
"Over many a quaint and curious volume of forgotten lore—\n"
"While I nodded, nearly napping, suddenly there came a tapping,\n"
"As of some one gently rapping, rapping at my chamber door.\n"
"“’Tis some visitor,” I muttered, “tapping at my chamber door—\n"
" Only this and nothing more.”\n";

std::vector<uint8_t> hash_input(input.begin(), input.end());

typename policy::digest_type result = nil::crypto3::hash<hash_type>(
nil::crypto3::hashes::conditional_block_to_field_elements_wrapper<
typename hash_type::word_type,
decltype(hash_input)>
(hash_input)
);
std::cout << result << std::endl;
}
};

template<typename hash_type>
struct poseidon_int_vector_example
{
static void run()
{
using policy = typename hash_type::policy_type;
using field_type = typename policy::field_type;

std::vector<uint32_t> hash_input {
0xDEAD, 0xC001CAFE
};

typename policy::digest_type result = nil::crypto3::hash<hash_type>(
nil::crypto3::hashes::conditional_block_to_field_elements_wrapper<
typename hash_type::word_type,
decltype(hash_input)>
(hash_input)
);
std::cout << result << std::endl;
}
};



int main() {
std::cout << "SHA2-256" << std::endl;
Expand All @@ -86,8 +141,9 @@ int main() {
using policy = detail::poseidon_policy<field_type, security_bits, rate>;
using hash_type = poseidon<policy>;


hash_usage_example<hash_type>::run();
poseidon_bytes_vector_example<hash_type>::run();
poseidon_int_vector_example<hash_type>::run();

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace nil {
namespace crypto3 {
namespace hashes {

template<typename Field, typename Container, bool OverflowOnPurpose = false>
template<typename Field, typename Container, bool OverflowOnPurpose = false, bool Padding = true>
class block_to_field_elements_wrapper {
public:
static_assert(std::numeric_limits<typename Container::value_type>::is_specialized);
Expand Down Expand Up @@ -106,12 +106,19 @@ namespace nil {
field_element_.data = field_element_.data.base() << input_value_bits_;
field_element_ += uint64_t(*tmp_iter++);
}
if (tmp_iter == input_container_r_ && Padding) {
std::size_t element_size = sizeof(typename std::iterator_traits<decltype(input_container_l_)>::value_type);
std::size_t bits_filled = 8 * element_size * std::distance(input_container_l_, tmp_iter);
/* This always adds 1 to higher bits without overflow as field element
* is filled with one byte less than a modulus width. */
field_element_ += typename value_type::integral_type(1) << (bits_filled);
}
element_filled_ = true;
}

void advance_container_iter() {
for (std::size_t i = 0; i < container_elements_per_field_element_ && input_container_l_ != input_container_r_; ++i) {
input_container_l_++;
++input_container_l_;
}
element_filled_ = false;
}
Expand Down Expand Up @@ -140,18 +147,19 @@ namespace nil {
typename Container::const_iterator input_container_end_;
};

template<typename Output, typename Container, bool OverflowOnPurpose, bool = algebra::is_field_element<Output>::value>
template<typename Output, typename Container, bool OverflowOnPurpose, bool Padding = true, bool = algebra::is_field_element<Output>::value>
struct conditional_block_to_field_elements_wrapper_helper {
using type = Container;
};

template<typename Output, typename Container, bool OverflowOnPurpose>
struct conditional_block_to_field_elements_wrapper_helper<Output, Container, OverflowOnPurpose, true> {
using type = block_to_field_elements_wrapper<typename Output::field_type, Container, OverflowOnPurpose>;
template<typename Output, typename Container, bool OverflowOnPurpose, bool Padding>
struct conditional_block_to_field_elements_wrapper_helper<Output, Container, OverflowOnPurpose, Padding, true> {
using type = block_to_field_elements_wrapper<typename Output::field_type, Container, OverflowOnPurpose, Padding>;
};

template<typename Output, typename Container, bool OverflowOnPurpose = false>
using conditional_block_to_field_elements_wrapper = typename conditional_block_to_field_elements_wrapper_helper<Output, Container, OverflowOnPurpose>::type;
template<typename Output, typename Container, bool OverflowOnPurpose = false, bool Padding = true>
using conditional_block_to_field_elements_wrapper =
typename conditional_block_to_field_elements_wrapper_helper<Output, Container, OverflowOnPurpose, Padding>::type;


} // namespace hashes
Expand Down
77 changes: 75 additions & 2 deletions crypto3/libs/hash/test/poseidon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// http://www.boost.org/LICENSE_1_0.txt
//---------------------------------------------------------------------------//

#include "nil/crypto3/algebra/fields/pallas/scalar_field.hpp"
#include "nil/crypto3/hash/detail/poseidon/poseidon_policy.hpp"
#define BOOST_TEST_MODULE poseidon_test

#include <iostream>
Expand Down Expand Up @@ -99,6 +101,77 @@ void test_poseidon_permutation(
}

BOOST_AUTO_TEST_SUITE(poseidon_tests)

BOOST_AUTO_TEST_CASE(poseidon_with_padding_test) {
using field_type = fields::pallas_scalar_field;
using policy = pasta_poseidon_policy<field_type>;
using hash_type = hashes::poseidon<policy>;

std::vector<uint8_t> hash_input1 {
0x00, 0x01, 0x02
};
std::vector<uint8_t> hash_input2 {
0x01, 0x02
};

/* Default behavior: input bytes converted into field elements and padded
* with lowest bit in the next higher block:
* 0x0000000000000000000000000000000000000000000000000000000001000102
* and
* 0x0000000000000000000000000000000000000000000000000000000000010102
*/
typename policy::digest_type result1 = nil::crypto3::hash<hash_type>(
vo-nil marked this conversation as resolved.
Show resolved Hide resolved
nil::crypto3::hashes::conditional_block_to_field_elements_wrapper<
typename hash_type::word_type,
decltype(hash_input1)>
(hash_input1)
);

typename policy::digest_type result2 = nil::crypto3::hash<hash_type>(
nil::crypto3::hashes::conditional_block_to_field_elements_wrapper<
typename hash_type::word_type,
decltype(hash_input2)>
(hash_input2)
);

/* Results should not be equal */
BOOST_CHECK_NE(result1, result2);
}

BOOST_AUTO_TEST_CASE(poseidon_without_padding_test) {
using field_type = fields::pallas_scalar_field;
using policy = pasta_poseidon_policy<field_type>;
using hash_type = hashes::poseidon<policy>;

std::vector<uint8_t> hash_input1 {
0x00, 0x01, 0x02
};
std::vector<uint8_t> hash_input2 {
0x01, 0x02
};

/* Explicit non-padding behavior: input bytes converted into field elements
* without padding, both inputs produce same element:
* 0x0000000000000000000000000000000000000000000000000000000000000102
*/
typename policy::digest_type result1 = nil::crypto3::hash<hash_type>(
nil::crypto3::hashes::conditional_block_to_field_elements_wrapper<
typename hash_type::word_type,
decltype(hash_input1), true, false /* padding */>
(hash_input1)
);

typename policy::digest_type result2 = nil::crypto3::hash<hash_type>(
nil::crypto3::hashes::conditional_block_to_field_elements_wrapper<
typename hash_type::word_type,
decltype(hash_input2), true, false /* padding */>
(hash_input2)
);

/* Results should be equal */
BOOST_CHECK_EQUAL(result1, result2);
}


// Test data for Mina version was taken from https://github.com/o1-labs/proof-systems/blob/a36c088b3e81d17f5720abfff82a49cf9cb1ad5b/poseidon/src/tests/test_vectors/kimchi.json.
// For some reason bytes in their test data are in Big Endian, while we need in Small Endian, I.E. you need to reverse the order of bytes to create our test data.
Expand Down Expand Up @@ -269,13 +342,13 @@ BOOST_AUTO_TEST_SUITE(poseidon_tests)
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD,
0xEF, // 256 bits up to this place, the last value should be moved to
// the next field element.
// the next field element and padded with one bit in the next byte.

};

std::vector<typename field_type::value_type> field_input = {
0x000123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCD_big_uint255,
0x00000000000000000000000000000000000000000000000000000000000000EF_big_uint255,
0x00000000000000000000000000000000000000000000000000000000000001EF_big_uint255,
};

typename policy::digest_type d_uint8 = hash<hash_t>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,6 @@ namespace nil {
return result;
}

// TODO: columns_with_copy_constraints -- It should be extracted from constraint_system
static inline preprocessed_data_type process(
const plonk_constraint_system<FieldType> &constraint_system,
std::shared_ptr<public_assignment_type> public_assignment,
Expand Down
7 changes: 3 additions & 4 deletions crypto3/libs/zk/test/transcript/transcript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
#include <nil/crypto3/marshalling/algebra/processing/mnt4.hpp>
#include <nil/crypto3/marshalling/algebra/processing/mnt6.hpp>


using namespace nil::crypto3;
using namespace nil::crypto3::zk;

Expand Down Expand Up @@ -90,9 +89,9 @@ BOOST_AUTO_TEST_CASE(zk_poseidon_transcript_init_test) {
auto ch2 = tr.challenge<field_type>();
int ch_int = tr.int_challenge<int>();

BOOST_CHECK_EQUAL(ch1.data, field_type::value_type(0x27B1BE8A820DE1A5E91A441F59F29D42D9DB9FC7778A0852819F331D5CD60B43_big_uint255).data);
BOOST_CHECK_EQUAL(ch2.data, field_type::value_type(0x12096E03B2ADEC9B317042D36F048C06AF123EED4A3FC040579E66DCE46C0AEE_big_uint255).data);
BOOST_CHECK_EQUAL(ch_int, 0x6296);
BOOST_CHECK_EQUAL(ch1.data, field_type::value_type(0x2c8488fd580563511086c59020975e49afd065fd26c451f6c1f9c5213798c928_big_uint255).data);
BOOST_CHECK_EQUAL(ch2.data, field_type::value_type(0x285f5407fb2f26a10fdcdc9357ecdc2b1415dc67b082f7c18964022bcb644ca7_big_uint255).data);
BOOST_CHECK_EQUAL(ch_int, 0x48f3);

init_blob = {};
tr = transcript::fiat_shamir_heuristic_sequential<poseidon_type>(init_blob);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ macro(define_containers_example example)

add_executable(${target_name} ${example}.cpp)
target_link_libraries(${target_name} PRIVATE
${CMAKE_WORKSPACE_NAME}::algebra
${CMAKE_WORKSPACE_NAME}::hash)
crypto3::algebra
crypto3::hash)

set_target_properties(${target_name} PROPERTIES CXX_STANDARD 20)
endmacro()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@

#include <nil/crypto3/zk/transcript/fiat_shamir.hpp>

#include <nil/crypto3/marshalling/algebra/processing/bls12.hpp>
#include <nil/crypto3/marshalling/algebra/processing/mnt4.hpp>
#include <nil/crypto3/marshalling/algebra/processing/mnt6.hpp>
#include <nil/crypto3/marshalling/algebra/processing/bls12.hpp>

using namespace nil::crypto3;
using namespace nil::crypto3::zk;
Expand Down Expand Up @@ -89,9 +89,9 @@ BOOST_AUTO_TEST_CASE(zk_poseidon_transcript_init_test) {
auto ch2 = tr.challenge<field_type>();
int ch_int = tr.int_challenge<int>();

BOOST_CHECK_EQUAL(ch1.data, field_type::value_type(0x27B1BE8A820DE1A5E91A441F59F29D42D9DB9FC7778A0852819F331D5CD60B43_big_uint255).data);
BOOST_CHECK_EQUAL(ch2.data, field_type::value_type(0x12096E03B2ADEC9B317042D36F048C06AF123EED4A3FC040579E66DCE46C0AEE_big_uint255).data);
BOOST_CHECK_EQUAL(ch_int, 0x6296);
BOOST_CHECK_EQUAL(ch1.data, field_type::value_type(0x2c8488fd580563511086c59020975e49afd065fd26c451f6c1f9c5213798c928_big_uint255).data);
BOOST_CHECK_EQUAL(ch2.data, field_type::value_type(0x285f5407fb2f26a10fdcdc9357ecdc2b1415dc67b082f7c18964022bcb644ca7_big_uint255).data);
BOOST_CHECK_EQUAL(ch_int, 0x48f3);

init_blob = {};
tr = transcript::fiat_shamir_heuristic_sequential<poseidon_type>(init_blob);
Expand Down