Skip to content
This repository was archived by the owner on Feb 17, 2025. It is now read-only.

Commit 45074e0

Browse files
committed
Reworked proof of work #288
Default parameter for grinding is bits, not mask #288 Replaced masks with bits #288 Simplified multiexp test to make CI runs faster #288 merge-in-progress wip Added missing includes for boost::hash_combine #288 Moved multiexp to benchmarks #288 Renamed int_be to to_bytes_array #288
1 parent 9980a34 commit 45074e0

File tree

18 files changed

+81
-48
lines changed

18 files changed

+81
-48
lines changed

libs/algebra/include/nil/crypto3/algebra/fields/detail/element/fp2.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#define CRYPTO3_ALGEBRA_FIELDS_ELEMENT_FP2_HPP
2828

2929
#include <type_traits>
30+
#include <boost/functional/hash.hpp>
3031

3132
#include <nil/crypto3/algebra/fields/detail/exponentiation.hpp>
3233
#include <nil/crypto3/algebra/fields/detail/element/operations.hpp>

libs/algebra/test/CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ set(RUNTIME_TESTS_NAMES
5656
"fields"
5757
"fields_static"
5858
"pairing"
59-
"multiexp"
6059
)
6160

6261
set(COMPILE_TIME_TESTS_NAMES

libs/algebra/test/bench_test/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ endmacro()
3737
set(RUNTIME_TESTS_NAMES
3838
"bench_curves"
3939
"bench_fields"
40+
"bench_multiexp"
4041
)
4142

4243
foreach(TEST_NAME ${RUNTIME_TESTS_NAMES})
File renamed without changes.

libs/math/include/nil/crypto3/math/polynomial/polynomial_dfs.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
#include <iterator>
3636
#include <unordered_map>
3737

38+
#include <boost/functional/hash.hpp>
39+
3840
#include <nil/crypto3/math/algorithms/make_evaluation_domain.hpp>
3941
#include <nil/crypto3/math/domains/evaluation_domain.hpp>
4042
#include <nil/crypto3/math/polynomial/basic_operations.hpp>

libs/multiprecision/include/nil/crypto3/multiprecision/cpp_int_modular/misc.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <boost/multiprecision/detail/constexpr.hpp>
1414
#include <boost/multiprecision/detail/bitscan.hpp> // lsb etc
1515
#include <boost/functional/hash_fwd.hpp>
16+
#include <boost/functional/hash.hpp>
1617

1718
#ifdef BOOST_MSVC
1819
#pragma warning(push)

libs/zk/include/nil/crypto3/zk/commitments/batched_commitment.hpp

+27-6
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,25 @@ namespace nil {
7272
std::map<std::size_t, bool> _locked; // _locked[batch] is true after it is commited
7373
std::map<std::size_t, std::vector<std::vector<typename field_type::value_type>>> _points;
7474

75+
// We frequently search over the this->_points structure, and it's better to keep a hashmap that maps point to
76+
// it's index in vector for faster search. We need to duplicate this data for now, because the order of points matters.
77+
std::map<std::size_t, std::vector<std::unordered_map<typename field_type::value_type, std::size_t>>> _points_map;
78+
79+
// Creates '_points_map'. We need to think about re-designing this class later. Currently this is used from LPC.
80+
void build_points_map() {
81+
for (const auto& [i, V]: this->_points) {
82+
_points_map[i].resize(V.size());
83+
for (std::size_t j = 0; j < V.size(); ++j) {
84+
const auto& batch = V[j];
85+
for (std::size_t k = 0; k < batch.size(); ++k) {
86+
// We need to store the index of the first occurance of each point.
87+
if (_points_map[i][j].find(batch[k]) == _points_map[i][j].end())
88+
_points_map[i][j][batch[k]] = k;
89+
}
90+
}
91+
}
92+
}
93+
7594
protected:
7695
math::polynomial<typename field_type::value_type> get_V(
7796
const std::vector<typename field_type::value_type> &points) const {
@@ -108,16 +127,18 @@ namespace nil {
108127
}
109128

110129
// We call them singles in recursive verifier
130+
// We keep the order of points, not sure if that was required.
111131
std::vector<typename field_type::value_type> get_unique_points() const {
132+
112133
std::vector<typename field_type::value_type> result;
113-
// std::unordered_set<typename field_type::value_type> result_set;
134+
std::unordered_set<typename field_type::value_type> result_set;
114135

115-
for( auto const &[k, point_batch]:_points ){
136+
for( auto const &[k, point_batch]: _points ){
116137
for( auto const &point_set: point_batch ){
117-
for( auto const &point:point_set ){
118-
if( std::find(result.begin(), result.end(), point) == result.end() ){
138+
for( auto const &point: point_set ){
139+
if (result_set.find(point) == result_set.end()) {
119140
result.push_back(point);
120-
// result_set.insert(point);
141+
result_set.insert(point);
121142
}
122143
}
123144
}
@@ -180,7 +201,7 @@ namespace nil {
180201

181202
BOOST_ASSERT(poly.size() == point.size() || point.size() == 1);
182203

183-
for (std::size_t i = 0; i < poly.size(); i++) {
204+
for (std::size_t i = 0; i < poly.size(); ++i) {
184205
_z.set_poly_points_number(k, i, point[i].size());
185206
for (std::size_t j = 0; j < point[i].size(); j++) {
186207
_z.set(k, i, j, poly[i].evaluate(point[i][j]));

libs/zk/include/nil/crypto3/zk/commitments/detail/polynomial/basic_fri.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ namespace nil {
154154
std::size_t lambda,
155155
std::size_t expand_factor,
156156
bool use_grinding = false,
157-
std::size_t grinding_parameter = 0xFFFF
157+
std::size_t grinding_parameter = 16
158158
): lambda(lambda)
159159
, use_grinding(use_grinding)
160160
, grinding_parameter(grinding_parameter)
@@ -171,7 +171,7 @@ namespace nil {
171171
std::size_t lambda,
172172
std::size_t expand_factor,
173173
bool use_grinding = false,
174-
std::size_t grinding_parameter = 0xFFFF
174+
std::size_t grinding_parameter = 16
175175
): lambda(lambda)
176176
, use_grinding(use_grinding)
177177
, grinding_parameter(grinding_parameter)
@@ -189,7 +189,7 @@ namespace nil {
189189
std::size_t expand_factor,
190190
std::size_t lambda,
191191
bool use_grinding = false,
192-
std::size_t grinding_parameter = 0xFFFF
192+
std::size_t grinding_parameter = 16
193193
) : lambda(lambda)
194194
, use_grinding(use_grinding)
195195
, grinding_parameter(grinding_parameter)

libs/zk/include/nil/crypto3/zk/commitments/detail/polynomial/proof_of_work.hpp

+22-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//---------------------------------------------------------------------------//
22
// Copyright (c) 2023 Elena Tatuzova <[email protected]>
3+
// Copyright (c) 2024 Vasiliy Olekhov <[email protected]>
34
//
45
// MIT License
56
//
@@ -44,37 +45,40 @@ namespace nil {
4445
using transcript_type = transcript::fiat_shamir_heuristic_sequential<transcript_hash_type>;
4546
using output_type = OutType;
4647

47-
static inline OutType generate(transcript_type &transcript, OutType mask=0xFFFF) {
48+
static inline std::array<std::uint8_t, sizeof(OutType)>
49+
to_byte_array(OutType v) {
50+
std::array<std::uint8_t, sizeof(OutType)> bytes;
51+
for(int i = sizeof(v)-1; i>=0; --i) {
52+
bytes[i] = v & 0xFF;
53+
v >>= 8;
54+
}
55+
return bytes;
56+
}
57+
58+
static inline OutType generate(transcript_type &transcript, std::size_t GrindingBits = 16) {
59+
BOOST_ASSERT_MSG(GrindingBits < 64, "Grinding parameter should be bits, not mask");
60+
output_type mask = GrindingBits > 0 ? ( 1ULL << GrindingBits ) - 1 : 0;
4861
output_type proof_of_work = std::rand();
4962
output_type result;
50-
std::vector<std::uint8_t> bytes(4);
5163

5264
while( true ) {
5365
transcript_type tmp_transcript = transcript;
54-
bytes[0] = std::uint8_t((proof_of_work&0xFF000000)>>24);
55-
bytes[1] = std::uint8_t((proof_of_work&0x00FF0000)>>16);
56-
bytes[2] = std::uint8_t((proof_of_work&0x0000FF00)>>8);
57-
bytes[3] = std::uint8_t(proof_of_work&0x000000FF);
58-
59-
tmp_transcript(bytes);
66+
tmp_transcript(to_byte_array(proof_of_work));
6067
result = tmp_transcript.template int_challenge<output_type>();
6168
if ((result & mask) == 0)
6269
break;
6370
proof_of_work++;
6471
}
65-
transcript(bytes);
72+
transcript(to_byte_array(proof_of_work));
6673
result = transcript.template int_challenge<output_type>();
6774
return proof_of_work;
6875
}
6976

70-
static inline bool verify(transcript_type &transcript, output_type proof_of_work, OutType mask=0xFFFF) {
71-
std::vector<std::uint8_t> bytes(4);
72-
bytes[0] = std::uint8_t((proof_of_work&0xFF000000)>>24);
73-
bytes[1] = std::uint8_t((proof_of_work&0x00FF0000)>>16);
74-
bytes[2] = std::uint8_t((proof_of_work&0x0000FF00)>>8);
75-
bytes[3] = std::uint8_t(proof_of_work&0x000000FF);
76-
transcript(bytes);
77+
static inline bool verify(transcript_type &transcript, output_type proof_of_work, std::size_t GrindingBits = 16) {
78+
BOOST_ASSERT_MSG(GrindingBits < 64, "Grinding parameter should be bits, not mask");
79+
transcript(to_byte_array(proof_of_work));
7780
output_type result = transcript.template int_challenge<output_type>();
81+
output_type mask = GrindingBits > 0 ? ( 1ULL << GrindingBits ) - 1 : 0;
7882
return ((result & mask) == 0);
7983
}
8084
};
@@ -91,7 +95,7 @@ namespace nil {
9195
using value_type = typename FieldType::value_type;
9296
using integral_type = typename FieldType::integral_type;
9397

94-
static inline value_type generate(transcript_type &transcript, std::size_t GrindingBits=16) {
98+
static inline value_type generate(transcript_type &transcript, std::size_t GrindingBits = 16) {
9599
static boost::random::random_device dev;
96100
static nil::crypto3::random::algebraic_engine<FieldType> random_engine(dev);
97101
value_type proof_of_work = random_engine();
@@ -115,7 +119,7 @@ namespace nil {
115119
return proof_of_work;
116120
}
117121

118-
static inline bool verify(transcript_type &transcript, value_type proof_of_work, std::size_t GrindingBits=16) {
122+
static inline bool verify(transcript_type &transcript, value_type proof_of_work, std::size_t GrindingBits = 16) {
119123
transcript(proof_of_work);
120124
integral_type mask =
121125
(GrindingBits > 0 ?

libs/zk/include/nil/crypto3/zk/commitments/polynomial/kzg.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,7 @@ namespace nil {
703703
typename CommitmentSchemeType::transcript_type &transcript) {
704704
/* The procedure of updating the transcript is subject to review and change
705705
* #295 */
706+
706707
// Push commitments to transcript
707708

708709
transcript(_commitments[batch_ind]);

libs/zk/include/nil/crypto3/zk/commitments/polynomial/kzg_v2.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ namespace nil {
190190
// Differs from static, because we pack the result into byte blob.
191191
commitment_type commit(std::size_t index) {
192192
this->_ind_commitments[index] = {};
193+
this->_ind_commitments[index].resize(this->_polys[index].size());
193194
this->state_commited(index);
194195

195196
std::vector<std::uint8_t> result = {};

libs/zk/include/nil/crypto3/zk/commitments/polynomial/lpc.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ namespace nil {
177177
if constexpr (std::is_same<math::polynomial_dfs<value_type>, PolynomialType>::value ) {
178178
combined_Q.from_coefficients(combined_Q_normal);
179179
} else {
180-
combined_Q = combined_Q_normal;
180+
combined_Q = std::move(combined_Q_normal);
181181
}
182182

183183
precommitment_type combined_Q_precommitment = nil::crypto3::zk::algorithms::precommit<fri_type>(

libs/zk/include/nil/crypto3/zk/snark/systems/plonk/placeholder/gates_argument.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ namespace nil {
8888
});
8989
std::shared_ptr<math::evaluation_domain<FieldType>> extended_domain =
9090
math::make_evaluation_domain<FieldType>(extended_domain_size);
91+
9192
visitor.visit(expr);
93+
9294
for (const auto& [var, count]: variable_counts) {
9395
// We may have variable values in required sizes in some cases.
9496
if (variable_values_out.find(var) != variable_values_out.end())

libs/zk/include/nil/crypto3/zk/snark/systems/plonk/placeholder/lookup_argument.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ namespace nil {
546546
}
547547

548548
// Each lookup table should fill full rectangle inside assignment table
549-
// Lookup tables may contain repeated values, but they shoul be placed into one
549+
// Lookup tables may contain repeated values, but they should be placed into one
550550
// option one under another.
551551
// Because of theta randomness compressed lookup tables' vectors for different table may contain
552552
// similar values only with negligible probability.

libs/zk/test/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ set(TESTS_NAMES
5656
# "commitment/r1cs_gg_ppzksnark_mpc"
5757
# "commitment/type_traits"
5858
# "commitment/kimchi_pedersen"
59-
# "commitment/proof_of_work"
59+
"commitment/proof_of_work"
6060

6161
"math/expression"
6262

libs/zk/test/commitment/fri.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ BOOST_AUTO_TEST_SUITE(fri_test_suite)
116116
2, //expand_factor
117117
lambda,
118118
true,
119-
0xFFFFF
119+
20
120120
);
121121

122122
BOOST_CHECK(D[1]->m == D[0]->m / 2);

libs/zk/test/commitment/lpc.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ BOOST_AUTO_TEST_SUITE(lpc_math_polynomial_suite);
210210
2, //expand_factor
211211
lambda,
212212
true,
213-
0xFFF
213+
12
214214
);
215215

216216
using lpc_scheme_type = nil::crypto3::zk::commitments::lpc_commitment_scheme<lpc_type, math::polynomial<typename FieldType::value_type>>;
@@ -510,7 +510,7 @@ BOOST_AUTO_TEST_SUITE(lpc_params_test_suite)
510510
2, //expand_factor
511511
lambda,
512512
true,
513-
0xFF
513+
8
514514
);
515515

516516
using lpc_scheme_type = nil::crypto3::zk::commitments::lpc_commitment_scheme<lpc_type, math::polynomial<typename FieldType::value_type>>;

libs/zk/test/commitment/proof_of_work.cpp

+14-14
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,18 @@ BOOST_AUTO_TEST_SUITE(proof_of_knowledge_test_suite)
5151
using poseidon = nil::crypto3::hashes::poseidon<policy>;
5252
using pow_type = nil::crypto3::zk::commitments::field_proof_of_work<poseidon, field_type>;
5353

54-
const integral_type expected_mask = integral_type(0xFF80000000000000) << (field_type::modulus_bits - 64);
54+
std::size_t grinding_bits = 9;
5555
nil::crypto3::zk::transcript::fiat_shamir_heuristic_sequential<poseidon> transcript;
5656
auto old_transcript_1 = transcript, old_transcript_2 = transcript;
5757

58-
auto result = pow_type::generate(transcript, 9);
59-
BOOST_ASSERT(pow_type::verify(old_transcript_1, result, 9));
58+
auto result = pow_type::generate(transcript, grinding_bits);
59+
BOOST_ASSERT(pow_type::verify(old_transcript_1, result, grinding_bits));
6060

6161
// manually reimplement verify to ensure that changes in implementation didn't break it
6262
old_transcript_2(result);
6363
auto chal = old_transcript_2.template challenge<field_type>();
64+
const integral_type expected_mask = integral_type( (1 << grinding_bits) - 1 ) << (field_type::modulus_bits - grinding_bits);
65+
6466
BOOST_ASSERT((integral_type(chal.data) & expected_mask) == 0);
6567

6668
using hard_pow_type = nil::crypto3::zk::commitments::field_proof_of_work<poseidon, field_type>;
@@ -70,28 +72,26 @@ BOOST_AUTO_TEST_SUITE(proof_of_knowledge_test_suite)
7072

7173
BOOST_AUTO_TEST_CASE(pow_basic_test) {
7274
using keccak = nil::crypto3::hashes::keccak_1600<512>;
73-
const std::uint32_t mask = 0xFFFFF000;
75+
76+
const std::uint32_t grinding_bits = 20;
77+
const uint64_t expected_mask = (1ULL << grinding_bits) - 1;
78+
7479
using pow_type = nil::crypto3::zk::commitments::proof_of_work<keccak, std::uint32_t>;
7580

7681
nil::crypto3::zk::transcript::fiat_shamir_heuristic_sequential<keccak> transcript;
7782
auto old_transcript_1 = transcript, old_transcript_2 = transcript;
7883

79-
auto result = pow_type::generate(transcript, mask);
80-
BOOST_ASSERT(pow_type::verify(old_transcript_1, result, mask));
84+
auto result = pow_type::generate(transcript, grinding_bits);
85+
BOOST_ASSERT(pow_type::verify(old_transcript_1, result, grinding_bits));
8186

8287
// manually reimplement verify to ensure that changes in implementation didn't break it
83-
std::array<std::uint8_t, 4> bytes;
84-
bytes[0] = std::uint8_t((result & 0xFF000000) >> 24);
85-
bytes[1] = std::uint8_t((result & 0x00FF0000) >> 16);
86-
bytes[2] = std::uint8_t((result & 0x0000FF00) >> 8);
87-
bytes[3] = std::uint8_t(result & 0x000000FF);
88-
old_transcript_2(bytes);
88+
old_transcript_2(pow_type::to_byte_array(result));
8989
auto chal = old_transcript_2.template int_challenge<std::uint32_t>();
90-
BOOST_ASSERT((chal & mask) == 0);
90+
BOOST_ASSERT( (chal & expected_mask) == 0);
9191

9292
// check that random stuff doesn't pass verify
9393
using hard_pow_type = nil::crypto3::zk::commitments::proof_of_work<keccak, std::uint32_t>;
94-
BOOST_ASSERT(!hard_pow_type::verify(old_transcript_1, result, mask));
94+
BOOST_ASSERT(!hard_pow_type::verify(old_transcript_1, result, grinding_bits));
9595
}
9696

9797
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)