From ac7d631e4befd082775ee2f286a07830f40c253d Mon Sep 17 00:00:00 2001 From: Vasiliy Olekhov Date: Tue, 16 Jul 2024 16:06:05 +0300 Subject: [PATCH] Reworked proof of work #288 --- .../detail/polynomial/proof_of_work.hpp | 34 ++++++++++--------- libs/zk/test/CMakeLists.txt | 2 +- libs/zk/test/commitment/proof_of_work.cpp | 28 +++++++-------- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/libs/zk/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp b/libs/zk/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp index 28be4b534..4a0fcee8d 100644 --- a/libs/zk/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp +++ b/libs/zk/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp @@ -1,5 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2023 Elena Tatuzova +// Copyright (c) 2024 Vasiliy Olekhov // // MIT License // @@ -44,37 +45,38 @@ namespace nil { using transcript_type = transcript::fiat_shamir_heuristic_sequential; using output_type = OutType; - static inline OutType generate(transcript_type &transcript, OutType mask=0xFFFF) { + static inline std::array + int_be(OutType v) { + std::array bytes; + for(int i = sizeof(v)-1; i>=0; --i) { + bytes[i] = v & 0xFF; + v >>= 8; + } + return bytes; + } + + static inline OutType generate(transcript_type &transcript, std::size_t GrindingBits = 16) { + output_type mask = GrindingBits > 0 ? ( 1ULL << GrindingBits ) - 1 : 0; output_type proof_of_work = std::rand(); output_type result; - std::vector bytes(4); while( true ) { transcript_type tmp_transcript = transcript; - bytes[0] = std::uint8_t((proof_of_work&0xFF000000)>>24); - bytes[1] = std::uint8_t((proof_of_work&0x00FF0000)>>16); - bytes[2] = std::uint8_t((proof_of_work&0x0000FF00)>>8); - bytes[3] = std::uint8_t(proof_of_work&0x000000FF); - - tmp_transcript(bytes); + tmp_transcript(int_be(proof_of_work)); result = tmp_transcript.template int_challenge(); if ((result & mask) == 0) break; proof_of_work++; } - transcript(bytes); + transcript(int_be(proof_of_work)); result = transcript.template int_challenge(); return proof_of_work; } - static inline bool verify(transcript_type &transcript, output_type proof_of_work, OutType mask=0xFFFF) { - std::vector bytes(4); - bytes[0] = std::uint8_t((proof_of_work&0xFF000000)>>24); - bytes[1] = std::uint8_t((proof_of_work&0x00FF0000)>>16); - bytes[2] = std::uint8_t((proof_of_work&0x0000FF00)>>8); - bytes[3] = std::uint8_t(proof_of_work&0x000000FF); - transcript(bytes); + static inline bool verify(transcript_type &transcript, output_type proof_of_work, std::size_t GrindingBits = 16) { + transcript(int_be(proof_of_work)); output_type result = transcript.template int_challenge(); + output_type mask = GrindingBits > 0 ? ( 1ULL << GrindingBits ) - 1 : 0; return ((result & mask) == 0); } }; diff --git a/libs/zk/test/CMakeLists.txt b/libs/zk/test/CMakeLists.txt index 9e1ea9096..c58e1849d 100644 --- a/libs/zk/test/CMakeLists.txt +++ b/libs/zk/test/CMakeLists.txt @@ -56,7 +56,7 @@ set(TESTS_NAMES # "commitment/r1cs_gg_ppzksnark_mpc" # "commitment/type_traits" # "commitment/kimchi_pedersen" -# "commitment/proof_of_work" + "commitment/proof_of_work" "math/expression" diff --git a/libs/zk/test/commitment/proof_of_work.cpp b/libs/zk/test/commitment/proof_of_work.cpp index ae7f51fcd..b153b0bdc 100644 --- a/libs/zk/test/commitment/proof_of_work.cpp +++ b/libs/zk/test/commitment/proof_of_work.cpp @@ -51,16 +51,18 @@ BOOST_AUTO_TEST_SUITE(proof_of_knowledge_test_suite) using poseidon = nil::crypto3::hashes::poseidon; using pow_type = nil::crypto3::zk::commitments::field_proof_of_work; - const integral_type expected_mask = integral_type(0xFF80000000000000) << (field_type::modulus_bits - 64); + std::size_t grinding_bits = 9; nil::crypto3::zk::transcript::fiat_shamir_heuristic_sequential transcript; auto old_transcript_1 = transcript, old_transcript_2 = transcript; - auto result = pow_type::generate(transcript, 9); - BOOST_ASSERT(pow_type::verify(old_transcript_1, result, 9)); + auto result = pow_type::generate(transcript, grinding_bits); + BOOST_ASSERT(pow_type::verify(old_transcript_1, result, grinding_bits)); // manually reimplement verify to ensure that changes in implementation didn't break it old_transcript_2(result); auto chal = old_transcript_2.template challenge(); + const integral_type expected_mask = integral_type( (1 << grinding_bits) - 1 ) << (field_type::modulus_bits - grinding_bits); + BOOST_ASSERT((integral_type(chal.data) & expected_mask) == 0); using hard_pow_type = nil::crypto3::zk::commitments::field_proof_of_work; @@ -70,28 +72,26 @@ BOOST_AUTO_TEST_SUITE(proof_of_knowledge_test_suite) BOOST_AUTO_TEST_CASE(pow_basic_test) { using keccak = nil::crypto3::hashes::keccak_1600<512>; - const std::uint32_t mask = 0xFFFFF000; + + const std::uint32_t grinding_bits = 20; + const uint64_t expected_mask = (1 << grinding_bits) - 1; + using pow_type = nil::crypto3::zk::commitments::proof_of_work; nil::crypto3::zk::transcript::fiat_shamir_heuristic_sequential transcript; auto old_transcript_1 = transcript, old_transcript_2 = transcript; - auto result = pow_type::generate(transcript, mask); - BOOST_ASSERT(pow_type::verify(old_transcript_1, result, mask)); + auto result = pow_type::generate(transcript, grinding_bits); + BOOST_ASSERT(pow_type::verify(old_transcript_1, result, grinding_bits)); // manually reimplement verify to ensure that changes in implementation didn't break it - std::array bytes; - bytes[0] = std::uint8_t((result & 0xFF000000) >> 24); - bytes[1] = std::uint8_t((result & 0x00FF0000) >> 16); - bytes[2] = std::uint8_t((result & 0x0000FF00) >> 8); - bytes[3] = std::uint8_t(result & 0x000000FF); - old_transcript_2(bytes); + old_transcript_2(pow_type::int_be(result)); auto chal = old_transcript_2.template int_challenge(); - BOOST_ASSERT((chal & mask) == 0); + BOOST_ASSERT( (chal & expected_mask) == 0); // check that random stuff doesn't pass verify using hard_pow_type = nil::crypto3::zk::commitments::proof_of_work; - BOOST_ASSERT(!hard_pow_type::verify(old_transcript_1, result, mask)); + BOOST_ASSERT(!hard_pow_type::verify(old_transcript_1, result, grinding_bits)); } BOOST_AUTO_TEST_SUITE_END()