From 015511b93d76e84f1d9ddd1101c0703a3980a8d9 Mon Sep 17 00:00:00 2001 From: Valeh Date: Mon, 27 Jan 2025 16:04:22 +0200 Subject: [PATCH 01/14] pass constraint names to circuit builder --- .../nil/blueprint/bbf/circuit_builder.hpp | 13 ++++- .../nil/blueprint/bbf/gate_optimizer.hpp | 30 +++++++--- .../include/nil/blueprint/bbf/generic.hpp | 57 +++++++++++++------ 3 files changed, 71 insertions(+), 29 deletions(-) diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/circuit_builder.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/circuit_builder.hpp index f1654237f..db9c0aff3 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/circuit_builder.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/circuit_builder.hpp @@ -186,7 +186,7 @@ namespace nil { selector_column.set_row(i); size_t full_selector_id = gates.add_selector(selector_column); - for(const auto& [selector_id, constraints] : gates.constraint_list) { + for(const auto& [selector_id, data] : gates.constraint_list) { /* std::cout << "GATE:\n"; for(const auto& c : constraints) { @@ -194,8 +194,15 @@ namespace nil { } std::cout << "Rows: "; */ - bp.add_gate(selector_id, constraints); + std::vector constraints; + std::vector names; + for(const auto &d : data){ + constraints.push_back(std::move(d.first)); + names.push_back(d.second); + } + bp.add_gate(selector_id, constraints); + constraint_names.insert({selector_id, names}); //std::cout << "\n"; } @@ -540,6 +547,7 @@ namespace nil { std::cout << "Constraint " << j << " from gate " << i << " on row " << selector_row << " is not satisfied." << std::endl; std::cout << "Constraint result: " << constraint_result << std::endl; + std::cout << "Offending constraint name: " << constraint_names.at(gates[i].selector_index).at(j) << std::endl; std::cout << "Offending contraint: " << gates[i].constraints[j] << std::endl; return false; } @@ -668,6 +676,7 @@ namespace nil { circuit> bp; crypto3::zk::snark::plonk_assignment_table presets; + std::map> constraint_names; }; } // namespace bbf diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/gate_optimizer.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/gate_optimizer.hpp index be50419a0..accf547d9 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/gate_optimizer.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/gate_optimizer.hpp @@ -54,7 +54,7 @@ namespace nil { using lookup_constraint_type = std::pair; // Here size_t is the index of the selector from 'selectors_'. - std::unordered_map> constraint_list; + std::unordered_map>> constraint_list; std::vector copy_constraints; std::map, size_t>> dynamic_lookup_tables; @@ -79,7 +79,7 @@ namespace nil { return iter->second; } - void add_constraints(size_t selector_id, const std::vector& constraints) { + void add_constraints(size_t selector_id, const std::vector>& constraints) { auto iter = constraint_list.find(selector_id); if (iter != constraint_list.end()) { iter->second.insert( @@ -115,7 +115,7 @@ namespace nil { os << "Constraints: " << std::endl; if (iter != gates.constraint_list.end()) { for (const auto &constraint : iter->second) { - os << constraint << std::endl; + os << constraint.second << "( " << constraint.first << " )" << std::endl; } os << "--------------------------------------------------------------" << std::endl; } @@ -155,8 +155,20 @@ namespace nil { : context_(std::make_unique(std::move(c))) { } + std::optional>> shift_constraints( + const std::vector> constraints, int shift) { + std::vector> shifted_constraints; + for (const auto& c: constraints) { + std::optional shifted = c.first.rotate(shift); + if (!shifted) + return std::nullopt; + shifted_constraints.push_back({*shifted, c.second}); + } + return shifted_constraints; + } + std::optional> shift_constraints( - const std::vector& constraints, int shift) { + const std::vector constraints, int shift) { std::vector shifted_constraints; for (const auto& c: constraints) { std::optional shifted = c.rotate(shift); @@ -188,7 +200,7 @@ namespace nil { optimized_gates result; // Take everything out of context, and erase the context to free its memory. - std::unordered_map, std::vector> constraint_list = context_->get_constraints(); + std::unordered_map, std::vector>> constraint_list = context_->get_constraints(); std::map, row_selector<>>> dynamic_lookup_tables = context_->get_dynamic_lookup_tables(); result.copy_constraints = context_->get_copy_constraints(); @@ -526,11 +538,11 @@ namespace nil { // Move all from constraints_list. auto iter = gates.constraint_list.find(id); if (iter != gates.constraint_list.end()) { - std::vector constraints = std::move(iter->second); + std::vector> constraints = std::move(iter->second); gates.constraint_list.erase(id); // We need the minus on the next line, we need to shift the constraints in the // opposite direction of the selector shift. - std::optional> shifted_constraints = + std::optional>> shifted_constraints = shift_constraints(std::move(constraints), -shift); //std::cout << "Shifting " << -shift << " :" << std::endl; @@ -721,8 +733,8 @@ namespace nil { // Check if there is a constraint that can't be shifted. auto iter = gates.constraint_list.find(selector_id); if (iter != gates.constraint_list.end()) { - const std::vector& constraints = iter->second; - std::optional> shifted_constraints = + const std::vector>& constraints = iter->second; + std::optional>> shifted_constraints = shift_constraints(constraints, shift); if (!shifted_constraints) { return false; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp index 2a4c3ec20..a196d057d 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp @@ -285,7 +285,8 @@ namespace nil { using var = crypto3::zk::snark::plonk_variable; using constraint_type = crypto3::zk::snark::plonk_constraint; using plonk_copy_constraint = crypto3::zk::snark::plonk_copy_constraint; - using constraints_container_type = std::map>>; + using constraints_container_type = std::map, std::string>>; + using constraint_names_container_type = std::unordered_map; using copy_constraints_container_type = std::vector; // TODO: maybe it's a set, not a vec? using lookup_input_constraints_type = crypto3::zk::snark::lookup_input_constraints; using lookup_constraints_container_type = std::map, // @@ -347,7 +348,7 @@ namespace nil { false, // false = use absolute cell address static_cast(t)); if ((C != TYPE()) && (t == column_type::witness)) { // TODO: TYPE() - is this ok? NB: we only constrain witnesses! - constrain(res - C,""); // TODO: maybe add a name for this constraint? + constrain(res - C,"T"); // TODO: maybe add a name for this constraint? } C = res; @@ -405,30 +406,33 @@ namespace nil { } std::size_t row = (min_row + max_row)/2; + + std::optional C_rel = C.rotate(-row); if (!C_rel) { throw std::logic_error("Can't shift the constraint in the given direction."); } - add_constraint(*C_rel, row); + + add_constraint(*C_rel, row, constraint_name); } // accesible only at GenerationStage::CONSTRAINTS ! - void relative_constrain(TYPE C_rel, std::size_t row) { + void relative_constrain(TYPE C_rel, std::size_t row, std::string constraint_name) { if (!C_rel.is_relative()) { std::stringstream ss; ss << "Constraint " << C_rel << " has absolute variables, cannot constrain."; throw std::logic_error(ss.str()); } - add_constraint(C_rel, get_row(row)); + add_constraint(C_rel, get_row(row), constraint_name); } - void relative_constrain(TYPE C_rel, std::size_t start_row, std::size_t end_row) { + void relative_constrain(TYPE C_rel, std::size_t start_row, std::size_t end_row, std::string constraint_name) { if (!C_rel.is_relative()) { std::stringstream ss; ss << "Constraint " << C_rel << " has absolute variables, cannot constrain."; throw std::logic_error(ss.str()); } - add_constraint(C_rel, get_row(start_row), get_row(end_row)); + add_constraint(C_rel, get_row(start_row), get_row(end_row), constraint_name); } @@ -512,18 +516,18 @@ namespace nil { lookup_tables->insert({name,{cols,rows}}); } - std::unordered_map, std::vector> get_constraints() { + std::unordered_map, std::vector>> get_constraints() { // joins constraints with identic selectors into a single gate // drop the constraint_id from the stored id->(constraint,row_list) map and // join constrains into single element if they have the same row list: - std::unordered_map, std::vector> res; + std::unordered_map, std::vector>> res; for(const auto& [id, data] : *constraints) { - auto it = res.find(data.second); + auto it = res.find(std::get<1>(data)); if (it == res.end()) { - res[data.second] = {data.first}; + res[std::get<1>(data)] = {{std::get<0>(data), std::get<2>(data)}}; } else { - it->second.push_back(data.first); + it->second.push_back({std::get<0>(data), std::get<2>(data)}); } } return res; @@ -580,6 +584,7 @@ namespace nil { void reset_storage() { constraints = std::make_shared(); + // constraint_names = std::make_shared(); copy_constraints = std::make_shared(); lookup_constraints = std::make_shared(); lookup_tables = std::make_shared(); @@ -600,23 +605,37 @@ namespace nil { } private: - void add_constraint(TYPE &C_rel, std::size_t row) { + void add_constraint(TYPE &C_rel, std::size_t row, std::string name) { std::size_t stored_row = row - (is_fresh ? row_shift : 0); constraint_id_type C_id = constraint_id_type(C_rel); if (constraints->find(C_id) == constraints->end()) { - constraints->insert({C_id, {C_rel, row_selector<>(desc.rows_amount)}}); + constraints->insert({C_id, {C_rel, row_selector<>(desc.rows_amount), name}}); + } + std::get<1>(constraints->at(C_id)).set_row(stored_row); + + auto old_name = std::get<2>(constraints->at(C_id)); + if(old_name.find(name) == std::string::npos){ + old_name += " or "; + old_name += name; + std::get<2>(constraints->at(C_id)) = old_name; } - constraints->at(C_id).second.set_row(stored_row); } - void add_constraint(TYPE &C_rel, std::size_t start_row, std::size_t end_row) { + void add_constraint(TYPE &C_rel, std::size_t start_row, std::size_t end_row, std::string name) { std::size_t stored_start_row = start_row - (is_fresh ? row_shift : 0); std::size_t stored_end_row = end_row - (is_fresh ? row_shift : 0); constraint_id_type C_id = constraint_id_type(C_rel); if (constraints->find(C_id) == constraints->end()) { - constraints->insert({C_id, {C_rel, row_selector<>(desc.rows_amount)}}); + constraints->insert({C_id, {C_rel, row_selector<>(desc.rows_amount), name}}); + } + std::get<1>(constraints->at(C_id)).set_interval(stored_start_row, stored_end_row); + + auto old_name = std::get<2>(constraints->at(C_id)); + if(old_name.find(name) == std::string::npos){ + old_name += " or "; + old_name += name; + std::get<2>(constraints->at(C_id)) = old_name; } - constraints->at(C_id).second.set_interval(stored_start_row, stored_end_row); } void add_lookup_constraint( @@ -653,6 +672,8 @@ namespace nil { // constraints (with unique id), and the rows they are applied to std::shared_ptr constraints; + // constraint names + // std::shared_ptr constraint_names; // copy constraints as in BP std::shared_ptr copy_constraints; // lookup constraints with table name, unique id and row list From 4fa27b96b0a070ac08f2b1a04bcb88526e38d4cb Mon Sep 17 00:00:00 2001 From: Valeh Date: Tue, 28 Jan 2025 12:59:39 +0200 Subject: [PATCH 02/14] use set instead of string search --- .../hashes/keccak/keccak_dynamic.hpp | 110 +++++++++--------- .../include/nil/blueprint/bbf/generic.hpp | 33 +++--- 2 files changed, 68 insertions(+), 75 deletions(-) diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp index 56257f3e0..45ef055cd 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp @@ -729,35 +729,35 @@ namespace nil { // gates: for (std::size_t i = 0; i < 6247 * max_blocks; i++) { - constrain(selector[i] * (1 - selector[i])); + constrain(selector[i] * (1 - selector[i]), "DYNAMIC_SELECTOR"); } for (std::size_t block_counter = 0; block_counter < max_blocks; block_counter++) { // Is_first and is_last definition constrain(m[block_counter].h.is_first * - (m[block_counter].h.is_first - 1)); // HF1 + (m[block_counter].h.is_first - 1), "HF1"); // HF1 constrain(m[block_counter].h.is_last * - (m[block_counter].h.is_last - 1)); // HF2 + (m[block_counter].h.is_last - 1), "HF2"); // HF2 constrain(m[block_counter].h.is_first * - (m[block_counter].h.L - m[block_counter].h.l)); // HF3 + (m[block_counter].h.L - m[block_counter].h.l), "HF3"); // HF3 lookup(m[block_counter].h.is_last * m[block_counter].h.l, // HF4 "keccak_pack_table/range_check_135"); // Hash computation correctness constrain(m[block_counter].h.is_last * (m[block_counter].h.hash_hi - - m[block_counter].h.hash_cur_hi)); // HF5 + m[block_counter].h.hash_cur_hi), "HF5"); // HF5 constrain(m[block_counter].h.is_last * (m[block_counter].h.hash_lo - - m[block_counter].h.hash_cur_lo)); // HF6 + m[block_counter].h.hash_cur_lo), "HF6"); // HF6 // RLC computation correctness constrain(m[block_counter].h.is_first * (m[block_counter].h.rlc_before - - m[block_counter].h.L)); // HF7 + m[block_counter].h.L), "HF7"); // HF7 constrain(m[block_counter].h.is_last * (m[block_counter].h.rlc_after - - m[block_counter].h.RLC)); // HF8 + m[block_counter].h.RLC), "HF8"); // HF8 // copy constraint r with public input if (make_links) { @@ -779,34 +779,34 @@ namespace nil { copy_constrain(m[block_counter].h.RLC, m[block_counter].f.RLC); copy_constrain(m[block_counter].h.r, m[block_counter].f.r); - constrain((1 - m[0].h.is_first)); // BT1 + constrain((1 - m[0].h.is_first), "BT1"); // BT1 lookup(m[block_counter].h.L, "keccak_pack_table/range_check_16bit"); lookup(m[block_counter].h.l, "keccak_pack_table/range_check_16bit"); if (block_counter > 0) { constrain((1 - m[block_counter - 1].f.is_last) * - m[block_counter].h.is_first); // BT2 + m[block_counter].h.is_first, "BT2"); // BT2 // Transition between blocks constrain((1 - m[block_counter].h.is_first) * (m[block_counter].h.L - - m[block_counter - 1].f.L)); // BT4 + m[block_counter - 1].f.L), "BT4"); // BT4 constrain((1 - m[block_counter].h.is_first) * (m[block_counter].h.RLC - - m[block_counter - 1].f.RLC)); // BT5 + m[block_counter - 1].f.RLC), "BT5"); // BT5 constrain((1 - m[block_counter].h.is_first) * (m[block_counter].h.hash_hi - - m[block_counter - 1].f.hash_hi)); // BT6 + m[block_counter - 1].f.hash_hi), "BT6"); // BT6 constrain((1 - m[block_counter].h.is_first) * (m[block_counter].h.hash_lo - - m[block_counter - 1].f.hash_lo)); // BT7 + m[block_counter - 1].f.hash_lo), "BT7"); // BT7 constrain((1 - m[block_counter].h.is_first) * (m[block_counter].h.rlc_before - - m[block_counter - 1].f.rlc_before)); // BT8 + m[block_counter - 1].f.rlc_before), "BT8"); // BT8 constrain((1 - m[block_counter].h.is_first) * (1 - m[block_counter].h.is_last) * (m[block_counter - 1].f.l - m[block_counter].h.l - - 136)); // BT9 + 136), "BT9"); // BT9 } copy_constrain(m[block_counter].s[3].S1, @@ -835,22 +835,22 @@ namespace nil { for (std::size_t i = 0; i < state_rows_amount; i++) { constrain(m[block_counter].s[i].S0 - (1 - m[block_counter].s[i].is_first) * - m[block_counter].s[i].s0); // ST3 + m[block_counter].s[i].s0, "ST3"); // ST3 constrain(m[block_counter].s[i].S1 - (1 - m[block_counter].s[i].is_first) * - m[block_counter].s[i].s1); // ST4 + m[block_counter].s[i].s1, "ST4"); // ST4 constrain(m[block_counter].s[i].S2 - (1 - m[block_counter].s[i].is_first) * - m[block_counter].s[i].s2); // ST5 + m[block_counter].s[i].s2, "ST5"); // ST5 constrain(m[block_counter].s[i].S3 - (1 - m[block_counter].s[i].is_first) * - m[block_counter].s[i].s3); // ST6 + m[block_counter].s[i].s3, "ST6"); // ST6 constrain(m[block_counter].s[i].S4 - (1 - m[block_counter].s[i].is_first) * - m[block_counter].s[i].s4); // ST7 + m[block_counter].s[i].s4, "ST7"); // ST7 if (i > 0) { constrain(m[block_counter].s[i].is_first - - m[block_counter].s[i - 1].is_first); // ST1 + m[block_counter].s[i - 1].is_first, "ST1"); // ST1 constrain(m[block_counter].s[i].out - m[block_counter].s[i - 1].XOR * (integral_type(1) << (48 * 3)) - @@ -858,7 +858,7 @@ namespace nil { (integral_type(1) << (48 * 2)) - m[block_counter].s[i].XOR * (integral_type(1) << (48)) - - m[block_counter].s[i].ch); // ST9 + m[block_counter].s[i].ch, "ST9"); // ST9 } // lookup constraint s.rng at keccak_pack_table/sparse_16bit lookup(m[block_counter].s[i].rng, @@ -868,19 +868,19 @@ namespace nil { constrain((m[block_counter].s[1].rng - sparse_x80 - m[block_counter].s[0].rng) * (m[block_counter].s[0].rng - sparse_x7f + - m[block_counter].s[1].rng)); // XOR1 + m[block_counter].s[1].rng), "XOR1"); // XOR1 constrain((m[block_counter].s[1].rng - sparse_x7f + m[block_counter].s[0].rng) * (m[block_counter].s[0].XOR + sparse_x80 - - m[block_counter].s[1].rng)); // XOR2 + m[block_counter].s[1].rng), "XOR2"); // XOR2 constrain((m[block_counter].s[1].rng - sparse_x80 - m[block_counter].s[0].rng) * (m[block_counter].s[0].XOR - sparse_x80 - - m[block_counter].s[1].rng)); // XOR3 + m[block_counter].s[1].rng), "XOR3"); // XOR3 constrain((m[block_counter].s[1].XOR - m[block_counter].s[0].ch * m[block_counter].s[0].XOR - (1 - m[block_counter].s[0].ch) * - m[block_counter].s[1].rng)); // XOR4 + m[block_counter].s[1].rng), "XOR4"); // XOR4 // Chunk constraints TYPE chunk_factor = TYPE(integral_type(1) << 48); @@ -900,31 +900,31 @@ namespace nil { auto diff = m[block_counter].c[i].l_before - m[block_counter].c[i].l; constrain(diff * (diff - 1) * (diff - 2) * (diff - 3) * - (diff - 4)); // LC4 + (diff - 4), "LC4"); // LC4 constrain(diff * (diff - 1) * (diff - 2) * (diff - 4) * - (m[block_counter].c[i].b3 - 1)); // PC1 + (m[block_counter].c[i].b3 - 1), "PC1"); // PC1 constrain(diff * (diff - 1) * (diff - 3) * (diff - 4) * - (m[block_counter].c[i].b2 - 1)); // PC2 + (m[block_counter].c[i].b2 - 1), "PC2"); // PC2 constrain(diff * (diff - 1) * (diff - 3) * (diff - 4) * - m[block_counter].c[i].b3); // PC3 + m[block_counter].c[i].b3, "PC3"); // PC3 constrain(diff * (diff - 2) * (diff - 3) * (diff - 4) * - (m[block_counter].c[i].b1 - 1)); // PC4 + (m[block_counter].c[i].b1 - 1), "PC4"); // PC4 constrain(diff * (diff - 2) * (diff - 3) * (diff - 4) * - m[block_counter].c[i].b2); // PC5 + m[block_counter].c[i].b2, "PC5"); // PC5 constrain(diff * (diff - 2) * (diff - 3) * (diff - 4) * - m[block_counter].c[i].b3); // PC6 + m[block_counter].c[i].b3, "PC6"); // PC6 constrain(m[block_counter].c[i].first_in_block * (diff - 1) * (diff - 2) * (diff - 3) * (diff - 4) * - (m[block_counter].c[i].b0 - 1)); // PC11 + (m[block_counter].c[i].b0 - 1), "PC11"); // PC11 constrain(m[block_counter].c[i].first_in_block * (diff - 1) * (diff - 2) * (diff - 3) * (diff - 4) * - m[block_counter].c[i].b1); // PC12 + m[block_counter].c[i].b1, "PC12"); // PC12 constrain(m[block_counter].c[i].first_in_block * (diff - 1) * (diff - 2) * (diff - 3) * (diff - 4) * - m[block_counter].c[i].b2); // PC13 + m[block_counter].c[i].b2, "PC13"); // PC13 constrain(m[block_counter].c[i].first_in_block * (diff - 1) * (diff - 2) * (diff - 3) * (diff - 4) * - m[block_counter].c[i].b3); // PC14 + m[block_counter].c[i].b3, "PC14"); // PC14 if (i > 0) { copy_constrain(m[block_counter].c[i].first_in_block, C[0]); // LC1 @@ -935,39 +935,39 @@ namespace nil { m[block_counter].c[i].sp0 * chunk_factor * chunk_factor - m[block_counter].c[i - 1].sp1 * chunk_factor - - m[block_counter].c[i - 1].sp0); // CH7 + m[block_counter].c[i - 1].sp0, "CH7"); // CH7 auto diff_prev = m[block_counter].c[i - 1].l_before - m[block_counter].c[i - 1].l; constrain((1 - m[block_counter].c[i].first_in_block) * (m[block_counter].c[i].l_before - - m[block_counter].c[i - 1].l)); // LC3 + m[block_counter].c[i - 1].l), "LC3"); // LC3 constrain((1 - m[block_counter].c[i].first_in_block) * - diff * (diff_prev - 4)); // LC5 + diff * (diff_prev - 4), "LC5"); // LC5 constrain((1 - m[block_counter].c[i].first_in_block) * (diff_prev - diff) * (diff_prev - diff - 1) * (diff_prev - diff - 2) * (diff_prev - diff - 3) * - (m[block_counter].c[i].b0 - 1)); // PC7 + (m[block_counter].c[i].b0 - 1), "PC7"); // PC7 constrain((1 - m[block_counter].c[i].first_in_block) * (diff_prev - diff) * (diff_prev - diff - 1) * (diff_prev - diff - 2) * (diff_prev - diff - 3) * - m[block_counter].c[i].b1); // PC8 + m[block_counter].c[i].b1, "PC8"); // PC8 constrain((1 - m[block_counter].c[i].first_in_block) * (diff_prev - diff) * (diff_prev - diff - 1) * (diff_prev - diff - 2) * (diff_prev - diff - 3) * - m[block_counter].c[i].b2); // PC9 + m[block_counter].c[i].b2, "PC9"); // PC9 constrain((1 - m[block_counter].c[i].first_in_block) * (diff_prev - diff) * (diff_prev - diff - 1) * (diff_prev - diff - 2) * (diff_prev - diff - 3) * - m[block_counter].c[i].b3); // PC10 + m[block_counter].c[i].b3, "PC10"); // PC10 constrain((1 - m[block_counter].c[i].first_in_block) * (m[block_counter].c[i].rlc_before - - m[block_counter].c[i - 1].rlc)); // RLC6 + m[block_counter].c[i - 1].rlc), "RLC6"); // RLC6 } else { copy_constrain(m[block_counter].c[i].first_in_block, C[1]); // LC1 @@ -992,10 +992,10 @@ namespace nil { constrain(m[block_counter].c[i].r2 - m[block_counter].c[i].r * - m[block_counter].c[i].r); // RLC4 + m[block_counter].c[i].r, "RLC4"); // RLC4 constrain(m[block_counter].c[i].r4 - m[block_counter].c[i].r2 * - m[block_counter].c[i].r2); // RLC5 + m[block_counter].c[i].r2, "RLC5"); // RLC5 constrain( diff * (diff - 1) * (diff - 2) * (diff - 3) * (m[block_counter].c[i].rlc - @@ -1005,7 +1005,7 @@ namespace nil { m[block_counter].c[i].b0 - m[block_counter].c[i].r2 * m[block_counter].c[i].b1 - m[block_counter].c[i].r * m[block_counter].c[i].b2 - - m[block_counter].c[i].b3)); // RLC7 + m[block_counter].c[i].b3), "RLC7"); // RLC7 constrain( diff * (diff - 1) * (diff - 2) * (diff - 4) * @@ -1014,7 +1014,7 @@ namespace nil { m[block_counter].c[i].rlc_before - m[block_counter].c[i].r2 * m[block_counter].c[i].b0 - m[block_counter].c[i].r * m[block_counter].c[i].b1 - - m[block_counter].c[i].b2)); // RLC8 + m[block_counter].c[i].b2), "RLC8"); // RLC8 constrain( diff * (diff - 1) * (diff - 3) * (diff - 4) * @@ -1022,17 +1022,17 @@ namespace nil { m[block_counter].c[i].r2 * m[block_counter].c[i].rlc_before - m[block_counter].c[i].r * m[block_counter].c[i].b0 - - m[block_counter].c[i].b1)); // RLC9 + m[block_counter].c[i].b1), "RLC9"); // RLC9 constrain(diff * (diff - 2) * (diff - 3) * (diff - 4) * (m[block_counter].c[i].rlc - m[block_counter].c[i].r * m[block_counter].c[i].rlc_before - - m[block_counter].c[i].b0)); // RLC10 + m[block_counter].c[i].b0), "RLC10"); // RLC10 constrain((diff - 1) * (diff - 2) * (diff - 3) * (diff - 4) * (m[block_counter].c[i].rlc - - m[block_counter].c[i].rlc_before)); // RLC11 + m[block_counter].c[i].rlc_before), "RLC11"); // RLC11 } // Unparser constraints @@ -1047,7 +1047,7 @@ namespace nil { m[block_counter].u[i].sp0 * (sparsed_factor << 96) - m[block_counter].u[i].sp1 * (sparsed_factor << 48) - m[block_counter].u[i].sp2 * sparsed_factor - - m[block_counter].u[i].sp3); // UN2 + m[block_counter].u[i].sp3, "UN2"); // UN2 if (i > 0) { constrain(m[block_counter].u[i].hash_chunk - m[block_counter].u[i - 1].ch3 * @@ -1062,7 +1062,7 @@ namespace nil { (ufactor << (16 * 2)) - m[block_counter].u[i].ch2 * (ufactor << (16)) - m[block_counter].u[i].ch1 * ufactor - - m[block_counter].u[i].ch0); // UN7 + m[block_counter].u[i].ch0, "UN7"); // UN7 } lookup({m[block_counter].u[i].ch0, m[block_counter].u[i].sp0}, // UN3 diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp index a196d057d..d1bb5664f 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp @@ -285,7 +285,7 @@ namespace nil { using var = crypto3::zk::snark::plonk_variable; using constraint_type = crypto3::zk::snark::plonk_constraint; using plonk_copy_constraint = crypto3::zk::snark::plonk_copy_constraint; - using constraints_container_type = std::map, std::string>>; + using constraints_container_type = std::map, std::set>>; using constraint_names_container_type = std::unordered_map; using copy_constraints_container_type = std::vector; // TODO: maybe it's a set, not a vec? using lookup_input_constraints_type = crypto3::zk::snark::lookup_input_constraints; @@ -348,7 +348,7 @@ namespace nil { false, // false = use absolute cell address static_cast(t)); if ((C != TYPE()) && (t == column_type::witness)) { // TODO: TYPE() - is this ok? NB: we only constrain witnesses! - constrain(res - C,"T"); // TODO: maybe add a name for this constraint? + constrain(res - C,""); // TODO: maybe add a name for this constraint? } C = res; @@ -524,10 +524,16 @@ namespace nil { std::unordered_map, std::vector>> res; for(const auto& [id, data] : *constraints) { auto it = res.find(std::get<1>(data)); + std::string name; + bool first = true; + for(auto const &s : std::get<2>(data)){ + if(first) name = s; + else name = name + "," + s; + } if (it == res.end()) { - res[std::get<1>(data)] = {{std::get<0>(data), std::get<2>(data)}}; + res[std::get<1>(data)] = {{std::get<0>(data), name}}; } else { - it->second.push_back({std::get<0>(data), std::get<2>(data)}); + it->second.push_back({std::get<0>(data), name}); } } return res; @@ -584,7 +590,6 @@ namespace nil { void reset_storage() { constraints = std::make_shared(); - // constraint_names = std::make_shared(); copy_constraints = std::make_shared(); lookup_constraints = std::make_shared(); lookup_tables = std::make_shared(); @@ -609,16 +614,10 @@ namespace nil { std::size_t stored_row = row - (is_fresh ? row_shift : 0); constraint_id_type C_id = constraint_id_type(C_rel); if (constraints->find(C_id) == constraints->end()) { - constraints->insert({C_id, {C_rel, row_selector<>(desc.rows_amount), name}}); + constraints->insert({C_id, {C_rel, row_selector<>(desc.rows_amount), {name}}}); } std::get<1>(constraints->at(C_id)).set_row(stored_row); - - auto old_name = std::get<2>(constraints->at(C_id)); - if(old_name.find(name) == std::string::npos){ - old_name += " or "; - old_name += name; - std::get<2>(constraints->at(C_id)) = old_name; - } + std::get<2>(constraints->at(C_id)).insert(name); } void add_constraint(TYPE &C_rel, std::size_t start_row, std::size_t end_row, std::string name) { @@ -629,13 +628,7 @@ namespace nil { constraints->insert({C_id, {C_rel, row_selector<>(desc.rows_amount), name}}); } std::get<1>(constraints->at(C_id)).set_interval(stored_start_row, stored_end_row); - - auto old_name = std::get<2>(constraints->at(C_id)); - if(old_name.find(name) == std::string::npos){ - old_name += " or "; - old_name += name; - std::get<2>(constraints->at(C_id)) = old_name; - } + std::get<2>(constraints->at(C_id)).insert(name); } void add_lookup_constraint( From c6ac73c0aa84d80052fcbedad6b344c3760f9721 Mon Sep 17 00:00:00 2001 From: Valeh Date: Tue, 28 Jan 2025 15:30:30 +0200 Subject: [PATCH 03/14] clean up --- .../bbf/components/hashes/keccak/keccak_dynamic.hpp | 2 +- .../libs/blueprint/include/nil/blueprint/bbf/generic.hpp | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp index 45ef055cd..f904ea7eb 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp @@ -729,7 +729,7 @@ namespace nil { // gates: for (std::size_t i = 0; i < 6247 * max_blocks; i++) { - constrain(selector[i] * (1 - selector[i]), "DYNAMIC_SELECTOR"); + constrain(selector[i] * (1 - selector[i]), "KECCAK_DYNAMIC_SELECTOR"); } for (std::size_t block_counter = 0; block_counter < max_blocks; block_counter++) { diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp index d1bb5664f..4eba4e46b 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp @@ -286,7 +286,6 @@ namespace nil { using constraint_type = crypto3::zk::snark::plonk_constraint; using plonk_copy_constraint = crypto3::zk::snark::plonk_copy_constraint; using constraints_container_type = std::map, std::set>>; - using constraint_names_container_type = std::unordered_map; using copy_constraints_container_type = std::vector; // TODO: maybe it's a set, not a vec? using lookup_input_constraints_type = crypto3::zk::snark::lookup_input_constraints; using lookup_constraints_container_type = std::map, // @@ -417,7 +416,7 @@ namespace nil { } // accesible only at GenerationStage::CONSTRAINTS ! - void relative_constrain(TYPE C_rel, std::size_t row, std::string constraint_name) { + void relative_constrain(TYPE C_rel, std::size_t row, std::string constraint_name = "") { if (!C_rel.is_relative()) { std::stringstream ss; ss << "Constraint " << C_rel << " has absolute variables, cannot constrain."; @@ -426,7 +425,7 @@ namespace nil { add_constraint(C_rel, get_row(row), constraint_name); } - void relative_constrain(TYPE C_rel, std::size_t start_row, std::size_t end_row, std::string constraint_name) { + void relative_constrain(TYPE C_rel, std::size_t start_row, std::size_t end_row, std::string constraint_name = "") { if (!C_rel.is_relative()) { std::stringstream ss; ss << "Constraint " << C_rel << " has absolute variables, cannot constrain."; @@ -665,8 +664,6 @@ namespace nil { // constraints (with unique id), and the rows they are applied to std::shared_ptr constraints; - // constraint names - // std::shared_ptr constraint_names; // copy constraints as in BP std::shared_ptr copy_constraints; // lookup constraints with table name, unique id and row list From 639248e5f5b07e9ec139b058918ee1c83030b2e2 Mon Sep 17 00:00:00 2001 From: Valeh Date: Tue, 28 Jan 2025 15:58:19 +0200 Subject: [PATCH 04/14] small fixes --- .../blueprint/include/nil/blueprint/bbf/circuit_builder.hpp | 3 +-- .../blueprint/include/nil/blueprint/bbf/gate_optimizer.hpp | 2 +- crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/circuit_builder.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/circuit_builder.hpp index db9c0aff3..ab7d53df6 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/circuit_builder.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/circuit_builder.hpp @@ -197,8 +197,7 @@ namespace nil { std::vector constraints; std::vector names; for(const auto &d : data){ - constraints.push_back(std::move(d.first)); - + constraints.push_back(d.first); names.push_back(d.second); } bp.add_gate(selector_id, constraints); diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/gate_optimizer.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/gate_optimizer.hpp index accf547d9..37ecdeeb8 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/gate_optimizer.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/gate_optimizer.hpp @@ -115,7 +115,7 @@ namespace nil { os << "Constraints: " << std::endl; if (iter != gates.constraint_list.end()) { for (const auto &constraint : iter->second) { - os << constraint.second << "( " << constraint.first << " )" << std::endl; + os << constraint.second << constraint.first << std::endl; } os << "--------------------------------------------------------------" << std::endl; } diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp index 4eba4e46b..eb6b6fc44 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp @@ -526,7 +526,7 @@ namespace nil { std::string name; bool first = true; for(auto const &s : std::get<2>(data)){ - if(first) name = s; + if(first) { name = s; first = false;} else name = name + "," + s; } if (it == res.end()) { @@ -624,7 +624,7 @@ namespace nil { std::size_t stored_end_row = end_row - (is_fresh ? row_shift : 0); constraint_id_type C_id = constraint_id_type(C_rel); if (constraints->find(C_id) == constraints->end()) { - constraints->insert({C_id, {C_rel, row_selector<>(desc.rows_amount), name}}); + constraints->insert({C_id, {C_rel, row_selector<>(desc.rows_amount), {name}}}); } std::get<1>(constraints->at(C_id)).set_interval(stored_start_row, stored_end_row); std::get<2>(constraints->at(C_id)).insert(name); From af7bcabbf63273ce2eb47afa2dd0be290fa51cb9 Mon Sep 17 00:00:00 2001 From: Valeh Date: Tue, 28 Jan 2025 18:45:59 +0200 Subject: [PATCH 05/14] fix usage of get_constraint within components --- .../blueprint/include/nil/blueprint/bbf/exp_wrapper.hpp | 8 ++++++-- .../blueprint/include/nil/blueprint/bbf/l1_wrapper.hpp | 8 ++++++-- .../blueprint/include/nil/blueprint/bbf/opcode_poc.hpp | 4 ++-- .../blueprint/include/nil/blueprint/zkevm_bbf/zkevm.hpp | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/exp_wrapper.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/exp_wrapper.hpp index 34ad6519a..4137f16c6 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/exp_wrapper.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/exp_wrapper.hpp @@ -209,10 +209,10 @@ namespace nil { ct.optimize_gates(); // compatibility layer: constraint list => gates & selectors - std::unordered_map, std::vector> constraint_list = + std::unordered_map, std::vector>> constraint_list = ct.get_constraints(); - for(const auto& [row_list, constraints] : constraint_list) { + for(const auto& [row_list, data] : constraint_list) { /* std::cout << "GATE:\n"; for(const auto& c : constraints) { @@ -220,6 +220,10 @@ namespace nil { } std::cout << "Rows: "; */ + std::vector constraints; + for(auto const& d : data){ + constraints.push_back(d.first); + } std::size_t selector_index = bp.add_gate(constraints); for(const std::size_t& row_index : row_list) { // std::cout << row_index << " "; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/l1_wrapper.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/l1_wrapper.hpp index 703f66ae0..c89aa7c2f 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/l1_wrapper.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/l1_wrapper.hpp @@ -210,10 +210,10 @@ namespace nil { // ct.optimize_gates(); // compatibility layer: constraint list => gates & selectors - std::unordered_map, std::vector> constraint_list = + std::unordered_map, std::vector>> constraint_list = ct.get_constraints(); - for(const auto& [row_list, constraints] : constraint_list) { + for(const auto& [row_list, data] : constraint_list) { /* std::cout << "GATE:\n"; for(const auto& c : constraints) { @@ -221,6 +221,10 @@ namespace nil { } std::cout << "Rows: "; */ + std::vector constraints; + for(auto const& d : data){ + constraints.push_back(d.first); + } std::size_t selector_index = bp.add_gate(constraints); for(const std::size_t& row_index : row_list) { // std::cout << row_index << " "; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/opcode_poc.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/opcode_poc.hpp index 083cbd7c2..3551af0e3 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/opcode_poc.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/opcode_poc.hpp @@ -106,7 +106,7 @@ namespace nil { std::vector block_list; std::vector> block_selector(max_rows); std::vector> block_row_selector(max_rows); - std::array, std::vector>, 5> block_constraints; + std::array, std::vector>>, 5> block_constraints; if constexpr (stage == GenerationStage::ASSIGNMENT) { std::cout << "Opcode POC assignment" << std::endl; @@ -163,7 +163,7 @@ namespace nil { if( !constr_list.first.is_set(block_row) ) continue; for( auto &constr: constr_list.second ){ //std::cout << pair_selector_relative * constr << std::endl; - context_object.relative_constrain(pair_selector_relative * constr, i); + context_object.relative_constrain(pair_selector_relative * constr.first, i, constr.second); } } } diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/zkevm.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/zkevm.hpp index 2e83f4801..dbb434dc9 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/zkevm.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/zkevm.hpp @@ -443,7 +443,7 @@ namespace nil { auto opcode_constraints = fresh_ct.get_constraints(); for( const auto &constr_list: opcode_constraints){ for( const auto &local_row: constr_list.first){ - for( auto constraint: constr_list.second){ + for( auto [constraint, name]: constr_list.second){ std::size_t real_row = std::ceil(float(current_opcode_bare_rows_amount) / 2) * 2 - local_row - current_opcode_bare_rows_amount % 2; opcode_constraints_aggregator[{current_opcode, real_row}].push_back(constraint); if(opcode_constraints_aggregator[{current_opcode, real_row}].size() > max_opcode_row_constraints){ From eba7d29195c79a3124c4c09088683679a84a7f83 Mon Sep 17 00:00:00 2001 From: Antoine Cyr Date: Wed, 8 Jan 2025 12:35:57 -0500 Subject: [PATCH 06/14] template specifications improvment bbf circuit --- .../algebra/fields/non_native/flexible_multiplication.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp index 7b97d0391..a273b16ec 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp @@ -63,7 +63,7 @@ namespace nil { TYPE zero; }; - template + template class flexible_multiplication : public generic_component { using generic_component::allocate; using generic_component::copy_constrain; @@ -329,7 +329,7 @@ namespace nil { template class pallas_flexible_multiplication : public flexible_multiplication { + crypto3::algebra::curves::pallas::base_field_type,0> { using Base = flexible_multiplication; public: From 6c1e3da2bc12bb25dba4c07f9445c618ef33ba45 Mon Sep 17 00:00:00 2001 From: Antoine Cyr Date: Thu, 9 Jan 2025 12:20:56 -0500 Subject: [PATCH 07/14] nonNative addition_mod_p bbf --- .../nil/blueprint/bbf/choice_function.hpp | 110 ------ .../fields/non_native/addition_mod_p.hpp | 316 ++++++++++++++++++ .../algebra/fields/non_native/check_mod_p.hpp | 6 +- .../non_native/flexible_multiplication.hpp | 30 +- .../components/detail/carry_on_addition.hpp | 5 +- .../bbf/components/detail/choice_function.hpp | 145 ++++++++ crypto3/libs/blueprint/test/CMakeLists.txt | 2 + .../fields/non_native/addition_mod_p.cpp | 199 +++++++++++ .../non_native/flexible_multiplication.cpp | 44 +-- .../test/bbf/detail/carry_on_addition.cpp | 2 +- .../test/bbf/detail/choice_function.cpp | 137 ++++++++ 11 files changed, 841 insertions(+), 155 deletions(-) delete mode 100644 crypto3/libs/blueprint/include/nil/blueprint/bbf/choice_function.hpp create mode 100644 crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp create mode 100644 crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp create mode 100644 crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp create mode 100644 crypto3/libs/blueprint/test/bbf/detail/choice_function.cpp diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/choice_function.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/choice_function.hpp deleted file mode 100644 index 64226bdfc..000000000 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/choice_function.hpp +++ /dev/null @@ -1,110 +0,0 @@ -//---------------------------------------------------------------------------// -// Copyright (c) 2024 Alexey Yashunsky -// -// MIT License -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -//---------------------------------------------------------------------------// -// @file Declaration of interfaces for PLONK BBF choice_function component class -//---------------------------------------------------------------------------// - -#ifndef CRYPTO3_BLUEPRINT_PLONK_BBF_CHOICE_FUNCTION_COMPONENT_HPP -#define CRYPTO3_BLUEPRINT_PLONK_BBF_CHOICE_FUNCTION_COMPONENT_HPP - -#include - -#include - -#include -#include -#include -//#include - -#include - -namespace nil { - namespace blueprint { - namespace bbf { - - template - class choice_function : public generic_component { - using typename generic_component::context_type; - using generic_component::allocate; - using generic_component::copy_constrain; - using generic_component::constrain; - - public: - using typename generic_component::TYPE; - - public: - TYPE q, x[num_chunks], y[num_chunks], z[num_chunks]; // interfaces - - choice_function(context_type &context_object, - TYPE input_q, - std::array input_x, - std::array input_y, - bool make_links = true) : - generic_component(context_object) { - - TYPE Q, X[num_chunks], Y[num_chunks], Z[num_chunks]; - - if constexpr (stage == GenerationStage::ASSIGNMENT) { - Q = input_q; - for(std::size_t i = 0; i < num_chunks; i++) { - X[i] = input_x[i]; - Y[i] = input_y[i]; - } - } - - allocate(Q); - for(std::size_t i = 0; i < num_chunks; i++) { - allocate(X[i]); - } - for(std::size_t i = 0; i < num_chunks; i++) { - allocate(Y[i]); - } - - if (make_links) { - copy_constrain(Q,input_q); - for(std::size_t i = 0; i < num_chunks; i++) { - copy_constrain(X[i],input_x[i]); - copy_constrain(Y[i],input_y[i]); - } - } - - constrain(Q*(1-Q)); - for(std::size_t i = 0; i < num_chunks; i++) { - Z[i] = (1-Q)*X[i] + Q*Y[i]; - allocate(Z[i]); - } - - q = Q; - for(std::size_t i = 0; i < num_chunks; i++) { - x[i] = X[i]; - y[i] = Y[i]; - z[i] = Z[i]; - } - }; - }; - - } // namespace bbf - } // namespace blueprint -} // namespace nil - -#endif // CRYPTO3_BLUEPRINT_PLONK_BBF_CHOICE_FUNCTION_COMPONENT_HPP diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp new file mode 100644 index 000000000..708f26394 --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp @@ -0,0 +1,316 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Valeh Farzaliyev +// Copyright (c) 2024 Antoine Cyr +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// +// @file Declaration of interfaces for FRI verification array swapping component. +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BBF_COMPONENTS_ADDITION_MOD_P_HPP +#define CRYPTO3_BBF_COMPONENTS_ADDITION_MOD_P_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace nil { + namespace blueprint { + namespace bbf { + namespace components { + // Addition mod p + // operates on k-chunked x,y, p, p' + // Parameters: num_chunks = k, bit_size_chunk = b + // Input: x[0], ..., x[k-1], y[0], ..., y[k-1], p[0], ..., p[k-1], p'[0], ..., p'[k-1], 0 + // Intemmediate values: q, t[0], ..., t[k-1], carry[k-1], t'[0], ..., t'[k-1], t"[0], ..., t"[k-1], carry"[k-1] + // Output: z[0] = x[0] + y[0] - qp[0], ..., z[k-1] = x[k-1] + y[k-1] -qp[k-1] + // + + template + struct addition_mod_p_raw_input { + using TYPE = typename FieldType::value_type; + std::vector x; + std::vector y; + std::vector p; + std::vector pp; + TYPE zero; + }; + + template + class addition_mod_p : public generic_component { + using generic_component::allocate; + using generic_component::copy_constrain; + using generic_component::constrain; + using generic_component::lookup; + using component_type = generic_component; + + public: + using typename generic_component::TYPE; + using typename generic_component::context_type; + using typename generic_component::table_params; + using raw_input_type = + typename std::conditional, + std::tuple<>>::type; + using NonNativeIntegralExtendedVariant = + std::variant, + nil::crypto3::multiprecision::big_uint< + 2 * crypto3::algebra::curves::vesta:: + base_field_type::modulus_bits>>; + + template + struct NonNativeFieldTypeIndex; + + template<> + struct NonNativeFieldTypeIndex< + crypto3::algebra::curves::pallas::base_field_type> { + static constexpr std::size_t value = 0; + }; + + template<> + struct NonNativeFieldTypeIndex< + crypto3::algebra::curves::vesta::base_field_type> { + static constexpr std::size_t value = 1; + }; + + public: + std::vector inp_x; + std::vector inp_y; + std::vector inp_p; + std::vector inp_pp; + std::vector res; + + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::size_t witness = 4 * num_chunks + 1; + constexpr std::size_t public_inputs = 1; + constexpr std::size_t constants = 0; + // rows = 4096-1 so that lookup table is not too hard to fit and padding doesn't inflate the table + constexpr std::size_t rows = 4095; + return {witness, public_inputs, constants, rows}; + } + + static std::tuple, std::vector, + std::vector, std::vector, TYPE> + form_input(context_type &context_object, raw_input_type raw_input, + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::vector input_x(num_chunks); + std::vector input_y(num_chunks); + std::vector input_p(num_chunks); + std::vector input_pp(num_chunks); + TYPE input_zero; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; i++) { + input_x[i] = raw_input.x[i]; + input_y[i] = raw_input.y[i]; + input_p[i] = raw_input.p[i]; + input_pp[i] = raw_input.pp[i]; + } + input_zero = raw_input.zero; + } + for (std::size_t i = 0; i < num_chunks; i++) { + context_object.allocate(input_x[i], 0, i, + column_type::public_input); + context_object.allocate(input_y[i], 0, i + num_chunks, + column_type::public_input); + context_object.allocate(input_p[i], 0, i + 2 * num_chunks, + column_type::public_input); + context_object.allocate(input_pp[i], 0, i + 3 * num_chunks, + column_type::public_input); + } + context_object.allocate(input_zero, 0, 4 * num_chunks, + column_type::public_input); + return std::make_tuple(input_x, input_y, input_p, input_pp, + input_zero); + } + + addition_mod_p(context_type &context_object, + std::vector input_x, std::vector input_y, + std::vector input_p, std::vector input_pp, + TYPE input_zero, std::size_t num_chunks, + std::size_t bit_size_chunk, bool make_links = true) + : generic_component(context_object) { + using integral_type = typename FieldType::integral_type; + using extended_integral_type = + typename std::variant_alternative_t< + NonNativeFieldTypeIndex::value, + NonNativeIntegralExtendedVariant>; + + using Carry_On_Addition = + typename bbf::components::carry_on_addition; + using Choice_Function = + typename bbf::components::choice_function; + using Check_Mod_P = + typename bbf::components::check_mod_p; + using Range_Check = + typename bbf::components::range_check_multi; + + std::vector X(num_chunks); + std::vector Y(num_chunks); + std::vector P(num_chunks); + std::vector PP(num_chunks); + std::vector Z(num_chunks); + std::vector ZERO(num_chunks); + TYPE Q; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + Q = 0; + for (std::size_t i = 0; i < num_chunks; ++i) { + X[i] = input_x[i]; + Y[i] = input_y[i]; + P[i] = input_p[i]; + PP[i] = input_pp[i]; + ZERO[i] = input_zero; + } + extended_integral_type x = 0, y = 0, z = 0, p = 0, pow = 1; + + // Populate x, y, p + for (std::size_t i = 0; i < num_chunks; ++i) { + x += extended_integral_type(integral_type(X[i].data)) * + pow; + y += extended_integral_type(integral_type(Y[i].data)) * + pow; + p += extended_integral_type(integral_type(P[i].data)) * + pow; + pow <<= bit_size_chunk; + } + + z = x + y; // x + y = z + qp + if (z >= p) { + z -= p; + Q = 1; + } + extended_integral_type mask = + (extended_integral_type(1) << bit_size_chunk) - 1; + for (std::size_t i = 0; i < num_chunks; ++i) { + Z[i] = TYPE(z & mask); + z >>= bit_size_chunk; + } + } + + for (std::size_t i = 0; i < num_chunks; ++i) { + allocate(X[i]); + allocate(Y[i]); + allocate(P[i]); + allocate(PP[i]); + allocate(Z[i]); + allocate(ZERO[i]); + } + allocate(Q); + + Carry_On_Addition ca_1 = Carry_On_Addition( + context_object, X, Y, num_chunks, bit_size_chunk); + Range_Check rc_1 = Range_Check(context_object, ca_1.res_z, + num_chunks, bit_size_chunk); + //(qp = 0 or p) + Choice_Function cf = + Choice_Function(context_object, Q, ZERO, P, num_chunks); + + Carry_On_Addition ca_2 = + Carry_On_Addition(context_object, cf.res_z, Z, num_chunks, + bit_size_chunk); // qp + z + + // carry_on_addition results should be equal to each other x + y = z + qp + + for (std::size_t i = 0; i < num_chunks; i++) { + copy_constrain(ca_1.res_z[i], ca_2.res_z[i]); + } + copy_constrain(ca_1.res_c, ca_2.res_c); + + Range_Check rc_2 = Range_Check(context_object, ca_2.res_z, + num_chunks, bit_size_chunk); + + Range_Check rc_3 = + Range_Check(context_object, Z, num_chunks, bit_size_chunk); + + Check_Mod_P cm = Check_Mod_P(context_object, Z, PP, ZERO[0], + num_chunks, bit_size_chunk); + + if (make_links) { + for (std::size_t i = 0; i < num_chunks; ++i) { + copy_constrain(X[i], input_x[i]); + copy_constrain(Y[i], input_y[i]); + copy_constrain(P[i], input_p[i]); + copy_constrain(PP[i], input_pp[i]); + copy_constrain(ZERO[i], input_zero); + } + } + + for (int i = 0; i < num_chunks; ++i) { + inp_x.push_back(input_x[i]); + inp_y.push_back(input_y[i]); + inp_p.push_back(input_p[i]); + inp_pp.push_back(input_pp[i]); + } + for (int i = 0; i < num_chunks; ++i) { + res.push_back(Z[i]); + } + } + }; + + template + class pallas_addition_mod_p + : public addition_mod_p< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { + using Base = + addition_mod_p; + + public: + using Base::Base; + }; + + template + class vesta_addition_mod_p + : public addition_mod_p< + FieldType, stage, + crypto3::algebra::curves::vesta::base_field_type> { + using Base = + addition_mod_p; + + public: + using Base::Base; + }; + + } // namespace components + } // namespace bbf + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BBF_COMPONENTS_ADDITION_MOD_P_HPP diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp index 70831e932..ff0ca66a7 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp @@ -78,7 +78,7 @@ namespace nil { static table_params get_minimal_requirements(std::size_t num_chunks, std::size_t bit_size_chunk, - bool expect_output) { + bool expect_output = false) { static const std::size_t bit_size_rc = 16; std::size_t num_rc_chunks = (bit_size_chunk / bit_size_rc) + (bit_size_chunk % bit_size_rc > 0); @@ -95,7 +95,7 @@ namespace nil { raw_input_type raw_input, std::size_t num_chunks, std::size_t bit_size_chunk, - bool expect_output) { + bool expect_output = false) { std::vector input_x(num_chunks); std::vector input_pp(num_chunks); TYPE input_zero; @@ -116,7 +116,7 @@ namespace nil { } check_mod_p(context_type &context_object, std::vector input_x, std::vector input_pp, TYPE input_zero, - std::size_t num_chunks, std::size_t bit_size_chunk,bool expect_output, + std::size_t num_chunks, std::size_t bit_size_chunk,bool expect_output = false, bool make_links = true) : generic_component(context_object) { using integral_type = typename FieldType::integral_type; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp index a273b16ec..c5a8b112f 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp @@ -63,7 +63,7 @@ namespace nil { TYPE zero; }; - template + template class flexible_multiplication : public generic_component { using generic_component::allocate; using generic_component::copy_constrain; @@ -166,21 +166,21 @@ namespace nil { P[i] = input_p[i]; PP[i] = input_pp[i]; } - double_non_native_integral_type foreign_p = 0, + extended_integral_type foreign_p = 0, foreign_x = 0, foreign_y = 0, pow = 1; for (std::size_t i = 0; i < num_chunks; ++i) { - foreign_x += double_non_native_integral_type(native_integral_type(X[i].data)) * pow; - foreign_y += double_non_native_integral_type(native_integral_type(Y[i].data)) * pow; - foreign_p += double_non_native_integral_type(native_integral_type(P[i].data)) * pow; + foreign_x += extended_integral_type(integral_type(X[i].data)) * pow; + foreign_y += extended_integral_type(integral_type(Y[i].data)) * pow; + foreign_p += extended_integral_type(integral_type(P[i].data)) * pow; pow <<= bit_size_chunk; } - double_non_native_integral_type foreign_r = (foreign_x * foreign_y) % foreign_p, // r = x*y % p + extended_integral_type foreign_r = (foreign_x * foreign_y) % foreign_p, // r = x*y % p foreign_q = (foreign_x * foreign_y - foreign_r) / foreign_p; // q = (x*y - r)/p - double_non_native_integral_type mask = (double_non_native_integral_type(1) << bit_size_chunk) - 1; + extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; for (std::size_t j = 0; j < num_chunks; ++j) { Q[j] = TYPE(foreign_q & mask); R[j] = TYPE(foreign_r & mask); @@ -199,7 +199,7 @@ namespace nil { allocate(P[i]); } - native_integral_type pow = 1; + integral_type pow = 1; for (std::size_t j = 0; j < num_chunks; ++j) { x_n += X[j] * pow; y_n += Y[j] * pow; @@ -235,20 +235,20 @@ namespace nil { if constexpr (stage == GenerationStage::ASSIGNMENT) { A[0] = Z[0] - R[0]; - native_integral_type a_integral = native_integral_type(A[0].data) >> bit_size_chunk; + integral_type a_integral = integral_type(A[0].data) >> bit_size_chunk; A[0] = TYPE(a_integral); for (std::size_t i = 1; i < num_chunks; ++i) { A[i] = (Z[i] + A[i-1] - R[i]); - a_integral = native_integral_type(A[i].data) >> bit_size_chunk; + a_integral = integral_type(A[i].data) >> bit_size_chunk; A[i] = TYPE(a_integral); } for (std::size_t i = 0; i < num_chunks - 2; ++i) { - B[2*i] = TYPE(native_integral_type(A[i].data) & ((native_integral_type(1) << bit_size_chunk) - 1)); - B[2*i + 1] =TYPE(native_integral_type(A[i].data) >> bit_size_chunk); + B[2*i] = TYPE(integral_type(A[i].data) & ((integral_type(1) << bit_size_chunk) - 1)); + B[2*i + 1] =TYPE(integral_type(A[i].data) >> bit_size_chunk); } } - native_integral_type b_shift = native_integral_type(1) << bit_size_chunk; + integral_type b_shift = integral_type(1) << bit_size_chunk; allocate(A[0]); constrain(A[0]*b_shift - Z[0] + R[0]); // constrain that the last t bits of z are equal to r: @@ -329,7 +329,7 @@ namespace nil { template class pallas_flexible_multiplication : public flexible_multiplication { + crypto3::algebra::curves::pallas::base_field_type> { using Base = flexible_multiplication; public: @@ -350,4 +350,4 @@ namespace nil { } // namespace blueprint } // namespace nil -#endif // CRYPTO3_BBF_COMPONENTS_FLEXIBLE_MULTIPLICATION_HPP +#endif // CRYPTO3_BBF_COMPONENTS_FLEXIBLE_MULTIPLICATION_HPP \ No newline at end of file diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp index 4b1af55fa..59c6d9c45 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp @@ -53,7 +53,6 @@ namespace nil { using generic_component::copy_constrain; using generic_component::constrain; using generic_component::lookup; - using component_type = generic_component; public: using typename generic_component::TYPE; @@ -74,7 +73,7 @@ namespace nil { std::size_t witness = 2; constexpr std::size_t public_inputs = 1; constexpr std::size_t constants = 0; - std::size_t rows = 4*num_chunks; + std::size_t rows = 3*num_chunks + 1; return {witness, public_inputs, constants, rows}; } @@ -138,8 +137,6 @@ namespace nil { for (int i = 0; i < num_chunks; ++i) { inp_x.push_back(input_x[i]); inp_y.push_back(input_y[i]); - } - for (int i = 0; i < num_chunks; ++i) { res_z.push_back(Z[i]); } res_c = C[num_chunks-1]; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp new file mode 100644 index 000000000..6b3e02396 --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp @@ -0,0 +1,145 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Alexey Yashunsky +// Copyright (c) 2024 Antoine Cyr +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// +// @file Declaration of interfaces for PLONK BBF choice_function component class +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BLUEPRINT_PLONK_BBF_CHOICE_FUNCTION_COMPONENT_HPP +#define CRYPTO3_BLUEPRINT_PLONK_BBF_CHOICE_FUNCTION_COMPONENT_HPP + +#include +#include +#include +#include +#include +#include + +namespace nil { + namespace blueprint { + namespace bbf { + namespace components { + + template + struct choice_function_raw_input { + using TYPE = typename FieldType::value_type; + TYPE q; + std::vector x; + std::vector y; + }; + + template + class choice_function : public generic_component { + using generic_component::allocate; + using generic_component::copy_constrain; + using generic_component::constrain; + + public: + using typename generic_component::TYPE; + using typename generic_component::context_type; + using typename generic_component::table_params; + using raw_input_type = + typename std::conditional, + std::tuple<>>::type; + + public: + TYPE inp_q; + std::vector inp_x, inp_y, res_z; + + static table_params get_minimal_requirements(std::size_t num_chunks) { + std::size_t witness = num_chunks + 1; + constexpr std::size_t public_inputs = 1; + constexpr std::size_t constants = 0; + std::size_t rows = 3 * num_chunks + 1; + return {witness, public_inputs, constants, rows}; + } + + static std::tuple, std::vector> + form_input(context_type &context_object, raw_input_type raw_input, + std::size_t num_chunks) { + TYPE input_q; + std::vector input_x(num_chunks); + std::vector input_y(num_chunks); + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; ++i) { + input_q = raw_input.q; + input_x[i] = raw_input.x[i]; + input_y[i] = raw_input.y[i]; + } + } + context_object.allocate(input_q, 0, 0, column_type::public_input); + for (std::size_t i = 0; i < num_chunks; ++i) { + context_object.allocate(input_x[i], 0, i + 1, + column_type::public_input); + context_object.allocate(input_y[i], 0, i + num_chunks + 1, + column_type::public_input); + } + return std::make_tuple(input_q, input_x, input_y); + } + + choice_function(context_type &context_object, TYPE input_q, + std::vector input_x, std::vector input_y, + std::size_t num_chunks, bool make_links = true) + : generic_component(context_object) { + TYPE Q, X[num_chunks], Y[num_chunks], Z[num_chunks]; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + Q = input_q; + for (std::size_t i = 0; i < num_chunks; i++) { + X[i] = input_x[i]; + Y[i] = input_y[i]; + } + } + + allocate(Q); + constrain(Q * (1 - Q)); + for (std::size_t i = 0; i < num_chunks; i++) { + allocate(X[i]); + allocate(Y[i]); + Z[i] = (1 - Q) * X[i] + Q * Y[i]; + allocate(Z[i]); + } + + if (make_links) { + copy_constrain(Q, input_q); + for (std::size_t i = 0; i < num_chunks; i++) { + copy_constrain(X[i], input_x[i]); + copy_constrain(Y[i], input_y[i]); + } + } + + inp_q = input_q; + for (std::size_t i = 0; i < num_chunks; i++) { + inp_x.push_back(X[i]); + inp_y.push_back(Y[i]); + res_z.push_back(Z[i]); + } + }; + }; + } // namespace components + } // namespace bbf + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BLUEPRINT_PLONK_BBF_CHOICE_FUNCTION_COMPONENT_HPP diff --git a/crypto3/libs/blueprint/test/CMakeLists.txt b/crypto3/libs/blueprint/test/CMakeLists.txt index 38db7a296..c905d4b51 100644 --- a/crypto3/libs/blueprint/test/CMakeLists.txt +++ b/crypto3/libs/blueprint/test/CMakeLists.txt @@ -101,6 +101,8 @@ set(COMMON_TEST_FILES "bbf/no_assignment_checks" "bbf/detail/range_check_multi" "bbf/detail/carry_on_addition" + "bbf/detail/choice_function" + "bbf/algebra/fields/non_native/addition_mod_p" "bbf/algebra/fields/non_native/check_mod_p" "bbf/algebra/fields/non_native/flexible_multiplication" ) diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp new file mode 100644 index 000000000..77131a719 --- /dev/null +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp @@ -0,0 +1,199 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Valeh Farzaliyev +// Copyright (c) 2024 Antoine Cyr +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE bbf_check_mod_p_test + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace nil; +using namespace nil::blueprint; + + +template +void test_addition_mod_p(const std::vector &public_input) { + using FieldType = BlueprintFieldType; + using TYPE = typename FieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> + extended_integral_type; + + extended_integral_type x = 0, y = 0, p = 0, pow = 1; + // Populate x, y, p + for (std::size_t i = 0; i < num_chunks; ++i) { + x += extended_integral_type(integral_type(public_input[i].data)) * pow; + y += extended_integral_type( + integral_type(public_input[i + num_chunks].data)) * + pow; + p += extended_integral_type( + integral_type(public_input[i + 2 * num_chunks].data)) * + pow; + pow <<= bit_size_chunk; + } + + extended_integral_type z = x + y; + if (z >= p) { + z -= p; + } + + auto assign_and_check = [&](auto &B, auto &raw_input) { + raw_input.x = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.y = std::vector(public_input.begin() + num_chunks, + public_input.begin() + 2 * num_chunks); + raw_input.p = std::vector(public_input.begin() + 2 * num_chunks, + public_input.begin() + 3 * num_chunks); + raw_input.pp = std::vector(public_input.begin() + 3 * num_chunks, + public_input.begin() + 4 * num_chunks); + raw_input.zero = public_input[4 * num_chunks]; + + auto [at, A, desc] = B.assign(raw_input); + bool pass = B.is_satisfied(at); + std::cout << "Is_satisfied = " << pass << std::endl; + + assert(pass == true); + extended_integral_type Z = 0; + pow = 1; + for (std::size_t i = 0; i < num_chunks; i++) { + Z += extended_integral_type(integral_type(A.res[i].data)) * pow; + pow <<= bit_size_chunk; + } +#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "addition_mod_p test" << std::endl; + std::cout << "Expected res: " << std::dec << z << std::endl; + std::cout << "Real res: " << std::dec << Z << std::endl; +#endif + assert(z == Z); + + }; + + if constexpr (std::is_same_v) { + typename bbf::components::vesta_addition_mod_p< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + + auto B = + bbf::circuit_builder(num_chunks, bit_size_chunk); + + assign_and_check(B, raw_input); + } else if constexpr (std::is_same_v< + NonNativeFieldType, + crypto3::algebra::curves::vesta::base_field_type>) { + typename bbf::components::pallas_addition_mod_p< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + auto B = + bbf::circuit_builder(num_chunks, bit_size_chunk); + + assign_and_check(B, raw_input); + } +} + + +template +void addition_mod_p_tests() { + using value_type = typename BlueprintFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using foreign_value_type = typename NonNativeFieldType::value_type; + typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> + extended_integral_type; + + static boost::random::mt19937 seed_seq; + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); + boost::random::uniform_int_distribution<> t_dist(0, 1); + extended_integral_type mask = + (extended_integral_type(1) << bit_size_chunk) - 1; + + for (std::size_t i = 0; i < RandomTestsAmount; i++) { + std::vector public_input; + + foreign_value_type src_x = generate_random(), src_y = generate_random(); + + extended_integral_type x = extended_integral_type( + integral_type(src_x.data)), + y = extended_integral_type( + integral_type(src_y.data)), + extended_base = 1, + ext_pow = extended_base + << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus; + extended_integral_type pp = ext_pow - p; + + public_input.resize(4 * num_chunks + 1); + for (std::size_t j = 0; j < num_chunks; j++) { + public_input[j] = value_type(x & mask); + x >>= bit_size_chunk; + + public_input[num_chunks + j] = value_type(y & mask); + y >>= bit_size_chunk; + + public_input[2 * num_chunks + j] = value_type(p & mask); + p >>= bit_size_chunk; + + public_input[3 * num_chunks + j] = value_type(pp & mask); + pp >>= bit_size_chunk; + } + public_input.push_back(value_type(0)); // the zero + + test_addition_mod_p(public_input); + } +} + +constexpr static const std::size_t random_tests_amount = 10; + +BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) + +BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_addition_mod_p_test) { + using pallas_field_type = typename crypto3::algebra::curves::pallas::base_field_type; + using vesta_field_type = typename crypto3::algebra::curves::vesta::base_field_type; + + addition_mod_p_tests(); + + addition_mod_p_tests(); + + addition_mod_p_tests(); + + addition_mod_p_tests(); + + addition_mod_p_tests(); + + addition_mod_p_tests(); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp index d1a1f6346..13b9baf65 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp @@ -55,24 +55,24 @@ void test_mult(const std::vector &publi using FieldType = BlueprintFieldType; using TYPE = typename FieldType::value_type; using integral_type = typename BlueprintFieldType::integral_type; - using double_non_native_integral_type = + using extended_integral_type = nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits>; - double_non_native_integral_type x = 0, y = 0, p = 0, pow = 1; + extended_integral_type x = 0, y = 0, p = 0, pow = 1; // Populate x, y, p for (std::size_t i = 0; i < num_chunks; ++i) { - x += double_non_native_integral_type(integral_type(public_input[i].data)) * pow; - y += double_non_native_integral_type( + x += extended_integral_type(integral_type(public_input[i].data)) * pow; + y += extended_integral_type( integral_type(public_input[i + num_chunks].data)) * pow; - p += double_non_native_integral_type( + p += extended_integral_type( integral_type(public_input[i + 2 * num_chunks].data)) * pow; pow <<= bit_size_chunk; } - double_non_native_integral_type r = x * y % p; + extended_integral_type r = x * y % p; auto assign_and_check = [&](auto &B, auto &raw_input) { raw_input.x = @@ -92,10 +92,11 @@ void test_mult(const std::vector &publi assert(pass == to_pass); if (to_pass) { - double_non_native_integral_type R = 0; + assert(pass == true); + extended_integral_type R = 0; pow = 1; for (std::size_t i = 0; i < num_chunks; i++) { - R += double_non_native_integral_type(integral_type(A.res[i].data)) * pow; + R += extended_integral_type(integral_type(A.res[i].data)) * pow; pow <<= bit_size_chunk; } #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED @@ -139,26 +140,25 @@ void mult_tests() { using value_type = typename BlueprintFieldType::value_type; using integral_type = typename BlueprintFieldType::integral_type; using foreign_value_type = typename NonNativeFieldType::value_type; - using foreign_integral_type = typename NonNativeFieldType::integral_type; typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> - double_non_native_integral_type; + extended_integral_type; static boost::random::mt19937 seed_seq; static nil::crypto3::random::algebraic_engine generate_random( seed_seq); boost::random::uniform_int_distribution<> t_dist(0, 1); - double_non_native_integral_type mask = - (double_non_native_integral_type(1) << bit_size_chunk) - 1; + extended_integral_type mask = + (extended_integral_type(1) << bit_size_chunk) - 1; for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input; foreign_value_type src_x = generate_random(), src_y = generate_random(); - double_non_native_integral_type x = double_non_native_integral_type( - foreign_integral_type(src_x.data)), - y = double_non_native_integral_type( - foreign_integral_type(src_y.data)), + extended_integral_type x = extended_integral_type( + integral_type(src_x.data)), + y = extended_integral_type( + integral_type(src_y.data)), extended_base = 1, ext_pow = extended_base << (num_chunks * bit_size_chunk), @@ -196,23 +196,23 @@ void mult_tests_to_fail() { using foreign_value_type = typename NonNativeFieldType::value_type; using foreign_integral_type = typename NonNativeFieldType::integral_type; typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> - double_non_native_integral_type; + extended_integral_type; static boost::random::mt19937 seed_seq; static nil::crypto3::random::algebraic_engine generate_random( seed_seq); boost::random::uniform_int_distribution<> t_dist(0, 1); - double_non_native_integral_type mask = - (double_non_native_integral_type(1) << bit_size_chunk) - 1; + extended_integral_type mask = + (extended_integral_type(1) << bit_size_chunk) - 1; for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input; foreign_value_type src_x = generate_random(), src_y = generate_random(); - double_non_native_integral_type - x = double_non_native_integral_type(foreign_integral_type(src_x.data)), - y = double_non_native_integral_type(foreign_integral_type(src_y.data)), + extended_integral_type + x = extended_integral_type(integral_type(src_x.data)), + y = extended_integral_type(integral_type(src_y.data)), extended_base = 1, ext_pow = extended_base << (num_chunks * bit_size_chunk), p = NonNativeFieldType::modulus, // Forcing the test to fail by substracting pp by 1 diff --git a/crypto3/libs/blueprint/test/bbf/detail/carry_on_addition.cpp b/crypto3/libs/blueprint/test/bbf/detail/carry_on_addition.cpp index a044bcff5..bafdf5447 100644 --- a/crypto3/libs/blueprint/test/bbf/detail/carry_on_addition.cpp +++ b/crypto3/libs/blueprint/test/bbf/detail/carry_on_addition.cpp @@ -72,7 +72,7 @@ void test_carry_on_addition(const std::vector +// Copyright (c) 2024 Antoine Cyr +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE choice_function_test + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace nil; +using namespace nil::blueprint; + +template +void test_choice_function( + const std::vector &public_input) { + using FieldType = BlueprintFieldType; + using integral_type = typename FieldType::integral_type; + using TYPE = typename FieldType::value_type; + + typename bbf::components::choice_function< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + raw_input.q = public_input[0]; + raw_input.x = std::vector(public_input.begin() + 1, + public_input.begin() + num_chunks + 1); + raw_input.y = + std::vector(public_input.begin() + num_chunks + 1, public_input.end()); + auto B = + bbf::circuit_builder( + num_chunks); + + auto [at, A, desc] = B.assign(raw_input); + bool pass = B.is_satisfied(at); + std::cout << "Is_satisfied = " << pass << std::endl; + + assert(pass == true); + + TYPE expected_res[num_chunks]; + for (std::size_t i = 0; i < num_chunks; i++) { + expected_res[i] = + (1 - raw_input.q) * raw_input.x[i] + raw_input.q * raw_input.y[i]; + } + + for (std::size_t i = 0; i < num_chunks; i++) { +#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "Expected res: " << std::dec << expected_res[i] << std::endl; + std::cout << "Real res: " << std::dec << A.res_z[i].data << std::endl; +#endif + assert(A.res_z[i].data == expected_res[i].data); + } +} + +template +void choice_function_tests() { + static boost::random::mt19937 seed_seq; + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); + boost::random::uniform_int_distribution<> t_dist(0, 1); + + for (std::size_t i = 0; i < RandomTestsAmount; i++) { + std::vector public_input = { + t_dist(seed_seq)}; // q is the first arg (0 or 1) + for (std::size_t j = 0; j < 2 * num_chunks; j++) { + public_input.push_back(generate_random()); + } + test_choice_function(public_input); + } +} + +constexpr static const std::size_t random_tests_amount = 3; + +BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) + +BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_choice_function_vesta_test) { + using field_type = typename crypto3::algebra::curves::vesta::base_field_type; + + choice_function_tests(); + + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); + + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); +} + +BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_choice_function_pallas_test) { + using field_type = typename crypto3::algebra::curves::pallas::base_field_type; + + choice_function_tests(); + + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); + + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); +} + +BOOST_AUTO_TEST_SUITE_END() From ffff957a330e880fbd9e1dbefde4980959355a48 Mon Sep 17 00:00:00 2001 From: Antoine Cyr Date: Thu, 9 Jan 2025 13:02:59 -0500 Subject: [PATCH 08/14] bbf negation_mod_p --- .../fields/non_native/negation_mod_p.hpp | 288 ++++++++++++++++++ crypto3/libs/blueprint/test/CMakeLists.txt | 1 + .../fields/non_native/negation_mod_p.cpp | 187 ++++++++++++ 3 files changed, 476 insertions(+) create mode 100644 crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp create mode 100644 crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp new file mode 100644 index 000000000..2c22daffc --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp @@ -0,0 +1,288 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Georgios Fotiadis +// Copyright (c) 2024 Alexey Yashunsky +// Copyright (c) 2024 Antoine Cyr +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// +// @file Declaration of interfaces for FRI verification array swapping component. +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BBF_COMPONENTS_NEGATION_MOD_P_HPP +#define CRYPTO3_BBF_COMPONENTS_NEGATION_MOD_P_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace nil { + namespace blueprint { + namespace bbf { + namespace components { + // Parameters: num_chunks = k, bit_size_chunk = b + // Finding the negative y of integer x, modulo p and checking that x + y = 0 mod p + // Input: x[0], ..., x[k-1], p[0], ..., p[k-1], pp[0], ..., pp[k-1], 0 (expects zero constant as input) + // Output: y[0], ..., y[k-1] + + template + struct negation_mod_p_raw_input { + using TYPE = typename FieldType::value_type; + std::vector x; + std::vector p; + std::vector pp; + TYPE zero; + }; + + template + class negation_mod_p : public generic_component { + using generic_component::allocate; + using generic_component::copy_constrain; + using generic_component::constrain; + using generic_component::lookup; + using component_type = generic_component; + + public: + using typename generic_component::TYPE; + using typename generic_component::context_type; + using typename generic_component::table_params; + using raw_input_type = + typename std::conditional, + std::tuple<>>::type; + using NonNativeIntegralExtendedVariant = + std::variant, + nil::crypto3::multiprecision::big_uint< + 2 * crypto3::algebra::curves::vesta:: + base_field_type::modulus_bits>>; + + template + struct NonNativeFieldTypeIndex; + + template<> + struct NonNativeFieldTypeIndex< + crypto3::algebra::curves::pallas::base_field_type> { + static constexpr std::size_t value = 0; + }; + + template<> + struct NonNativeFieldTypeIndex< + crypto3::algebra::curves::vesta::base_field_type> { + static constexpr std::size_t value = 1; + }; + + public: + std::vector inp_x; + std::vector inp_p; + std::vector inp_pp; + std::vector res; + + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::size_t witness = 3 * num_chunks + 1; + constexpr std::size_t public_inputs = 1; + constexpr std::size_t constants = 0; + // rows = 4096-1 so that lookup table is not too hard to fit and + // padding doesn't inflate the table + constexpr std::size_t rows = 4095; + return {witness, public_inputs, constants, rows}; + } + + static std::tuple, std::vector, + std::vector, TYPE> + form_input(context_type &context_object, raw_input_type raw_input, + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::vector input_x(num_chunks); + std::vector input_p(num_chunks); + std::vector input_pp(num_chunks); + TYPE input_zero; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; i++) { + input_x[i] = raw_input.x[i]; + input_p[i] = raw_input.p[i]; + input_pp[i] = raw_input.pp[i]; + } + input_zero = raw_input.zero; + } + for (std::size_t i = 0; i < num_chunks; i++) { + context_object.allocate(input_x[i], 0, i, + column_type::public_input); + context_object.allocate(input_p[i], 0, i + 1 * num_chunks, + column_type::public_input); + context_object.allocate(input_pp[i], 0, i + 2 * num_chunks, + column_type::public_input); + } + context_object.allocate(input_zero, 0, 3 * num_chunks, + column_type::public_input); + return std::make_tuple(input_x, input_p, input_pp, input_zero); + } + + negation_mod_p(context_type &context_object, + std::vector input_x, std::vector input_p, + std::vector input_pp, TYPE input_zero, + std::size_t num_chunks, std::size_t bit_size_chunk, + bool make_links = true) + : generic_component(context_object) { + using integral_type = typename FieldType::integral_type; + using extended_integral_type = + typename std::variant_alternative_t< + NonNativeFieldTypeIndex::value, + NonNativeIntegralExtendedVariant>; + + using Carry_On_Addition = + typename bbf::components::carry_on_addition; + using Choice_Function = + typename bbf::components::choice_function; + using Check_Mod_P = + typename bbf::components::check_mod_p; + using Range_Check = + typename bbf::components::range_check_multi; + + std::vector X(num_chunks); + std::vector Y(num_chunks); + std::vector P(num_chunks); + std::vector PP(num_chunks); + std::vector ZERO(num_chunks); + TYPE Q; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; ++i) { + X[i] = input_x[i]; + P[i] = input_p[i]; + PP[i] = input_pp[i]; + ZERO[i] = input_zero; + } + + extended_integral_type x = 0, y = 0, p = 0, pow = 1; + + // Populate x, p + for (std::size_t i = 0; i < num_chunks; ++i) { + x += extended_integral_type(integral_type(X[i].data)) * + pow; + p += extended_integral_type(integral_type(P[i].data)) * + pow; + pow <<= bit_size_chunk; + } + Q = (x == 0) ? 0 : 1; + y = (x == 0) ? 0 : p - x; // if x = 0, then y = 0 + + extended_integral_type mask = + (extended_integral_type(1) << bit_size_chunk) - 1; + for (std::size_t i = 0; i < num_chunks; ++i) { + Y[i] = TYPE(y & mask); + y >>= bit_size_chunk; + } + } + + for (std::size_t i = 0; i < num_chunks; ++i) { + allocate(X[i]); + allocate(Y[i]); + allocate(P[i]); + allocate(PP[i]); + allocate(ZERO[i]); + } + allocate(Q); + + Choice_Function cf = + Choice_Function(context_object, Q, ZERO, P, num_chunks); + + Carry_On_Addition ca = Carry_On_Addition( + context_object, X, Y, num_chunks, bit_size_chunk); + + // x + y = 0 or p + for (std::size_t i = 0; i < num_chunks; i++) { + copy_constrain(ca.res_z[i], cf.res_z[i]); + } + copy_constrain(ca.res_c, ZERO[0]); + + Range_Check rc = + Range_Check(context_object, Y, num_chunks, bit_size_chunk); + + Check_Mod_P cm = Check_Mod_P(context_object, Y, PP, ZERO[0], + num_chunks, bit_size_chunk); + + if (make_links) { + for (std::size_t i = 0; i < num_chunks; ++i) { + copy_constrain(X[i], input_x[i]); + copy_constrain(P[i], input_p[i]); + copy_constrain(PP[i], input_pp[i]); + copy_constrain(ZERO[i], input_zero); + } + } + + for (int i = 0; i < num_chunks; ++i) { + inp_x.push_back(input_x[i]); + inp_p.push_back(input_p[i]); + inp_pp.push_back(input_pp[i]); + } + for (int i = 0; i < num_chunks; ++i) { + res.push_back(Y[i]); + } + } + }; + + template + class pallas_negation_mod_p + : public negation_mod_p< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { + using Base = + negation_mod_p; + + public: + using Base::Base; + }; + + template + class vesta_negation_mod_p + : public negation_mod_p< + FieldType, stage, + crypto3::algebra::curves::vesta::base_field_type> { + using Base = + negation_mod_p; + + public: + using Base::Base; + }; + + } // namespace components + } // namespace bbf + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BBF_COMPONENTS_NEGATION_MOD_P_HPP diff --git a/crypto3/libs/blueprint/test/CMakeLists.txt b/crypto3/libs/blueprint/test/CMakeLists.txt index c905d4b51..1e263a4b3 100644 --- a/crypto3/libs/blueprint/test/CMakeLists.txt +++ b/crypto3/libs/blueprint/test/CMakeLists.txt @@ -104,6 +104,7 @@ set(COMMON_TEST_FILES "bbf/detail/choice_function" "bbf/algebra/fields/non_native/addition_mod_p" "bbf/algebra/fields/non_native/check_mod_p" + "bbf/algebra/fields/non_native/negation_mod_p" "bbf/algebra/fields/non_native/flexible_multiplication" ) diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp new file mode 100644 index 000000000..5ab9031ac --- /dev/null +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp @@ -0,0 +1,187 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Valeh Farzaliyev +// Copyright (c) 2024 Antoine Cyr +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE bbf_check_mod_p_test + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace nil; +using namespace nil::blueprint; + +template +void test_negation_mod_p( + const std::vector &public_input) { + using FieldType = BlueprintFieldType; + using TYPE = typename FieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> + extended_integral_type; + + extended_integral_type x = 0, p = 0, pow = 1; + // Populate x, p + for (std::size_t i = 0; i < num_chunks; ++i) { + x += extended_integral_type(integral_type(public_input[i].data)) * pow; + p += extended_integral_type(integral_type(public_input[i + num_chunks].data)) * + pow; + pow <<= bit_size_chunk; + } + + extended_integral_type y = (x == 0) ? 0 : p - x; // if x = 0, then y = 0 + + auto assign_and_check = [&](auto &B, auto &raw_input) { + raw_input.x = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.p = std::vector(public_input.begin() + num_chunks, + public_input.begin() + 2 * num_chunks); + raw_input.pp = std::vector(public_input.begin() + 2 * num_chunks, + public_input.begin() + 3 * num_chunks); + raw_input.zero = public_input[3 * num_chunks]; + + auto [at, A, desc] = B.assign(raw_input); + bool pass = B.is_satisfied(at); + std::cout << "Is_satisfied = " << pass << std::endl; + + assert(pass == true); + extended_integral_type Y = 0; + pow = 1; + for (std::size_t i = 0; i < num_chunks; i++) { + Y += extended_integral_type(integral_type(A.res[i].data)) * pow; + pow <<= bit_size_chunk; + } +#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "negation_mod_p test" << std::endl; + std::cout << "Expected res: " << std::dec << z << std::endl; + std::cout << "Real res: " << std::dec << Z << std::endl; +#endif + assert(y == Y); + }; + + if constexpr (std::is_same_v) { + typename bbf::components::vesta_negation_mod_p< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + + auto B = + bbf::circuit_builder(num_chunks, bit_size_chunk); + + assign_and_check(B, raw_input); + } else if constexpr (std::is_same_v< + NonNativeFieldType, + crypto3::algebra::curves::vesta::base_field_type>) { + typename bbf::components::pallas_negation_mod_p< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + auto B = + bbf::circuit_builder(num_chunks, bit_size_chunk); + + assign_and_check(B, raw_input); + } +} + +template +void negation_mod_p_tests() { + using value_type = typename BlueprintFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using foreign_value_type = typename NonNativeFieldType::value_type; + typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> + extended_integral_type; + + static boost::random::mt19937 seed_seq; + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); + boost::random::uniform_int_distribution<> t_dist(0, 1); + extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; + + for (std::size_t i = 0; i < RandomTestsAmount; i++) { + std::vector public_input; + + foreign_value_type src_x = generate_random(), src_y = generate_random(); + + extended_integral_type x = extended_integral_type(integral_type(src_x.data)), + y = extended_integral_type(integral_type(src_y.data)), + extended_base = 1, + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus; + extended_integral_type pp = ext_pow - p; + + public_input.resize(3 * num_chunks + 1); + for (std::size_t j = 0; j < num_chunks; j++) { + public_input[j] = value_type(x & mask); + x >>= bit_size_chunk; + + public_input[1 * num_chunks + j] = value_type(p & mask); + p >>= bit_size_chunk; + + public_input[2 * num_chunks + j] = value_type(pp & mask); + pp >>= bit_size_chunk; + } + public_input.push_back(value_type(0)); // the zero + + test_negation_mod_p(public_input); + } +} + +constexpr static const std::size_t random_tests_amount = 10; + +BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) + +BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_negation_mod_p_test) { + using pallas_field_type = typename crypto3::algebra::curves::pallas::base_field_type; + using vesta_field_type = typename crypto3::algebra::curves::vesta::base_field_type; + + negation_mod_p_tests(); + + negation_mod_p_tests(); + + negation_mod_p_tests(); + + negation_mod_p_tests(); + + negation_mod_p_tests(); + + negation_mod_p_tests(); +} + +BOOST_AUTO_TEST_SUITE_END() From cb6cff6c14772a99c70dcfcde15a15613bd78bb8 Mon Sep 17 00:00:00 2001 From: Antoine Cyr Date: Tue, 21 Jan 2025 16:12:11 -0500 Subject: [PATCH 09/14] ec double checkpoint bbf --- .../algebra/curves/weierstrass/ec_double.hpp | 375 ++++++++++++ .../curves/weierstrass/ec_double_old.hpp | 561 ++++++++++++++++++ .../fields/non_native/addition_mod_p.hpp | 4 +- .../non_native/flexible_multiplication.hpp | 4 +- .../fields/non_native/negation_mod_p.hpp | 4 +- crypto3/libs/blueprint/test/CMakeLists.txt | 1 + .../algebra/curves/weierstrass/ec_double.cpp | 204 +++++++ .../fields/non_native/addition_mod_p.cpp | 2 +- .../non_native/flexible_multiplication.cpp | 2 +- .../fields/non_native/negation_mod_p.cpp | 5 +- 10 files changed, 1151 insertions(+), 11 deletions(-) create mode 100644 crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp create mode 100644 crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double_old.hpp create mode 100644 crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp new file mode 100644 index 000000000..a66f50fd6 --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp @@ -0,0 +1,375 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Alexey Yashunsky +// Copyright (c) 2024 Antoine Cyr +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// +// @file Declaration of interfaces for FRI verification array swapping component. +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BBF_COMPONENTS_EC_DOUBLE_ECDSA_HPP +#define CRYPTO3_BBF_COMPONENTS_EC_DOUBLE_ECDSA_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nil { + namespace blueprint { + namespace bbf { + namespace components { + // Parameters: num_chunks = k, bit_size_chunk = b + // For a point Q = (x_Q,y_Q) from an elliptic curve over F[p] + // computes R = (x_R, y_R) = 2Q (EC doubling) + // Expects input as k-chunked values with b bits per chunk + // p' = 2^(kb) - p + // Input: xQ[0],...,xQ[k-1], yQ[0],...,yQ[k-1], p[0],...,p[k-1], + // pp[0],...,pp[k-1], 0 (expects zero constant as input) Output: + // xR[0],...,xR[k-1], yR[0],...,yR[k-1] + + template + struct ec_double_raw_input { + using TYPE = typename FieldType::value_type; + std::vector xQ; + std::vector yQ; + std::vector p; + std::vector pp; + TYPE zero; + }; + + template + class ec_double : public generic_component { + using generic_component::allocate; + using generic_component::copy_constrain; + using generic_component::constrain; + using generic_component::lookup; + using component_type = generic_component; + + public: + using typename generic_component::TYPE; + using typename generic_component::context_type; + using typename generic_component::table_params; + using raw_input_type = + typename std::conditional, + std::tuple<>>::type; + + public: + std::vector inp_xQ; + std::vector inp_yQ; + std::vector inp_p; + std::vector inp_pp; + std::vector res_xR; + std::vector res_yR; + + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::size_t witness = 4 * num_chunks + 1; + constexpr std::size_t public_inputs = 1; + constexpr std::size_t constants = 0; + // rows = 4096-1 so that lookup table is not too hard to fit and + // padding doesn't inflate the table + constexpr std::size_t rows = 4095; + return {witness, public_inputs, constants, rows}; + } + + static std::tuple, std::vector, + std::vector, std::vector, TYPE> + form_input(context_type &context_object, raw_input_type raw_input, + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::vector input_xQ(num_chunks); + std::vector input_yQ(num_chunks); + std::vector input_p(num_chunks); + std::vector input_pp(num_chunks); + TYPE input_zero; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; i++) { + input_xQ[i] = raw_input.xQ[i]; + input_yQ[i] = raw_input.yQ[i]; + input_p[i] = raw_input.p[i]; + input_pp[i] = raw_input.pp[i]; + } + input_zero = raw_input.zero; + } + for (std::size_t i = 0; i < num_chunks; i++) { + context_object.allocate(input_xQ[i], 0, i, + column_type::public_input); + context_object.allocate(input_yQ[i], 0, i + num_chunks, + column_type::public_input); + context_object.allocate(input_p[i], 0, i + 2 * num_chunks, + column_type::public_input); + context_object.allocate(input_pp[i], 0, i + 3 * num_chunks, + column_type::public_input); + } + context_object.allocate(input_zero, 0, 4 * num_chunks, + column_type::public_input); + return std::make_tuple(input_xQ, input_yQ, input_p, input_pp, + input_zero); + } + + ec_double(context_type &context_object, std::vector input_xQ, + std::vector input_yQ, std::vector input_p, + std::vector input_pp, TYPE input_zero, + std::size_t num_chunks, std::size_t bit_size_chunk, + bool make_links = true) + : generic_component(context_object) { + using integral_type = typename FieldType::integral_type; + using NON_NATIVE_TYPE = typename NonNativeFieldType::value_type; + using non_native_integral_type = + typename NonNativeFieldType::integral_type; + + using Choice_Function = + typename bbf::components::choice_function; + using Range_Check = + typename bbf::components::range_check_multi; + using Check_Mod_P = + typename bbf::components::check_mod_p; + using Addition_Mod_P = + typename bbf::components::addition_mod_p; + using Negation_Mod_P = + typename bbf::components::negation_mod_p; + using Multiplication_Mod_P = + typename bbf::components::flexible_multiplication; + + std::vector XQ(num_chunks); + std::vector YQ(num_chunks); + std::vector P(num_chunks); + std::vector PP(num_chunks); + TYPE ZERO; + + std::vector LAMBDA(num_chunks); + std::vector Z(num_chunks); + std::vector XR(num_chunks); + std::vector YR(num_chunks); + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; ++i) { + XQ[i] = input_xQ[i]; + YQ[i] = input_yQ[i]; + P[i] = input_p[i]; + PP[i] = input_pp[i]; + } + ZERO = input_zero; + + non_native_integral_type B = non_native_integral_type(1) + << bit_size_chunk, + pow = 0; + NON_NATIVE_TYPE xQ = 0, yQ = 0; + + for (std::size_t i = 0; i < num_chunks; ++i) { + xQ += non_native_integral_type( + integral_type(input_xQ[i].data)) * + pow; + yQ += non_native_integral_type( + integral_type(input_yQ[i].data)) * + pow; + pow <<= bit_size_chunk; + } + + NON_NATIVE_TYPE + lambda = + (yQ == 0) + ? 0 + : 3 * xQ * xQ * + ((2 * yQ).inversed()), // if yQ = 0, lambda = 0 + z = (yQ == 0) ? 0 : yQ.inversed(), // if yQ = 0, z = 0 + xR = lambda * lambda - 2 * xQ, + yR = lambda * (xQ - xR) - yQ; + + auto base_B = [&B,num_chunks](NON_NATIVE_TYPE x) { + std::vector res(num_chunks); + non_native_integral_type t = non_native_integral_type(x.data); + for (std::size_t i = 0; i < num_chunks; i++) { + res[i] = t % B; + t /= B; + } + return res; + }; + + LAMBDA = base_B(lambda); + Z = base_B(z); + XR = base_B(xR); + YR = base_B(yR); + } + + for (std::size_t i = 0; i < num_chunks; ++i) { + allocate(XQ[i]); + allocate(YQ[i]); + allocate(P[i]); + allocate(PP[i]); + + allocate(LAMBDA[i]); + allocate(Z[i]); + allocate(XR[i]); + allocate(YR[i]); + } + allocate(ZERO); + + auto check_chunked = + [&context_object,num_chunks,bit_size_chunk,PP,ZERO](std::vector x) { + Range_Check rc = Range_Check(context_object, x, + num_chunks, bit_size_chunk); + Check_Mod_P cm = Check_Mod_P(context_object, x, PP, ZERO, + num_chunks, bit_size_chunk); + }; + + // Copy constraint generation lambda expression + auto CopyConstrain = [this,num_chunks](std::vector x, std::vector y) { + for (std::size_t i = 0; i < num_chunks; i++) { + std::cout << "copy_constrain x[i]: " << x[i] << " , y[i]: " << y[i] << std::endl; + copy_constrain(x[i], y[i]); + } + }; + //YQ + //LAMBDA + //XQ + //2yQ * lambda = 3xQ^2 + + // perform range checks and mod p checks on all stored variables + check_chunked(LAMBDA); + check_chunked(Z); + check_chunked(XR); + check_chunked(YR); + + std::cout<< "t1" << std::endl; + Multiplication_Mod_P t1 = Multiplication_Mod_P( + context_object, YQ, LAMBDA, P, PP,num_chunks,bit_size_chunk); // t1 = yQ * lambda + std::cout<< "t2" << std::endl; + Addition_Mod_P t2 = + Addition_Mod_P(context_object, t1.res_z, t1.res_z, P, + PP,ZERO,num_chunks,bit_size_chunk); // t2 = t1 + t1 = 2yQ * lambda + std::cout<< "t3" << std::endl; + Addition_Mod_P t3 = Addition_Mod_P(context_object, XQ, XQ, P, PP, + ZERO,num_chunks,bit_size_chunk); // t3 = xQ + xQ = 2xQ + std::cout<< "t4" << std::endl; + Addition_Mod_P t4 = + Addition_Mod_P(context_object, XQ, t3.res_z, P, PP, + ZERO,num_chunks,bit_size_chunk); // t4 = xQ + t3 = 3xQ + std::cout<< "t5" << std::endl; + Multiplication_Mod_P t5 = Multiplication_Mod_P( + context_object, t4.res_z, XQ, P, PP,num_chunks,bit_size_chunk); // t5 = t4 * xQ = 3xQ^2 + std::cout<< "copy 1" << std::endl; + CopyConstrain(t2.res_z, t5.res_z); // 2yQ * lambda = 3xQ^2 + std::cout<< "t6" << std::endl; + Addition_Mod_P t6 = + Addition_Mod_P(context_object, XR, t3.res_z, P, PP, + ZERO,num_chunks,bit_size_chunk); // t6 = xR + t3 = xR + 2xQ + std::cout<< "t7" << std::endl; + Multiplication_Mod_P t7 = + Multiplication_Mod_P(context_object, LAMBDA, LAMBDA, P, + PP,num_chunks,bit_size_chunk); // t7 = lambda * lambda + std::cout<< "copy 2" << std::endl; + CopyConstrain(t6.res_z, t7.res_z); // xR + 2xQ = lambda^2 + std::cout<< "t8" << std::endl; + Addition_Mod_P t8 = Addition_Mod_P(context_object, YR, YQ, P, PP, + ZERO,num_chunks,bit_size_chunk); // t8 = yR + yQ + std::cout<< "t9" << std::endl; + Negation_Mod_P t9 = + Negation_Mod_P(context_object, XR, P, PP, ZERO,num_chunks,bit_size_chunk); // t9 = -xR + std::cout<< "t10" << std::endl; + Addition_Mod_P t10 = + Addition_Mod_P(context_object, XQ, t9.res_z, P, PP, + ZERO,num_chunks,bit_size_chunk); // t10 = xQ + t9 = xQ - xR + std::cout<< "t11" << std::endl; + Multiplication_Mod_P t11 = Multiplication_Mod_P( + context_object, LAMBDA, t10.res_z, P, + PP,num_chunks,bit_size_chunk); // t11 = lambda * t10 =lambda(xQ-xR) + std::cout<< "copy 3" << std::endl; + CopyConstrain(t8.res_z, t11.res_z); // yR + yQ = lambda(xQ - xR) + std::cout<< "t12" << std::endl; + Multiplication_Mod_P t12 = + Multiplication_Mod_P(context_object, Z, t1.res_z, P, PP, + num_chunks,bit_size_chunk); // t12 = z * t1 = z * yQ * lambda + std::cout<< "copy 4" << std::endl; + CopyConstrain(LAMBDA, t12.res_z); // lambda = z yQ lambda + + std::cout<< "make links" << std::endl; + if (make_links) { + for (std::size_t i = 0; i < num_chunks; ++i) { + copy_constrain(XQ[i], input_xQ[i]); + copy_constrain(YQ[i], input_yQ[i]); + copy_constrain(P[i], input_p[i]); + copy_constrain(PP[i], input_pp[i]); + } + copy_constrain(ZERO, input_zero); + } + + for (int i = 0; i < num_chunks; ++i) { + inp_xQ.push_back(input_xQ[i]); + inp_yQ.push_back(input_yQ[i]); + inp_pp.push_back(input_p[i]); + inp_pp.push_back(input_pp[i]); + } + for (int i = 0; i < num_chunks; ++i) { + res_xR.push_back(XR[i]); + res_yR.push_back(YR[i]); + } + } + }; + + template + class pallas_ec_double + : public ec_double< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { + using Base = + ec_double; + + public: + using Base::Base; + }; + + template + class vesta_ec_double + : public ec_double { + using Base = + ec_double; + + public: + using Base::Base; + }; + + } // namespace components + } // namespace bbf + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BBF_COMPONENTS_EC_DOUBLE_ECDSA_HPP diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double_old.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double_old.hpp new file mode 100644 index 000000000..596de4945 --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double_old.hpp @@ -0,0 +1,561 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Alexey Yashunsky +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// +// @file Declaration of interfaces for doubling an EC point over a non-native field +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_EC_DOUBLE_ECDSA_HPP +#define CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_EC_DOUBLE_ECDSA_HPP + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace nil { + namespace blueprint { + namespace components { + // Parameters: num_chunks = k, bit_size_chunk = b + // For a point Q = (x_Q,y_Q) from an elliptic curve over F[p] + // computes R = (x_R, y_R) = 2Q (EC doubling) + // Expects input as k-chunked values with b bits per chunk + // p' = 2^(kb) - p + // Input: xQ[0],...,xQ[k-1], yQ[0],...,yQ[k-1], p[0],...,p[k-1], pp[0],...,pp[k-1], 0 + // (expects zero constant as input) + // Output: xR[0],...,xR[k-1], yR[0],...,yR[k-1] + // + template + class ec_double; + + template + class ec_double, + BlueprintFieldType, + NonNativeFieldType, + num_chunks, + bit_size_chunk> + : public plonk_component { + + public: + using component_type = plonk_component; + + using var = typename component_type::var; + using manifest_type = plonk_component_manifest; + using range_check_component = range_check_multi, + BlueprintFieldType, num_chunks, bit_size_chunk>; + using check_mod_p_component = check_mod_p, + BlueprintFieldType, num_chunks, bit_size_chunk>; + using mult_mod_p_component = flexible_mult, + BlueprintFieldType, NonNativeFieldType, num_chunks, bit_size_chunk>; + using neg_mod_p_component = negation_mod_p, + BlueprintFieldType, NonNativeFieldType, num_chunks, bit_size_chunk>; + using add_mod_p_component = addition_mod_p, + BlueprintFieldType, NonNativeFieldType, num_chunks, bit_size_chunk>; + + // needed only for gate_manifest: + using choice_function_component = + choice_function, BlueprintFieldType, num_chunks>; + + class gate_manifest_type : public component_gate_manifest { + public: + std::uint32_t gates_amount() const override { + return ec_double::gates_amount; + } + }; + + static gate_manifest get_gate_manifest(std::size_t witness_amount) { + // NB: this uses a workaround, as manifest cannot process intersecting sets of gates. + // We merge only non-intersecting sets of gates which cover all gates in the circuit. + gate_manifest manifest = + gate_manifest(gate_manifest_type()) + // .merge_with(range_check_component::get_gate_manifest(witness_amount)) + // .merge_with(check_mod_p_component::get_gate_manifest(witness_amount)) + .merge_with(mult_mod_p_component::get_gate_manifest(witness_amount)) // constains everything except choice_function + .merge_with(choice_function_component::get_gate_manifest(witness_amount)) + // .merge_with(add_mod_p_component::get_gate_manifest(witness_amount)) + // .merge_with(neg_mod_p_component::get_gate_manifest(witness_amount)) + ; + return manifest; + } + + static manifest_type get_manifest() { + manifest_type manifest = manifest_type( + // all requirements come from sub-components, the component itself has no personal requirements + std::shared_ptr(new manifest_range_param(1,4*num_chunks,1)), // we need place for 4k variables + false // constant column not needed + ).merge_with(range_check_component::get_manifest()) + .merge_with(check_mod_p_component::get_manifest()) + .merge_with(mult_mod_p_component::get_manifest()) + .merge_with(add_mod_p_component::get_manifest()) + .merge_with(neg_mod_p_component::get_manifest()); + return manifest; + } + + constexpr static std::size_t get_rows_amount(std::size_t witness_amount) { + return (4*num_chunks)/witness_amount + ((4*num_chunks) % witness_amount > 0) // to store 4k variables + + 4*range_check_component::get_rows_amount(witness_amount) + + 4*check_mod_p_component::get_rows_amount(witness_amount) + + 5*mult_mod_p_component::get_rows_amount(witness_amount) + + 6*add_mod_p_component::get_rows_amount(witness_amount) + + 1*neg_mod_p_component::get_rows_amount(witness_amount) + ; + } + + constexpr static const std::size_t gates_amount = 0; + const std::size_t rows_amount = get_rows_amount(this->witness_amount()); + const std::string component_name = "non-native field EC point doubling function"; + + struct input_type { + var xQ[num_chunks], yQ[num_chunks], p[num_chunks], pp[num_chunks], zero; + + std::vector> all_vars() { + std::vector> res = {zero}; + for(std::size_t i = 0; i < num_chunks; i++) { + res.push_back(xQ[i]); + res.push_back(yQ[i]); + res.push_back(p[i]); + res.push_back(pp[i]); + } + return res; + } + }; + + struct result_type { + var xR[num_chunks], yR[num_chunks]; + + result_type(const ec_double &component, std::uint32_t start_row_index) { + const std::size_t WA = component.witness_amount(); + for(std::size_t i = 0; i < num_chunks; i++) { + xR[i] = var(component.W((2*num_chunks + i) % WA), + start_row_index + (2*num_chunks + i)/WA, false, var::column_type::witness); + yR[i] = var(component.W((3*num_chunks + i) % WA), + start_row_index + (3*num_chunks + i)/WA, false, var::column_type::witness); + } + } + + std::vector> all_vars() { + std::vector> res = {}; + for(std::size_t i = 0; i < num_chunks; i++) { + res.push_back(xR[i]); + res.push_back(yR[i]); + } + return res; + } + }; + + template + explicit ec_double(ContainerType witness) : component_type(witness, {}, {}, get_manifest()) {}; + + template + ec_double(WitnessContainerType witness, ConstantContainerType constant, + PublicInputContainerType public_input) : + component_type(witness, constant, public_input, get_manifest()) {}; + + ec_double( + std::initializer_list + witnesses, + std::initializer_list + constants, + std::initializer_list + public_inputs) : + component_type(witnesses, constants, public_inputs, get_manifest()) {}; + + std::map component_lookup_tables(){ + std::map lookup_tables; + lookup_tables["range_16bit/full"] = 0; + + return lookup_tables; + } + }; + + template + using plonk_ec_double = + ec_double< + crypto3::zk::snark::plonk_constraint_system, + BlueprintFieldType, + NonNativeFieldType, + num_chunks, + bit_size_chunk>; + + template + typename plonk_ec_double::result_type generate_assignments( + const plonk_ec_double &component, + assignment> + &assignment, + const typename plonk_ec_double::input_type + &instance_input, + const std::uint32_t start_row_index) { + + using component_type = plonk_ec_double; + using var = typename component_type::var; + + using range_check_type = typename component_type::range_check_component; + using check_mod_p_type = typename component_type::check_mod_p_component; + using mult_mod_p_type = typename component_type::mult_mod_p_component; + using add_mod_p_type = typename component_type::add_mod_p_component; + using neg_mod_p_type = typename component_type::neg_mod_p_component; + + using value_type = typename BlueprintFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using non_native_value_type = typename NonNativeFieldType::value_type; + using non_native_integral_type = typename NonNativeFieldType::integral_type; + + const std::size_t WA = component.witness_amount(); + + // instances of used subcomponents + range_check_type range_check_instance( component._W, component._C, component._PI); + check_mod_p_type check_mod_p_instance( component._W, component._C, component._PI); + mult_mod_p_type mult_mod_p_instance( component._W, component._C, component._PI); + add_mod_p_type add_mod_p_instance( component._W, component._C, component._PI); + neg_mod_p_type neg_mod_p_instance( component._W, component._C, component._PI); + + non_native_integral_type B = non_native_integral_type(1) << bit_size_chunk; + non_native_value_type xQ = 0, + yQ = 0; + + for(std::size_t i = num_chunks; i > 0; i--) { + xQ *= B; + xQ += non_native_integral_type(integral_type(var_value(assignment, instance_input.xQ[i-1]).data)); + yQ *= B; + yQ += non_native_integral_type(integral_type(var_value(assignment, instance_input.yQ[i-1]).data)); + } + + non_native_value_type lambda = (yQ == 0) ? 0 : 3*xQ*xQ*((2*yQ).inversed()), // if yQ = 0, lambda = 0 + z = (yQ == 0) ? 0 : yQ.inversed(), // if yQ = 0, z = 0 + xR = lambda*lambda - 2*xQ, + yR = lambda*(xQ - xR) - yQ; + + auto base_B = [&B](non_native_value_type x) { + std::array res; + non_native_integral_type t = non_native_integral_type(x.data); + for(std::size_t i = 0; i < num_chunks; i++) { + res[i] = t % B; + t /= B; + } + return res; + }; + + std::array lambda_B = base_B(lambda), + z_B = base_B(z), + xR_B = base_B(xR), + yR_B = base_B(yR); + // place to store locations for further reference + var xQ_var[num_chunks], yQ_var[num_chunks], + lambda_var[num_chunks], z_var[num_chunks], xR_var[num_chunks], yR_var[num_chunks]; + + // Store vars for future reference; fill cells with chunks of lambda, z, xR, yR consecutively + for(std::size_t i = 0; i < num_chunks; i++) { + xQ_var[i] = instance_input.xQ[i]; + yQ_var[i] = instance_input.yQ[i]; + + assignment.witness(component.W(i % WA), start_row_index + i/WA) = lambda_B[i]; + lambda_var[i] = var(component.W(i % WA), start_row_index + i/WA, false); + + assignment.witness(component.W((num_chunks + i) % WA), start_row_index + (num_chunks + i)/WA) = z_B[i]; + z_var[i] = var(component.W((num_chunks + i) % WA), start_row_index + (num_chunks + i)/WA,false); + + assignment.witness(component.W((2*num_chunks + i) % WA), start_row_index + (2*num_chunks + i)/WA) = xR_B[i]; + xR_var[i] = var(component.W((2*num_chunks + i) % WA), start_row_index + (2*num_chunks + i)/WA,false); + + assignment.witness(component.W((3*num_chunks + i) % WA), start_row_index + (3*num_chunks + i)/WA) = yR_B[i]; + yR_var[i] = var(component.W((3*num_chunks + i) % WA), start_row_index + (3*num_chunks + i)/WA,false); + } + + // the number of rows used up to now + std::size_t current_row_shift = (4*num_chunks)/WA + ((4*num_chunks) % WA > 0); + + auto check_chunked_var = [&assignment, &instance_input, &range_check_instance, &check_mod_p_instance, + &start_row_index, ¤t_row_shift ] (var x[num_chunks]) { + typename range_check_type::input_type range_check_input; + for(std::size_t i = 0; i < num_chunks; i++) { + range_check_input.x[i] = x[i]; + } + generate_assignments(range_check_instance, assignment, range_check_input, start_row_index + current_row_shift); + current_row_shift += range_check_instance.rows_amount; + + typename check_mod_p_type::input_type mod_p_check_input; + for(std::size_t i = 0; i < num_chunks; i++) { + mod_p_check_input.x[i] = x[i]; + mod_p_check_input.pp[i] = instance_input.pp[i]; + } + mod_p_check_input.zero = instance_input.zero; + generate_assignments(check_mod_p_instance, assignment, mod_p_check_input, + start_row_index + current_row_shift); // check_mod_p + current_row_shift += check_mod_p_instance.rows_amount; + }; + // perform range checks and mod p checks on all stored variables + check_chunked_var(lambda_var); + check_chunked_var(z_var); + check_chunked_var(xR_var); + check_chunked_var(yR_var); + + // assignment generation lambda expressions for mod p arithemetic + auto MultModP = [&instance_input, &mult_mod_p_instance, &assignment, &start_row_index, ¤t_row_shift] + (var x[num_chunks], var y[num_chunks]) { + typename mult_mod_p_type::input_type mult_input; + for(std::size_t i = 0; i < num_chunks; i++) { + mult_input.x[i] = x[i]; + mult_input.y[i] = y[i]; + mult_input.p[i] = instance_input.p[i]; + mult_input.pp[i] = instance_input.pp[i]; + } + mult_input.zero = instance_input.zero; + typename mult_mod_p_type::result_type res = generate_assignments(mult_mod_p_instance, assignment, mult_input, + start_row_index + current_row_shift); + current_row_shift += mult_mod_p_instance.rows_amount; + return res; + }; + auto AddModP = [&instance_input, &add_mod_p_instance, &assignment, &start_row_index, ¤t_row_shift] + (var x[num_chunks], var y[num_chunks]) { + typename add_mod_p_type::input_type add_input; + for(std::size_t i = 0; i < num_chunks; i++) { + add_input.x[i] = x[i]; + add_input.y[i] = y[i]; + add_input.p[i] = instance_input.p[i]; + add_input.pp[i] = instance_input.pp[i]; + } + add_input.zero = instance_input.zero; + typename add_mod_p_type::result_type res = generate_assignments(add_mod_p_instance, assignment, add_input, + start_row_index + current_row_shift); + current_row_shift += add_mod_p_instance.rows_amount; + return res; + }; + auto NegModP = [&instance_input, &neg_mod_p_instance, &assignment, &start_row_index, ¤t_row_shift] + (var x[num_chunks]) { + typename neg_mod_p_type::input_type neg_input; + for(std::size_t i = 0; i < num_chunks; i++) { + neg_input.x[i] = x[i]; + neg_input.p[i] = instance_input.p[i]; + neg_input.pp[i] = instance_input.pp[i]; + } + neg_input.zero = instance_input.zero; + typename neg_mod_p_type::result_type res = generate_assignments(neg_mod_p_instance, assignment, neg_input, + start_row_index + current_row_shift); + current_row_shift += neg_mod_p_instance.rows_amount; + return res; + }; + + typename mult_mod_p_type::result_type t1 = MultModP(yQ_var,lambda_var); // t1 = yQ * lambda + typename add_mod_p_type::result_type t2 = AddModP(t1.r,t1.r); // t2 = t1 + t1 = 2yQ * lambda + typename add_mod_p_type::result_type t3 = AddModP(xQ_var,xQ_var); // t3 = xQ + xQ = 2xQ + typename add_mod_p_type::result_type t4 = AddModP(xQ_var,t3.z); // t4 = xQ + t3 = 3xQ + typename mult_mod_p_type::result_type t5 = MultModP(t4.z,xQ_var); // t5 = t4 * xQ = 3xQ^2 + typename add_mod_p_type::result_type t6 = AddModP(xR_var,t3.z); // t6 = xR + t3 = xR + 2xQ + typename mult_mod_p_type::result_type t7 = MultModP(lambda_var,lambda_var); // t7 = lambda * lambda + typename add_mod_p_type::result_type t8 = AddModP(yR_var,yQ_var); // t8 = yR + yQ + typename neg_mod_p_type::result_type t9 = NegModP(xR_var); // t9 = -xR + typename add_mod_p_type::result_type t10= AddModP(xQ_var,t9.y); // t10 = xQ + t9 = xQ - xR + typename mult_mod_p_type::result_type t11= MultModP(lambda_var,t10.z); // t11 = lambda * t10 =lambda(xQ-xR) + typename mult_mod_p_type::result_type t12= MultModP(z_var,t1.r); // t12 = z * t1 = z * yQ * lambda + + return typename component_type::result_type(component, start_row_index); + } + + template + std::vector generate_gates( + const plonk_ec_double &component, + circuit> &bp, + assignment> + &assignment, + const typename plonk_ec_double::input_type + &instance_input) { + + // never actually called + return {}; + } + + template + void generate_copy_constraints( + const plonk_ec_double &component, + circuit> &bp, + assignment> + &assignment, + const typename plonk_ec_double::input_type &instance_input, + const std::size_t start_row_index) { + + // all copy constraints are moved to generate_circuit + } + + template + typename plonk_ec_double::result_type generate_circuit( + const plonk_ec_double &component, + circuit> &bp, + assignment> + &assignment, + const typename plonk_ec_double::input_type &instance_input, + const std::size_t start_row_index) { + using component_type = plonk_ec_double; + using var = typename component_type::var; + + using range_check_type = typename component_type::range_check_component; + using check_mod_p_type = typename component_type::check_mod_p_component; + using mult_mod_p_type = typename component_type::mult_mod_p_component; + using add_mod_p_type = typename component_type::add_mod_p_component; + using neg_mod_p_type = typename component_type::neg_mod_p_component; + + using value_type = typename BlueprintFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using non_native_value_type = typename NonNativeFieldType::value_type; + using non_native_integral_type = typename NonNativeFieldType::integral_type; + + const std::size_t WA = component.witness_amount(); + + // instances of used subcomponents + range_check_type range_check_instance( component._W, component._C, component._PI); + check_mod_p_type check_mod_p_instance( component._W, component._C, component._PI); + mult_mod_p_type mult_mod_p_instance( component._W, component._C, component._PI); + add_mod_p_type add_mod_p_instance( component._W, component._C, component._PI); + neg_mod_p_type neg_mod_p_instance( component._W, component._C, component._PI); + + var xQ_var[num_chunks], yQ_var[num_chunks], + lambda_var[num_chunks], z_var[num_chunks], xR_var[num_chunks], yR_var[num_chunks]; + + for(std::size_t i = 0; i < num_chunks; i++) { + xQ_var[i] = instance_input.xQ[i]; + yQ_var[i] = instance_input.yQ[i]; + lambda_var[i] = var(component.W(i % WA), start_row_index + i/WA, false); + z_var[i] = var(component.W((num_chunks + i) % WA), start_row_index + (num_chunks + i)/WA,false); + xR_var[i] = var(component.W((2*num_chunks + i) % WA), start_row_index + (2*num_chunks + i)/WA,false); + yR_var[i] = var(component.W((3*num_chunks + i) % WA), start_row_index + (3*num_chunks + i)/WA,false); + } + + // the number of rows used by data storage + std::size_t current_row_shift = (4*num_chunks)/WA + ((4*num_chunks) % WA > 0); + + auto check_chunked_var = [&bp, &assignment, &instance_input, &range_check_instance, &check_mod_p_instance, + &start_row_index, ¤t_row_shift ] (var x[num_chunks]) { + typename range_check_type::input_type range_check_input; + for(std::size_t i = 0; i < num_chunks; i++) { + range_check_input.x[i] = x[i]; + } + generate_circuit(range_check_instance, bp, assignment, range_check_input, start_row_index + current_row_shift); + current_row_shift += range_check_instance.rows_amount; + + typename check_mod_p_type::input_type mod_p_check_input; + for(std::size_t i = 0; i < num_chunks; i++) { + mod_p_check_input.x[i] = x[i]; + mod_p_check_input.pp[i] = instance_input.pp[i]; + } + mod_p_check_input.zero = instance_input.zero; + generate_circuit(check_mod_p_instance, bp, assignment, mod_p_check_input, + start_row_index + current_row_shift); // check_mod_p + current_row_shift += check_mod_p_instance.rows_amount; + }; + // perform range checks and mod p checks on all stored variables + check_chunked_var(lambda_var); + check_chunked_var(z_var); + check_chunked_var(xR_var); + check_chunked_var(yR_var); + + // circuit generation lambda expressions for mod p arithemetic + auto MultModP = [&instance_input, &mult_mod_p_instance, &bp, &assignment, &start_row_index, ¤t_row_shift] + (var x[num_chunks], var y[num_chunks]) { + typename mult_mod_p_type::input_type mult_input; + for(std::size_t i = 0; i < num_chunks; i++) { + mult_input.x[i] = x[i]; + mult_input.y[i] = y[i]; + mult_input.p[i] = instance_input.p[i]; + mult_input.pp[i] = instance_input.pp[i]; + } + mult_input.zero = instance_input.zero; + typename mult_mod_p_type::result_type res = generate_circuit(mult_mod_p_instance, bp, assignment, mult_input, + start_row_index + current_row_shift); + current_row_shift += mult_mod_p_instance.rows_amount; + return res; + }; + auto AddModP = [&instance_input, &add_mod_p_instance, &bp, &assignment, &start_row_index, ¤t_row_shift] + (var x[num_chunks], var y[num_chunks]) { +//std::cout << "Add starting at row " << (start_row_index + current_row_shift) << "\n"; + typename add_mod_p_type::input_type add_input; + for(std::size_t i = 0; i < num_chunks; i++) { + add_input.x[i] = x[i]; + add_input.y[i] = y[i]; + add_input.p[i] = instance_input.p[i]; + add_input.pp[i] = instance_input.pp[i]; + } + add_input.zero = instance_input.zero; + typename add_mod_p_type::result_type res = generate_circuit(add_mod_p_instance, bp, assignment, add_input, + start_row_index + current_row_shift); + current_row_shift += add_mod_p_instance.rows_amount; +//std::cout << "Add ending at row " << (start_row_index + current_row_shift) << "\n"; + return res; + }; + auto NegModP = [&instance_input, &neg_mod_p_instance, &bp, &assignment, &start_row_index, ¤t_row_shift] + (var x[num_chunks]) { + typename neg_mod_p_type::input_type neg_input; + for(std::size_t i = 0; i < num_chunks; i++) { + neg_input.x[i] = x[i]; + neg_input.p[i] = instance_input.p[i]; + neg_input.pp[i] = instance_input.pp[i]; + } + neg_input.zero = instance_input.zero; + typename neg_mod_p_type::result_type res = generate_circuit(neg_mod_p_instance, bp, assignment, neg_input, + start_row_index + current_row_shift); + current_row_shift += neg_mod_p_instance.rows_amount; + return res; + }; + + // Copy constraint generation lambda expression + auto CopyConstrain = [&bp](var x[num_chunks], var y[num_chunks]) { + for(std::size_t i = 0; i < num_chunks; i++) { + bp.add_copy_constraint({x[i], y[i]}); + } + }; + + typename mult_mod_p_type::result_type t1 = MultModP(yQ_var,lambda_var); // t1 = yQ * lambda + typename add_mod_p_type::result_type t2 = AddModP(t1.r,t1.r); // t2 = t1 + t1 = 2yQ * lambda + typename add_mod_p_type::result_type t3 = AddModP(xQ_var,xQ_var); // t3 = xQ + xQ = 2xQ + typename add_mod_p_type::result_type t4 = AddModP(xQ_var,t3.z); // t4 = xQ + t3 = 3xQ + typename mult_mod_p_type::result_type t5 = MultModP(t4.z,xQ_var); // t5 = t4 * xQ = 3xQ^2 + CopyConstrain(t2.z, t5.r); // 2yQ lambda = 3xQ^2 + typename add_mod_p_type::result_type t6 = AddModP(xR_var,t3.z); // t6 = xR + t3 = xR + 2xQ + typename mult_mod_p_type::result_type t7 = MultModP(lambda_var,lambda_var); // t7 = lambda * lambda + CopyConstrain(t6.z, t7.r); // xR + 2xQ = lambda^2 + typename add_mod_p_type::result_type t8 = AddModP(yR_var,yQ_var); // t8 = yR + yQ + typename neg_mod_p_type::result_type t9 = NegModP(xR_var); // t9 = -xR + typename add_mod_p_type::result_type t10= AddModP(xQ_var,t9.y); // t10 = xQ + t9 = xQ - xR + typename mult_mod_p_type::result_type t11= MultModP(lambda_var,t10.z); // t11 = lambda * t10 =lambda(xQ-xR) + CopyConstrain(t8.z, t11.r); // yR + yQ = lambda(xQ - xR) + typename mult_mod_p_type::result_type t12= MultModP(z_var,t1.r); // t12 = z * t1 = z * yQ * lambda + CopyConstrain(lambda_var, t12.r); // lambda = z yQ lambda + + generate_copy_constraints(component, bp, assignment, instance_input, start_row_index); // does nothing, may be skipped? + + return typename component_type::result_type(component, start_row_index); + } + + } // namespace components + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_EC_DOUBLE_ECDSA_HPP \ No newline at end of file diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp index 708f26394..5624e025b 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp @@ -111,7 +111,7 @@ namespace nil { std::vector inp_y; std::vector inp_p; std::vector inp_pp; - std::vector res; + std::vector res_z; static table_params get_minimal_requirements( std::size_t num_chunks, std::size_t bit_size_chunk) { @@ -277,7 +277,7 @@ namespace nil { inp_pp.push_back(input_pp[i]); } for (int i = 0; i < num_chunks; ++i) { - res.push_back(Z[i]); + res_z.push_back(Z[i]); } } }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp index c5a8b112f..5cecbdc60 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp @@ -86,7 +86,7 @@ namespace nil { std::vector inp_y; std::vector inp_p; std::vector inp_pp; - std::vector res; + std::vector res_z; static table_params get_minimal_requirements(std::size_t num_chunks,std::size_t bit_size_chunk) { //The 6 variables chunks fit in 2 rows, and there is a 3rd additionnal row available for the constraint values @@ -321,7 +321,7 @@ namespace nil { inp_pp.push_back(input_pp[i]); } for (int i = 0; i < num_chunks; ++i) { - res.push_back(R[i]); + res_z.push_back(R[i]); } } diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp index 2c22daffc..dafb76010 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp @@ -107,7 +107,7 @@ namespace nil { std::vector inp_x; std::vector inp_p; std::vector inp_pp; - std::vector res; + std::vector res_z; static table_params get_minimal_requirements( std::size_t num_chunks, std::size_t bit_size_chunk) { @@ -249,7 +249,7 @@ namespace nil { inp_pp.push_back(input_pp[i]); } for (int i = 0; i < num_chunks; ++i) { - res.push_back(Y[i]); + res_z.push_back(Y[i]); } } }; diff --git a/crypto3/libs/blueprint/test/CMakeLists.txt b/crypto3/libs/blueprint/test/CMakeLists.txt index 1e263a4b3..afa4cd20d 100644 --- a/crypto3/libs/blueprint/test/CMakeLists.txt +++ b/crypto3/libs/blueprint/test/CMakeLists.txt @@ -106,6 +106,7 @@ set(COMMON_TEST_FILES "bbf/algebra/fields/non_native/check_mod_p" "bbf/algebra/fields/non_native/negation_mod_p" "bbf/algebra/fields/non_native/flexible_multiplication" + "bbf/algebra/curves/weierstrass/ec_double" ) set(NON_NATIVE_TESTS_FILES diff --git a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp new file mode 100644 index 000000000..8392ceef6 --- /dev/null +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp @@ -0,0 +1,204 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Antoine Cyr +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE bbf_check_mod_p_test + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace nil; +using namespace nil::blueprint; + +template +void test_ec_double( + const std::vector &public_input) { + using FieldType = BlueprintFieldType; + using TYPE = typename FieldType::value_type; + using NON_NATIVE_TYPE = typename NonNativeFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> + extended_integral_type; + + extended_integral_type B = extended_integral_type(1) + << bit_size_chunk, + pow = 0; + NON_NATIVE_TYPE xQ = 0, yQ = 0; + + for (std::size_t i = 0; i < num_chunks; ++i) { + xQ += extended_integral_type(integral_type(public_input[i].data)) * pow; + yQ += extended_integral_type(integral_type(public_input[i + num_chunks].data)) * + pow <<= bit_size_chunk; + } + + + NON_NATIVE_TYPE lambda = + (yQ == 0) + ? 0 + : 3 * xQ * xQ * + ((2 * yQ).inversed()), // if yQ = 0, lambda = 0 + z = (yQ == 0) ? 0 : yQ.inversed(), // if yQ = 0, z = 0 + expected_xR = lambda * lambda - 2 * xQ, expected_yR = lambda * (xQ - expected_xR) - yQ; + + auto assign_and_check = [&](auto &B, auto &raw_input) { + raw_input.xQ = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.yQ = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.p = std::vector(public_input.begin() + num_chunks, + public_input.begin() + 2 * num_chunks); + raw_input.pp = std::vector(public_input.begin() + 2 * num_chunks, + public_input.begin() + 3 * num_chunks); + raw_input.zero = public_input[3 * num_chunks]; + + auto [at, A, desc] = B.assign(raw_input); + bool pass = B.is_satisfied(at); + std::cout << "Is_satisfied = " << pass << std::endl; + + assert(pass == true); + extended_integral_type xR = 0; + extended_integral_type yR = 0; + pow = 1; + for (std::size_t i = 0; i < num_chunks; i++) { + xR += extended_integral_type(integral_type(A.res_xR[i].data)) * pow; + yR += extended_integral_type(integral_type(A.res_yR[i].data)) * pow; + pow <<= bit_size_chunk; + } +#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "negation_mod_p test" << std::endl; + std::cout << "Expected xR - yR: " << std::dec << expected_xR.data << " - " << expected_yR.data << std::endl; + std::cout << "Real res xR - yR: " << std::dec << xR << " - " << yR << std::endl; +#endif + assert(xR == expected_xR.data); + assert(yR == expected_yR.data); + }; + + if constexpr (std::is_same_v) { + typename bbf::components::vesta_ec_double< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + + auto B = + bbf::circuit_builder(num_chunks, bit_size_chunk); + + assign_and_check(B, raw_input); + } else if constexpr (std::is_same_v< + NonNativeFieldType, + crypto3::algebra::curves::vesta::base_field_type>) { + typename bbf::components::pallas_ec_double< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + auto B = + bbf::circuit_builder(num_chunks, bit_size_chunk); + + assign_and_check(B, raw_input); + } +} + +template +void ec_double_tests() { + using value_type = typename BlueprintFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using foreign_value_type = typename NonNativeFieldType::value_type; + typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> + extended_integral_type; + + static boost::random::mt19937 seed_seq; + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); + boost::random::uniform_int_distribution<> t_dist(0, 1); + extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; + + for (std::size_t i = 0; i < RandomTestsAmount; i++) { + std::vector public_input; + + foreign_value_type src_x = generate_random(), src_y = generate_random(); + + extended_integral_type xQ = extended_integral_type(integral_type(src_x.data)), + yQ = extended_integral_type(integral_type(src_y.data)), + extended_base = 1, + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus; + extended_integral_type pp = ext_pow - p; + + public_input.resize(3 * num_chunks + 1); + for (std::size_t j = 0; j < num_chunks; j++) { + public_input[j] = value_type(xQ & mask); + xQ >>= bit_size_chunk; + + public_input[j] = value_type(yQ & mask); + yQ >>= bit_size_chunk; + + public_input[1 * num_chunks + j] = value_type(p & mask); + p >>= bit_size_chunk; + + public_input[2 * num_chunks + j] = value_type(pp & mask); + pp >>= bit_size_chunk; + } + public_input.push_back(value_type(0)); // the zero + + test_ec_double(public_input); + } +} + +constexpr static const std::size_t random_tests_amount = 10; + +BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) + +BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_ec_double_test) { + using pallas_field_type = typename crypto3::algebra::curves::pallas::base_field_type; + using vesta_field_type = typename crypto3::algebra::curves::vesta::base_field_type; + + ec_double_tests(); + + ec_double_tests(); + + ec_double_tests(); + + ec_double_tests(); + + ec_double_tests(); + + ec_double_tests(); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp index 77131a719..109cfaa9a 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp @@ -87,7 +87,7 @@ void test_addition_mod_p(const std::vector &publi extended_integral_type R = 0; pow = 1; for (std::size_t i = 0; i < num_chunks; i++) { - R += extended_integral_type(integral_type(A.res[i].data)) * pow; + R += extended_integral_type(integral_type(A.res_z[i].data)) * pow; pow <<= bit_size_chunk; } #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp index 5ab9031ac..030e4079e 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp @@ -78,7 +78,7 @@ void test_negation_mod_p( extended_integral_type Y = 0; pow = 1; for (std::size_t i = 0; i < num_chunks; i++) { - Y += extended_integral_type(integral_type(A.res[i].data)) * pow; + Y += extended_integral_type(integral_type(A.res_z[i].data)) * pow; pow <<= bit_size_chunk; } #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED @@ -130,10 +130,9 @@ void negation_mod_p_tests() { for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input; - foreign_value_type src_x = generate_random(), src_y = generate_random(); + foreign_value_type src_x = generate_random(); extended_integral_type x = extended_integral_type(integral_type(src_x.data)), - y = extended_integral_type(integral_type(src_y.data)), extended_base = 1, ext_pow = extended_base << (num_chunks * bit_size_chunk), p = NonNativeFieldType::modulus; From 32102d2dd538ea277e758ae22c5e2b17a426505f Mon Sep 17 00:00:00 2001 From: Antoine Cyr Date: Thu, 23 Jan 2025 20:56:49 -0500 Subject: [PATCH 10/14] ec_double bbf --- .../algebra/curves/weierstrass/ec_double.hpp | 193 +++++++++--------- .../non_native/flexible_multiplication.hpp | 4 +- .../algebra/curves/weierstrass/ec_double.cpp | 140 ++++++------- .../fields/non_native/addition_mod_p.cpp | 8 +- .../non_native/flexible_multiplication.cpp | 9 +- .../fields/non_native/negation_mod_p.cpp | 8 +- 6 files changed, 183 insertions(+), 179 deletions(-) diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp index a66f50fd6..7518c6203 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp @@ -70,7 +70,7 @@ namespace nil { }; template + typename NonNativeFieldType> class ec_double : public generic_component { using generic_component::allocate; using generic_component::copy_constrain; @@ -78,16 +78,16 @@ namespace nil { using generic_component::lookup; using component_type = generic_component; - public: + public: using typename generic_component::TYPE; using typename generic_component::context_type; using typename generic_component::table_params; using raw_input_type = typename std::conditional, - std::tuple<>>::type; + ec_double_raw_input, + std::tuple<>>::type; - public: + public: std::vector inp_xQ; std::vector inp_yQ; std::vector inp_p; @@ -103,13 +103,13 @@ namespace nil { // rows = 4096-1 so that lookup table is not too hard to fit and // padding doesn't inflate the table constexpr std::size_t rows = 4095; - return {witness, public_inputs, constants, rows}; + return { witness, public_inputs, constants, rows }; } static std::tuple, std::vector, - std::vector, std::vector, TYPE> - form_input(context_type &context_object, raw_input_type raw_input, - std::size_t num_chunks, std::size_t bit_size_chunk) { + std::vector, std::vector, TYPE> + form_input(context_type& context_object, raw_input_type raw_input, + std::size_t num_chunks, std::size_t bit_size_chunk) { std::vector input_xQ(num_chunks); std::vector input_yQ(num_chunks); std::vector input_p(num_chunks); @@ -127,30 +127,29 @@ namespace nil { } for (std::size_t i = 0; i < num_chunks; i++) { context_object.allocate(input_xQ[i], 0, i, - column_type::public_input); + column_type::public_input); context_object.allocate(input_yQ[i], 0, i + num_chunks, - column_type::public_input); + column_type::public_input); context_object.allocate(input_p[i], 0, i + 2 * num_chunks, - column_type::public_input); + column_type::public_input); context_object.allocate(input_pp[i], 0, i + 3 * num_chunks, - column_type::public_input); + column_type::public_input); } context_object.allocate(input_zero, 0, 4 * num_chunks, - column_type::public_input); + column_type::public_input); return std::make_tuple(input_xQ, input_yQ, input_p, input_pp, - input_zero); + input_zero); } - ec_double(context_type &context_object, std::vector input_xQ, - std::vector input_yQ, std::vector input_p, - std::vector input_pp, TYPE input_zero, - std::size_t num_chunks, std::size_t bit_size_chunk, - bool make_links = true) + ec_double(context_type& context_object, std::vector input_xQ, + std::vector input_yQ, std::vector input_p, + std::vector input_pp, TYPE input_zero, + std::size_t num_chunks, std::size_t bit_size_chunk, + bool make_links = true) : generic_component(context_object) { using integral_type = typename FieldType::integral_type; using NON_NATIVE_TYPE = typename NonNativeFieldType::value_type; - using non_native_integral_type = - typename NonNativeFieldType::integral_type; + using non_native_integral_type = typename NonNativeFieldType::integral_type; using Choice_Function = typename bbf::components::choice_function; @@ -159,12 +158,12 @@ namespace nil { using Check_Mod_P = typename bbf::components::check_mod_p; using Addition_Mod_P = - typename bbf::components::addition_mod_p; + typename bbf::components::addition_mod_p; using Negation_Mod_P = - typename bbf::components::negation_mod_p; + typename bbf::components::negation_mod_p; using Multiplication_Mod_P = typename bbf::components::flexible_multiplication; + stage, NonNativeFieldType>; std::vector XQ(num_chunks); std::vector YQ(num_chunks); @@ -186,45 +185,44 @@ namespace nil { } ZERO = input_zero; - non_native_integral_type B = non_native_integral_type(1) - << bit_size_chunk, - pow = 0; + non_native_integral_type pow = 1; NON_NATIVE_TYPE xQ = 0, yQ = 0; for (std::size_t i = 0; i < num_chunks; ++i) { xQ += non_native_integral_type( - integral_type(input_xQ[i].data)) * - pow; + integral_type(input_xQ[i].data)) * + pow; yQ += non_native_integral_type( - integral_type(input_yQ[i].data)) * - pow; + integral_type(input_yQ[i].data)) * + pow; pow <<= bit_size_chunk; } NON_NATIVE_TYPE - lambda = + lambda = (yQ == 0) - ? 0 - : 3 * xQ * xQ * - ((2 * yQ).inversed()), // if yQ = 0, lambda = 0 + ? 0 + : 3 * xQ * xQ * + ((2 * yQ).inversed()), // if yQ = 0, lambda = 0 z = (yQ == 0) ? 0 : yQ.inversed(), // if yQ = 0, z = 0 xR = lambda * lambda - 2 * xQ, - yR = lambda * (xQ - xR) - yQ; + yR = lambda * (xQ - xR) - yQ; - auto base_B = [&B,num_chunks](NON_NATIVE_TYPE x) { + auto base = [num_chunks, bit_size_chunk](NON_NATIVE_TYPE x) { std::vector res(num_chunks); - non_native_integral_type t = non_native_integral_type(x.data); + non_native_integral_type mask = (non_native_integral_type(1) << bit_size_chunk) - 1; + non_native_integral_type x_value = non_native_integral_type(x.data); for (std::size_t i = 0; i < num_chunks; i++) { - res[i] = t % B; - t /= B; + res[i] = TYPE(x_value & mask); + x_value >>= bit_size_chunk; } return res; - }; + }; - LAMBDA = base_B(lambda); - Z = base_B(z); - XR = base_B(xR); - YR = base_B(yR); + LAMBDA = base(lambda); + Z = base(z); + XR = base(xR); + YR = base(yR); } for (std::size_t i = 0; i < num_chunks; ++i) { @@ -241,24 +239,20 @@ namespace nil { allocate(ZERO); auto check_chunked = - [&context_object,num_chunks,bit_size_chunk,PP,ZERO](std::vector x) { - Range_Check rc = Range_Check(context_object, x, - num_chunks, bit_size_chunk); - Check_Mod_P cm = Check_Mod_P(context_object, x, PP, ZERO, - num_chunks, bit_size_chunk); + [&context_object, num_chunks, bit_size_chunk, PP, ZERO](std::vector x) { + Range_Check rc = Range_Check(context_object, x, + num_chunks, bit_size_chunk); + Check_Mod_P cm = Check_Mod_P(context_object, x, PP, ZERO, + num_chunks, bit_size_chunk); }; // Copy constraint generation lambda expression - auto CopyConstrain = [this,num_chunks](std::vector x, std::vector y) { + auto CopyConstrain = [this, num_chunks](std::vector x, std::vector y) { for (std::size_t i = 0; i < num_chunks; i++) { - std::cout << "copy_constrain x[i]: " << x[i] << " , y[i]: " << y[i] << std::endl; copy_constrain(x[i], y[i]); } - }; - //YQ - //LAMBDA - //XQ - //2yQ * lambda = 3xQ^2 + }; + // perform range checks and mod p checks on all stored variables check_chunked(LAMBDA); @@ -266,59 +260,68 @@ namespace nil { check_chunked(XR); check_chunked(YR); - std::cout<< "t1" << std::endl; Multiplication_Mod_P t1 = Multiplication_Mod_P( - context_object, YQ, LAMBDA, P, PP,num_chunks,bit_size_chunk); // t1 = yQ * lambda - std::cout<< "t2" << std::endl; + context_object, YQ, LAMBDA, P, PP, ZERO, num_chunks, bit_size_chunk); // t1 = yQ * lambda + + Addition_Mod_P t2 = Addition_Mod_P(context_object, t1.res_z, t1.res_z, P, - PP,ZERO,num_chunks,bit_size_chunk); // t2 = t1 + t1 = 2yQ * lambda - std::cout<< "t3" << std::endl; + PP, ZERO, num_chunks, bit_size_chunk); // t2 = t1 + t1 = 2yQ * lambda Addition_Mod_P t3 = Addition_Mod_P(context_object, XQ, XQ, P, PP, - ZERO,num_chunks,bit_size_chunk); // t3 = xQ + xQ = 2xQ - std::cout<< "t4" << std::endl; + ZERO, num_chunks, bit_size_chunk); // t3 = xQ + xQ = 2xQ + if constexpr (stage == GenerationStage::ASSIGNMENT) { + non_native_integral_type a = 0, b = 0, pow = 1; + for (std::size_t i = 0; i < num_chunks; ++i) { + a += non_native_integral_type(integral_type( + t1.res_z[i].data)) * + pow; + b += non_native_integral_type(integral_type( + t3.res_z[i].data)) * + pow; + pow <<= bit_size_chunk; + } + } Addition_Mod_P t4 = Addition_Mod_P(context_object, XQ, t3.res_z, P, PP, - ZERO,num_chunks,bit_size_chunk); // t4 = xQ + t3 = 3xQ - std::cout<< "t5" << std::endl; + ZERO, num_chunks, bit_size_chunk); // t4 = xQ + t3 = 3xQ Multiplication_Mod_P t5 = Multiplication_Mod_P( - context_object, t4.res_z, XQ, P, PP,num_chunks,bit_size_chunk); // t5 = t4 * xQ = 3xQ^2 - std::cout<< "copy 1" << std::endl; + context_object, t4.res_z, XQ, P, PP, ZERO, num_chunks, bit_size_chunk); // t5 = t4 * xQ = 3xQ^2 + if constexpr (stage == GenerationStage::ASSIGNMENT) { + non_native_integral_type a = 0, b = 0, pow = 1; + for (std::size_t i = 0; i < num_chunks; ++i) { + a += non_native_integral_type( + integral_type(t2.res_z[i].data)) * + pow; + b += non_native_integral_type( + integral_type(t5.res_z[i].data)) * + pow; + pow <<= bit_size_chunk; + } + } CopyConstrain(t2.res_z, t5.res_z); // 2yQ * lambda = 3xQ^2 - std::cout<< "t6" << std::endl; Addition_Mod_P t6 = Addition_Mod_P(context_object, XR, t3.res_z, P, PP, - ZERO,num_chunks,bit_size_chunk); // t6 = xR + t3 = xR + 2xQ - std::cout<< "t7" << std::endl; + ZERO, num_chunks, bit_size_chunk); // t6 = xR + t3 = xR + 2xQ Multiplication_Mod_P t7 = Multiplication_Mod_P(context_object, LAMBDA, LAMBDA, P, - PP,num_chunks,bit_size_chunk); // t7 = lambda * lambda - std::cout<< "copy 2" << std::endl; + PP, ZERO, num_chunks, bit_size_chunk); // t7 = lambda * lambda CopyConstrain(t6.res_z, t7.res_z); // xR + 2xQ = lambda^2 - std::cout<< "t8" << std::endl; Addition_Mod_P t8 = Addition_Mod_P(context_object, YR, YQ, P, PP, - ZERO,num_chunks,bit_size_chunk); // t8 = yR + yQ - std::cout<< "t9" << std::endl; + ZERO, num_chunks, bit_size_chunk); // t8 = yR + yQ Negation_Mod_P t9 = - Negation_Mod_P(context_object, XR, P, PP, ZERO,num_chunks,bit_size_chunk); // t9 = -xR - std::cout<< "t10" << std::endl; + Negation_Mod_P(context_object, XR, P, PP, ZERO, num_chunks, bit_size_chunk); // t9 = -xR Addition_Mod_P t10 = Addition_Mod_P(context_object, XQ, t9.res_z, P, PP, - ZERO,num_chunks,bit_size_chunk); // t10 = xQ + t9 = xQ - xR - std::cout<< "t11" << std::endl; + ZERO, num_chunks, bit_size_chunk); // t10 = xQ + t9 = xQ - xR Multiplication_Mod_P t11 = Multiplication_Mod_P( context_object, LAMBDA, t10.res_z, P, - PP,num_chunks,bit_size_chunk); // t11 = lambda * t10 =lambda(xQ-xR) - std::cout<< "copy 3" << std::endl; + PP, ZERO, num_chunks, bit_size_chunk); // t11 = lambda * t10 =lambda(xQ-xR) CopyConstrain(t8.res_z, t11.res_z); // yR + yQ = lambda(xQ - xR) - std::cout<< "t12" << std::endl; Multiplication_Mod_P t12 = - Multiplication_Mod_P(context_object, Z, t1.res_z, P, PP, - num_chunks,bit_size_chunk); // t12 = z * t1 = z * yQ * lambda - std::cout<< "copy 4" << std::endl; + Multiplication_Mod_P(context_object, Z, t1.res_z, P, PP, ZERO, + num_chunks, bit_size_chunk); // t12 = z * t1 = z * yQ * lambda CopyConstrain(LAMBDA, t12.res_z); // lambda = z yQ lambda - std::cout<< "make links" << std::endl; if (make_links) { for (std::size_t i = 0; i < num_chunks; ++i) { copy_constrain(XQ[i], input_xQ[i]); @@ -345,25 +348,25 @@ namespace nil { template class pallas_ec_double : public ec_double< - FieldType, stage, - crypto3::algebra::curves::pallas::base_field_type> { + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { using Base = ec_double; + crypto3::algebra::curves::pallas::base_field_type>; - public: + public: using Base::Base; }; template class vesta_ec_double : public ec_double { + crypto3::algebra::curves::vesta::base_field_type> { using Base = ec_double; + crypto3::algebra::curves::vesta::base_field_type>; - public: + public: using Base::Base; }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp index 5cecbdc60..e65666ccb 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp @@ -134,9 +134,9 @@ namespace nil { bool make_links = true) : generic_component(context_object) { - using double_non_native_integral_type = nil::crypto3::multiprecision::big_uint<2* NonNativeFieldType::modulus_bits>; + using extended_integral_type = nil::crypto3::multiprecision::big_uint<2* NonNativeFieldType::modulus_bits>; - using native_integral_type = typename FieldType::integral_type; + using integral_type = typename FieldType::integral_type; using Check_Mod_P = typename bbf::components::check_mod_p; using Range_Check = typename bbf::components::range_check_multi; diff --git a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp index 8392ceef6..b0335aa7a 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp @@ -40,137 +40,143 @@ using namespace nil; using namespace nil::blueprint; template + std::size_t bit_size_chunk> void test_ec_double( - const std::vector &public_input) { + const std::vector& public_input) { using FieldType = BlueprintFieldType; using TYPE = typename FieldType::value_type; using NON_NATIVE_TYPE = typename NonNativeFieldType::value_type; using integral_type = typename BlueprintFieldType::integral_type; - typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> - extended_integral_type; + using non_native_integral_type = typename BlueprintFieldType::integral_type; + - extended_integral_type B = extended_integral_type(1) - << bit_size_chunk, - pow = 0; + non_native_integral_type pow = 1; NON_NATIVE_TYPE xQ = 0, yQ = 0; for (std::size_t i = 0; i < num_chunks; ++i) { - xQ += extended_integral_type(integral_type(public_input[i].data)) * pow; - yQ += extended_integral_type(integral_type(public_input[i + num_chunks].data)) * + xQ += non_native_integral_type(integral_type(public_input[i].data)) * pow; + yQ += non_native_integral_type(integral_type(public_input[i + num_chunks].data)) * pow; pow <<= bit_size_chunk; } NON_NATIVE_TYPE lambda = - (yQ == 0) - ? 0 - : 3 * xQ * xQ * - ((2 * yQ).inversed()), // if yQ = 0, lambda = 0 + (yQ == 0) + ? 0 + : 3 * xQ * xQ * + ((2 * yQ).inversed()), // if yQ = 0, lambda = 0 z = (yQ == 0) ? 0 : yQ.inversed(), // if yQ = 0, z = 0 expected_xR = lambda * lambda - 2 * xQ, expected_yR = lambda * (xQ - expected_xR) - yQ; - auto assign_and_check = [&](auto &B, auto &raw_input) { + + auto assign_and_check = [&](auto& B, auto& raw_input) { raw_input.xQ = std::vector(public_input.begin(), public_input.begin() + num_chunks); raw_input.yQ = - std::vector(public_input.begin(), public_input.begin() + num_chunks); - raw_input.p = std::vector(public_input.begin() + num_chunks, - public_input.begin() + 2 * num_chunks); - raw_input.pp = std::vector(public_input.begin() + 2 * num_chunks, - public_input.begin() + 3 * num_chunks); - raw_input.zero = public_input[3 * num_chunks]; + std::vector(public_input.begin() + num_chunks, public_input.begin() + 2 * num_chunks); + raw_input.p = std::vector(public_input.begin() + 2 * num_chunks, + public_input.begin() + 3 * num_chunks); + raw_input.pp = std::vector(public_input.begin() + 3 * num_chunks, + public_input.begin() + 4 * num_chunks); + raw_input.zero = public_input[4 * num_chunks]; auto [at, A, desc] = B.assign(raw_input); bool pass = B.is_satisfied(at); std::cout << "Is_satisfied = " << pass << std::endl; - assert(pass == true); - extended_integral_type xR = 0; - extended_integral_type yR = 0; + assert(pass == true); + non_native_integral_type xR = 0; + non_native_integral_type yR = 0; pow = 1; for (std::size_t i = 0; i < num_chunks; i++) { - xR += extended_integral_type(integral_type(A.res_xR[i].data)) * pow; - yR += extended_integral_type(integral_type(A.res_yR[i].data)) * pow; + xR += non_native_integral_type(integral_type(A.res_xR[i].data)) * pow; + yR += non_native_integral_type(integral_type(A.res_yR[i].data)) * pow; pow <<= bit_size_chunk; } -#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED - std::cout << "negation_mod_p test" << std::endl; - std::cout << "Expected xR - yR: " << std::dec << expected_xR.data << " - " << expected_yR.data << std::endl; + //#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "Expected xR - yR: " << std::dec << expected_xR.data << " - " << expected_yR.data << std::endl; std::cout << "Real res xR - yR: " << std::dec << xR << " - " << yR << std::endl; -#endif + //#endif assert(xR == expected_xR.data); assert(yR == expected_yR.data); - }; + }; if constexpr (std::is_same_v) { - typename bbf::components::vesta_ec_double< + crypto3::algebra::curves::pallas::base_field_type>) { + typename bbf::components::pallas_ec_double< FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; auto B = - bbf::circuit_builder(num_chunks, bit_size_chunk); + bbf::circuit_builder(num_chunks, bit_size_chunk); assign_and_check(B, raw_input); - } else if constexpr (std::is_same_v< - NonNativeFieldType, - crypto3::algebra::curves::vesta::base_field_type>) { - typename bbf::components::pallas_ec_double< + } + else if constexpr (std::is_same_v< + NonNativeFieldType, + crypto3::algebra::curves::vesta::base_field_type>) { + typename bbf::components::vesta_ec_double< FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; auto B = - bbf::circuit_builder(num_chunks, bit_size_chunk); + bbf::circuit_builder(num_chunks, bit_size_chunk); assign_and_check(B, raw_input); } } -template +template void ec_double_tests() { + using NonNativeFieldType = typename Curve::base_field_type; using value_type = typename BlueprintFieldType::value_type; using integral_type = typename BlueprintFieldType::integral_type; using foreign_value_type = typename NonNativeFieldType::value_type; + using ec_point_value_type = typename Curve::template g1_type::value_type; + typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> extended_integral_type; static boost::random::mt19937 seed_seq; - static nil::crypto3::random::algebraic_engine generate_random( + static nil::crypto3::random::algebraic_engine generate_random( seed_seq); boost::random::uniform_int_distribution<> t_dist(0, 1); + + extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input; - foreign_value_type src_x = generate_random(), src_y = generate_random(); + extended_integral_type extended_base = 1, + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus, + pp = ext_pow - p; - extended_integral_type xQ = extended_integral_type(integral_type(src_x.data)), - yQ = extended_integral_type(integral_type(src_y.data)), - extended_base = 1, - ext_pow = extended_base << (num_chunks * bit_size_chunk), - p = NonNativeFieldType::modulus; - extended_integral_type pp = ext_pow - p; + value_type d = generate_random(); + ec_point_value_type Q = ec_point_value_type::one(); + Q = Q * d; - public_input.resize(3 * num_chunks + 1); + public_input.resize(4 * num_chunks + 1); + integral_type xQ = integral_type(Q.X.data); + integral_type yQ = integral_type(Q.Y.data); for (std::size_t j = 0; j < num_chunks; j++) { public_input[j] = value_type(xQ & mask); xQ >>= bit_size_chunk; - public_input[j] = value_type(yQ & mask); + public_input[1 * num_chunks + j] = value_type(yQ & mask); yQ >>= bit_size_chunk; - public_input[1 * num_chunks + j] = value_type(p & mask); + public_input[2 * num_chunks + j] = value_type(p & mask); p >>= bit_size_chunk; - public_input[2 * num_chunks + j] = value_type(pp & mask); + public_input[3 * num_chunks + j] = value_type(pp & mask); pp >>= bit_size_chunk; } public_input.push_back(value_type(0)); // the zero test_ec_double(public_input); + bit_size_chunk>(public_input); } } @@ -179,26 +185,20 @@ constexpr static const std::size_t random_tests_amount = 10; BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_ec_double_test) { - using pallas_field_type = typename crypto3::algebra::curves::pallas::base_field_type; - using vesta_field_type = typename crypto3::algebra::curves::vesta::base_field_type; - - ec_double_tests(); + using pallas = typename crypto3::algebra::curves::pallas; + using vesta = typename crypto3::algebra::curves::vesta; - ec_double_tests(); + ec_double_tests(); - ec_double_tests(); + ec_double_tests(); - ec_double_tests(); + ec_double_tests(); - ec_double_tests(); + ec_double_tests(); - ec_double_tests(); } BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp index 109cfaa9a..4343786c2 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp @@ -101,23 +101,23 @@ void test_addition_mod_p(const std::vector) { - typename bbf::components::vesta_addition_mod_p< + typename bbf::components::pallas_addition_mod_p< FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; auto B = bbf::circuit_builder(num_chunks, bit_size_chunk); assign_and_check(B, raw_input); } else if constexpr (std::is_same_v< NonNativeFieldType, crypto3::algebra::curves::vesta::base_field_type>) { - typename bbf::components::pallas_addition_mod_p< + typename bbf::components::vesta_addition_mod_p< FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; auto B = bbf::circuit_builder(num_chunks, bit_size_chunk); assign_and_check(B, raw_input); diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp index 642281451..f3af88a39 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp @@ -110,24 +110,24 @@ void test_mult(const std::vector &publi if constexpr (std::is_same_v) { - typename bbf::components::vesta_flexible_multiplication< + typename bbf::components::pallas_flexible_multiplication< FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; auto B = bbf::circuit_builder(num_chunks, bit_size_chunk); assign_and_check(B, raw_input); } else if constexpr (std::is_same_v< NonNativeFieldType, crypto3::algebra::curves::vesta::base_field_type>) { - typename bbf::components::pallas_flexible_multiplication< + typename bbf::components::vesta_flexible_multiplication< FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; auto B = bbf::circuit_builder(num_chunks, bit_size_chunk); assign_and_check(B, raw_input); @@ -232,6 +232,7 @@ void mult_tests_to_fail() { public_input[3 * num_chunks + j] = value_type(pp & mask); pp >>= bit_size_chunk; } + public_input.push_back(value_type(0)); // the zero test_mult(public_input); diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp index 030e4079e..8a114cfac 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp @@ -91,21 +91,21 @@ void test_negation_mod_p( if constexpr (std::is_same_v) { - typename bbf::components::vesta_negation_mod_p< + typename bbf::components::pallas_negation_mod_p< FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; auto B = - bbf::circuit_builder(num_chunks, bit_size_chunk); assign_and_check(B, raw_input); } else if constexpr (std::is_same_v< NonNativeFieldType, crypto3::algebra::curves::vesta::base_field_type>) { - typename bbf::components::pallas_negation_mod_p< + typename bbf::components::vesta_negation_mod_p< FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; auto B = - bbf::circuit_builder(num_chunks, bit_size_chunk); assign_and_check(B, raw_input); From 318eb9c7e4b50c1fb8866a24da1c582dd53ff40e Mon Sep 17 00:00:00 2001 From: Antoine Cyr Date: Fri, 24 Jan 2025 19:38:22 -0500 Subject: [PATCH 11/14] ec addition --- .../algebra/curves/weierstrass/ec_double.hpp | 219 ++++--- .../curves/weierstrass/ec_double_old.hpp | 561 ------------------ .../curves/weierstrass/ec_full_add.hpp | 493 +++++++++++++++ .../curves/weierstrass/ec_incomplete_add.hpp | 389 ++++++++++++ .../fields/non_native/addition_mod_p.hpp | 20 +- .../algebra/fields/non_native/check_mod_p.hpp | 2 +- .../non_native/flexible_multiplication.hpp | 4 +- .../fields/non_native/negation_mod_p.hpp | 14 +- .../components/detail/carry_on_addition.hpp | 4 +- .../bbf/components/detail/choice_function.hpp | 6 +- crypto3/libs/blueprint/test/CMakeLists.txt | 2 + .../algebra/curves/weierstrass/ec_double.cpp | 4 +- .../curves/weierstrass/ec_full_add.cpp | 253 ++++++++ .../curves/weierstrass/ec_incomplete_add.cpp | 215 +++++++ .../fields/non_native/addition_mod_p.cpp | 20 +- .../non_native/flexible_multiplication.cpp | 2 +- .../fields/non_native/negation_mod_p.cpp | 16 +- .../test/bbf/detail/carry_on_addition.cpp | 6 +- .../test/bbf/detail/choice_function.cpp | 6 +- 19 files changed, 1506 insertions(+), 730 deletions(-) delete mode 100644 crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double_old.hpp create mode 100644 crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp create mode 100644 crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp create mode 100644 crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp create mode 100644 crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp index 7518c6203..e70280e68 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp @@ -1,6 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Alexey Yashunsky -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -22,7 +22,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //---------------------------------------------------------------------------// -// @file Declaration of interfaces for FRI verification array swapping component. +// @file Declaration of interfaces for doubling an EC points over a non-native field //---------------------------------------------------------------------------// #ifndef CRYPTO3_BBF_COMPONENTS_EC_DOUBLE_ECDSA_HPP @@ -56,8 +56,9 @@ namespace nil { // Expects input as k-chunked values with b bits per chunk // p' = 2^(kb) - p // Input: xQ[0],...,xQ[k-1], yQ[0],...,yQ[k-1], p[0],...,p[k-1], - // pp[0],...,pp[k-1], 0 (expects zero constant as input) Output: - // xR[0],...,xR[k-1], yR[0],...,yR[k-1] + // pp[0],...,pp[k-1], 0 + // (expects zero constant as input) + // Output: xR[0],...,xR[k-1], yR[0],...,yR[k-1] template struct ec_double_raw_input { @@ -70,7 +71,7 @@ namespace nil { }; template + typename NonNativeFieldType> class ec_double : public generic_component { using generic_component::allocate; using generic_component::copy_constrain; @@ -78,16 +79,16 @@ namespace nil { using generic_component::lookup; using component_type = generic_component; - public: + public: using typename generic_component::TYPE; using typename generic_component::context_type; using typename generic_component::table_params; using raw_input_type = typename std::conditional, - std::tuple<>>::type; + ec_double_raw_input, + std::tuple<>>::type; - public: + public: std::vector inp_xQ; std::vector inp_yQ; std::vector inp_p; @@ -103,13 +104,13 @@ namespace nil { // rows = 4096-1 so that lookup table is not too hard to fit and // padding doesn't inflate the table constexpr std::size_t rows = 4095; - return { witness, public_inputs, constants, rows }; + return {witness, public_inputs, constants, rows}; } static std::tuple, std::vector, - std::vector, std::vector, TYPE> - form_input(context_type& context_object, raw_input_type raw_input, - std::size_t num_chunks, std::size_t bit_size_chunk) { + std::vector, std::vector, TYPE> + form_input(context_type& context_object, raw_input_type raw_input, + std::size_t num_chunks, std::size_t bit_size_chunk) { std::vector input_xQ(num_chunks); std::vector input_yQ(num_chunks); std::vector input_p(num_chunks); @@ -127,29 +128,30 @@ namespace nil { } for (std::size_t i = 0; i < num_chunks; i++) { context_object.allocate(input_xQ[i], 0, i, - column_type::public_input); + column_type::public_input); context_object.allocate(input_yQ[i], 0, i + num_chunks, - column_type::public_input); + column_type::public_input); context_object.allocate(input_p[i], 0, i + 2 * num_chunks, - column_type::public_input); + column_type::public_input); context_object.allocate(input_pp[i], 0, i + 3 * num_chunks, - column_type::public_input); + column_type::public_input); } context_object.allocate(input_zero, 0, 4 * num_chunks, - column_type::public_input); + column_type::public_input); return std::make_tuple(input_xQ, input_yQ, input_p, input_pp, - input_zero); + input_zero); } ec_double(context_type& context_object, std::vector input_xQ, - std::vector input_yQ, std::vector input_p, - std::vector input_pp, TYPE input_zero, - std::size_t num_chunks, std::size_t bit_size_chunk, - bool make_links = true) + std::vector input_yQ, std::vector input_p, + std::vector input_pp, TYPE input_zero, + std::size_t num_chunks, std::size_t bit_size_chunk, + bool make_links = true) : generic_component(context_object) { using integral_type = typename FieldType::integral_type; using NON_NATIVE_TYPE = typename NonNativeFieldType::value_type; - using non_native_integral_type = typename NonNativeFieldType::integral_type; + using non_native_integral_type = + typename NonNativeFieldType::integral_type; using Choice_Function = typename bbf::components::choice_function; @@ -158,12 +160,14 @@ namespace nil { using Check_Mod_P = typename bbf::components::check_mod_p; using Addition_Mod_P = - typename bbf::components::addition_mod_p; + typename bbf::components::addition_mod_p; using Negation_Mod_P = - typename bbf::components::negation_mod_p; + typename bbf::components::negation_mod_p; using Multiplication_Mod_P = - typename bbf::components::flexible_multiplication; + typename bbf::components::flexible_multiplication< + FieldType, stage, NonNativeFieldType>; std::vector XQ(num_chunks); std::vector YQ(num_chunks); @@ -190,34 +194,36 @@ namespace nil { for (std::size_t i = 0; i < num_chunks; ++i) { xQ += non_native_integral_type( - integral_type(input_xQ[i].data)) * - pow; + integral_type(input_xQ[i].data)) * + pow; yQ += non_native_integral_type( - integral_type(input_yQ[i].data)) * - pow; + integral_type(input_yQ[i].data)) * + pow; pow <<= bit_size_chunk; } NON_NATIVE_TYPE - lambda = + lambda = (yQ == 0) - ? 0 - : 3 * xQ * xQ * - ((2 * yQ).inversed()), // if yQ = 0, lambda = 0 + ? 0 + : 3 * xQ * xQ * + ((2 * yQ).inversed()), // if yQ = 0, lambda = 0 z = (yQ == 0) ? 0 : yQ.inversed(), // if yQ = 0, z = 0 xR = lambda * lambda - 2 * xQ, - yR = lambda * (xQ - xR) - yQ; + yR = lambda * (xQ - xR) - yQ; auto base = [num_chunks, bit_size_chunk](NON_NATIVE_TYPE x) { std::vector res(num_chunks); - non_native_integral_type mask = (non_native_integral_type(1) << bit_size_chunk) - 1; - non_native_integral_type x_value = non_native_integral_type(x.data); + non_native_integral_type mask = + (non_native_integral_type(1) << bit_size_chunk) - 1; + non_native_integral_type x_value = + non_native_integral_type(x.data); for (std::size_t i = 0; i < num_chunks; i++) { res[i] = TYPE(x_value & mask); x_value >>= bit_size_chunk; } return res; - }; + }; LAMBDA = base(lambda); Z = base(z); @@ -238,21 +244,21 @@ namespace nil { } allocate(ZERO); - auto check_chunked = - [&context_object, num_chunks, bit_size_chunk, PP, ZERO](std::vector x) { - Range_Check rc = Range_Check(context_object, x, - num_chunks, bit_size_chunk); + auto check_chunked = [&context_object, num_chunks, bit_size_chunk, + PP, ZERO](std::vector x) { + Range_Check rc = Range_Check(context_object, x, num_chunks, + bit_size_chunk); Check_Mod_P cm = Check_Mod_P(context_object, x, PP, ZERO, - num_chunks, bit_size_chunk); - }; + num_chunks, bit_size_chunk); + }; // Copy constraint generation lambda expression - auto CopyConstrain = [this, num_chunks](std::vector x, std::vector y) { + auto CopyConstrain = [this, num_chunks](std::vector x, + std::vector y) { for (std::size_t i = 0; i < num_chunks; i++) { copy_constrain(x[i], y[i]); } - }; - + }; // perform range checks and mod p checks on all stored variables check_chunked(LAMBDA); @@ -260,67 +266,46 @@ namespace nil { check_chunked(XR); check_chunked(YR); - Multiplication_Mod_P t1 = Multiplication_Mod_P( - context_object, YQ, LAMBDA, P, PP, ZERO, num_chunks, bit_size_chunk); // t1 = yQ * lambda - - - Addition_Mod_P t2 = - Addition_Mod_P(context_object, t1.res_z, t1.res_z, P, - PP, ZERO, num_chunks, bit_size_chunk); // t2 = t1 + t1 = 2yQ * lambda - Addition_Mod_P t3 = Addition_Mod_P(context_object, XQ, XQ, P, PP, - ZERO, num_chunks, bit_size_chunk); // t3 = xQ + xQ = 2xQ - if constexpr (stage == GenerationStage::ASSIGNMENT) { - non_native_integral_type a = 0, b = 0, pow = 1; - for (std::size_t i = 0; i < num_chunks; ++i) { - a += non_native_integral_type(integral_type( - t1.res_z[i].data)) * - pow; - b += non_native_integral_type(integral_type( - t3.res_z[i].data)) * - pow; - pow <<= bit_size_chunk; - } - } - Addition_Mod_P t4 = - Addition_Mod_P(context_object, XQ, t3.res_z, P, PP, - ZERO, num_chunks, bit_size_chunk); // t4 = xQ + t3 = 3xQ - Multiplication_Mod_P t5 = Multiplication_Mod_P( - context_object, t4.res_z, XQ, P, PP, ZERO, num_chunks, bit_size_chunk); // t5 = t4 * xQ = 3xQ^2 - if constexpr (stage == GenerationStage::ASSIGNMENT) { - non_native_integral_type a = 0, b = 0, pow = 1; - for (std::size_t i = 0; i < num_chunks; ++i) { - a += non_native_integral_type( - integral_type(t2.res_z[i].data)) * - pow; - b += non_native_integral_type( - integral_type(t5.res_z[i].data)) * - pow; - pow <<= bit_size_chunk; - } - } - CopyConstrain(t2.res_z, t5.res_z); // 2yQ * lambda = 3xQ^2 - Addition_Mod_P t6 = - Addition_Mod_P(context_object, XR, t3.res_z, P, PP, - ZERO, num_chunks, bit_size_chunk); // t6 = xR + t3 = xR + 2xQ - Multiplication_Mod_P t7 = - Multiplication_Mod_P(context_object, LAMBDA, LAMBDA, P, - PP, ZERO, num_chunks, bit_size_chunk); // t7 = lambda * lambda - CopyConstrain(t6.res_z, t7.res_z); // xR + 2xQ = lambda^2 - Addition_Mod_P t8 = Addition_Mod_P(context_object, YR, YQ, P, PP, - ZERO, num_chunks, bit_size_chunk); // t8 = yR + yQ - Negation_Mod_P t9 = - Negation_Mod_P(context_object, XR, P, PP, ZERO, num_chunks, bit_size_chunk); // t9 = -xR - Addition_Mod_P t10 = - Addition_Mod_P(context_object, XQ, t9.res_z, P, PP, - ZERO, num_chunks, bit_size_chunk); // t10 = xQ + t9 = xQ - xR - Multiplication_Mod_P t11 = Multiplication_Mod_P( - context_object, LAMBDA, t10.res_z, P, - PP, ZERO, num_chunks, bit_size_chunk); // t11 = lambda * t10 =lambda(xQ-xR) - CopyConstrain(t8.res_z, t11.res_z); // yR + yQ = lambda(xQ - xR) - Multiplication_Mod_P t12 = - Multiplication_Mod_P(context_object, Z, t1.res_z, P, PP, ZERO, - num_chunks, bit_size_chunk); // t12 = z * t1 = z * yQ * lambda - CopyConstrain(LAMBDA, t12.res_z); // lambda = z yQ lambda + auto MultModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x, + std::vector y) { + Multiplication_Mod_P t = + Multiplication_Mod_P(context_object, x, y, P, PP, ZERO, + num_chunks, bit_size_chunk); + return t.res_r; + }; + auto AddModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x, + std::vector y) { + Addition_Mod_P t = + Addition_Mod_P(context_object, x, y, P, PP, ZERO, + num_chunks, bit_size_chunk); + return t.res_r; + }; + auto NegModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x) { + Negation_Mod_P t = + Negation_Mod_P(context_object, x, P, PP, ZERO, num_chunks, + bit_size_chunk); + return t.res_r; + }; + + auto t1 = MultModP(YQ,LAMBDA); // t1 = yQ * lambda + auto t2 = AddModP(t1,t1); // t2 = t1 + t1 = 2yQ * lambda + auto t3 = AddModP(XQ,XQ); // t3 = xQ + xQ = 2xQ + auto t4 = AddModP(XQ,t3); // t4 = xQ + t3 = 3xQ + auto t5 = MultModP(t4,XQ); // t5 = t4 * xQ = 3xQ^2 + CopyConstrain(t2, t5); // 2yQ lambda = 3xQ^2 + auto t6 = AddModP(XR,t3); // t6 = xR + t3 = xR + 2xQ + auto t7 = MultModP(LAMBDA,LAMBDA); // t7 = lambda * lambda + CopyConstrain(t6, t7); // xR + 2xQ = lambda^2 + auto t8 = AddModP(YR,YQ); // t8 = yR + yQ + auto t9 = NegModP(XR); // t9 = -xR + auto t10 = AddModP(XQ,t9); // t10 = xQ + t9 = xQ - xR + auto t11 = MultModP(LAMBDA,t10); // t11 = lambda * t10 =lambda(xQ-xR) + CopyConstrain(t8, t11); // yR + yQ = lambda(xQ - xR) + auto t12 = MultModP(Z,t1); // t12 = z * t1 = z * yQ * lambda + CopyConstrain(LAMBDA, t12); // lambda = z yQ lambda if (make_links) { for (std::size_t i = 0; i < num_chunks; ++i) { @@ -348,25 +333,25 @@ namespace nil { template class pallas_ec_double : public ec_double< - FieldType, stage, - crypto3::algebra::curves::pallas::base_field_type> { + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { using Base = ec_double; + crypto3::algebra::curves::pallas::base_field_type>; - public: + public: using Base::Base; }; template class vesta_ec_double : public ec_double { + crypto3::algebra::curves::vesta::base_field_type> { using Base = ec_double; + crypto3::algebra::curves::vesta::base_field_type>; - public: + public: using Base::Base; }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double_old.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double_old.hpp deleted file mode 100644 index 596de4945..000000000 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double_old.hpp +++ /dev/null @@ -1,561 +0,0 @@ -//---------------------------------------------------------------------------// -// Copyright (c) 2024 Alexey Yashunsky -// -// MIT License -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -//---------------------------------------------------------------------------// -// @file Declaration of interfaces for doubling an EC point over a non-native field -//---------------------------------------------------------------------------// - -#ifndef CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_EC_DOUBLE_ECDSA_HPP -#define CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_EC_DOUBLE_ECDSA_HPP - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace nil { - namespace blueprint { - namespace components { - // Parameters: num_chunks = k, bit_size_chunk = b - // For a point Q = (x_Q,y_Q) from an elliptic curve over F[p] - // computes R = (x_R, y_R) = 2Q (EC doubling) - // Expects input as k-chunked values with b bits per chunk - // p' = 2^(kb) - p - // Input: xQ[0],...,xQ[k-1], yQ[0],...,yQ[k-1], p[0],...,p[k-1], pp[0],...,pp[k-1], 0 - // (expects zero constant as input) - // Output: xR[0],...,xR[k-1], yR[0],...,yR[k-1] - // - template - class ec_double; - - template - class ec_double, - BlueprintFieldType, - NonNativeFieldType, - num_chunks, - bit_size_chunk> - : public plonk_component { - - public: - using component_type = plonk_component; - - using var = typename component_type::var; - using manifest_type = plonk_component_manifest; - using range_check_component = range_check_multi, - BlueprintFieldType, num_chunks, bit_size_chunk>; - using check_mod_p_component = check_mod_p, - BlueprintFieldType, num_chunks, bit_size_chunk>; - using mult_mod_p_component = flexible_mult, - BlueprintFieldType, NonNativeFieldType, num_chunks, bit_size_chunk>; - using neg_mod_p_component = negation_mod_p, - BlueprintFieldType, NonNativeFieldType, num_chunks, bit_size_chunk>; - using add_mod_p_component = addition_mod_p, - BlueprintFieldType, NonNativeFieldType, num_chunks, bit_size_chunk>; - - // needed only for gate_manifest: - using choice_function_component = - choice_function, BlueprintFieldType, num_chunks>; - - class gate_manifest_type : public component_gate_manifest { - public: - std::uint32_t gates_amount() const override { - return ec_double::gates_amount; - } - }; - - static gate_manifest get_gate_manifest(std::size_t witness_amount) { - // NB: this uses a workaround, as manifest cannot process intersecting sets of gates. - // We merge only non-intersecting sets of gates which cover all gates in the circuit. - gate_manifest manifest = - gate_manifest(gate_manifest_type()) - // .merge_with(range_check_component::get_gate_manifest(witness_amount)) - // .merge_with(check_mod_p_component::get_gate_manifest(witness_amount)) - .merge_with(mult_mod_p_component::get_gate_manifest(witness_amount)) // constains everything except choice_function - .merge_with(choice_function_component::get_gate_manifest(witness_amount)) - // .merge_with(add_mod_p_component::get_gate_manifest(witness_amount)) - // .merge_with(neg_mod_p_component::get_gate_manifest(witness_amount)) - ; - return manifest; - } - - static manifest_type get_manifest() { - manifest_type manifest = manifest_type( - // all requirements come from sub-components, the component itself has no personal requirements - std::shared_ptr(new manifest_range_param(1,4*num_chunks,1)), // we need place for 4k variables - false // constant column not needed - ).merge_with(range_check_component::get_manifest()) - .merge_with(check_mod_p_component::get_manifest()) - .merge_with(mult_mod_p_component::get_manifest()) - .merge_with(add_mod_p_component::get_manifest()) - .merge_with(neg_mod_p_component::get_manifest()); - return manifest; - } - - constexpr static std::size_t get_rows_amount(std::size_t witness_amount) { - return (4*num_chunks)/witness_amount + ((4*num_chunks) % witness_amount > 0) // to store 4k variables - + 4*range_check_component::get_rows_amount(witness_amount) - + 4*check_mod_p_component::get_rows_amount(witness_amount) - + 5*mult_mod_p_component::get_rows_amount(witness_amount) - + 6*add_mod_p_component::get_rows_amount(witness_amount) - + 1*neg_mod_p_component::get_rows_amount(witness_amount) - ; - } - - constexpr static const std::size_t gates_amount = 0; - const std::size_t rows_amount = get_rows_amount(this->witness_amount()); - const std::string component_name = "non-native field EC point doubling function"; - - struct input_type { - var xQ[num_chunks], yQ[num_chunks], p[num_chunks], pp[num_chunks], zero; - - std::vector> all_vars() { - std::vector> res = {zero}; - for(std::size_t i = 0; i < num_chunks; i++) { - res.push_back(xQ[i]); - res.push_back(yQ[i]); - res.push_back(p[i]); - res.push_back(pp[i]); - } - return res; - } - }; - - struct result_type { - var xR[num_chunks], yR[num_chunks]; - - result_type(const ec_double &component, std::uint32_t start_row_index) { - const std::size_t WA = component.witness_amount(); - for(std::size_t i = 0; i < num_chunks; i++) { - xR[i] = var(component.W((2*num_chunks + i) % WA), - start_row_index + (2*num_chunks + i)/WA, false, var::column_type::witness); - yR[i] = var(component.W((3*num_chunks + i) % WA), - start_row_index + (3*num_chunks + i)/WA, false, var::column_type::witness); - } - } - - std::vector> all_vars() { - std::vector> res = {}; - for(std::size_t i = 0; i < num_chunks; i++) { - res.push_back(xR[i]); - res.push_back(yR[i]); - } - return res; - } - }; - - template - explicit ec_double(ContainerType witness) : component_type(witness, {}, {}, get_manifest()) {}; - - template - ec_double(WitnessContainerType witness, ConstantContainerType constant, - PublicInputContainerType public_input) : - component_type(witness, constant, public_input, get_manifest()) {}; - - ec_double( - std::initializer_list - witnesses, - std::initializer_list - constants, - std::initializer_list - public_inputs) : - component_type(witnesses, constants, public_inputs, get_manifest()) {}; - - std::map component_lookup_tables(){ - std::map lookup_tables; - lookup_tables["range_16bit/full"] = 0; - - return lookup_tables; - } - }; - - template - using plonk_ec_double = - ec_double< - crypto3::zk::snark::plonk_constraint_system, - BlueprintFieldType, - NonNativeFieldType, - num_chunks, - bit_size_chunk>; - - template - typename plonk_ec_double::result_type generate_assignments( - const plonk_ec_double &component, - assignment> - &assignment, - const typename plonk_ec_double::input_type - &instance_input, - const std::uint32_t start_row_index) { - - using component_type = plonk_ec_double; - using var = typename component_type::var; - - using range_check_type = typename component_type::range_check_component; - using check_mod_p_type = typename component_type::check_mod_p_component; - using mult_mod_p_type = typename component_type::mult_mod_p_component; - using add_mod_p_type = typename component_type::add_mod_p_component; - using neg_mod_p_type = typename component_type::neg_mod_p_component; - - using value_type = typename BlueprintFieldType::value_type; - using integral_type = typename BlueprintFieldType::integral_type; - using non_native_value_type = typename NonNativeFieldType::value_type; - using non_native_integral_type = typename NonNativeFieldType::integral_type; - - const std::size_t WA = component.witness_amount(); - - // instances of used subcomponents - range_check_type range_check_instance( component._W, component._C, component._PI); - check_mod_p_type check_mod_p_instance( component._W, component._C, component._PI); - mult_mod_p_type mult_mod_p_instance( component._W, component._C, component._PI); - add_mod_p_type add_mod_p_instance( component._W, component._C, component._PI); - neg_mod_p_type neg_mod_p_instance( component._W, component._C, component._PI); - - non_native_integral_type B = non_native_integral_type(1) << bit_size_chunk; - non_native_value_type xQ = 0, - yQ = 0; - - for(std::size_t i = num_chunks; i > 0; i--) { - xQ *= B; - xQ += non_native_integral_type(integral_type(var_value(assignment, instance_input.xQ[i-1]).data)); - yQ *= B; - yQ += non_native_integral_type(integral_type(var_value(assignment, instance_input.yQ[i-1]).data)); - } - - non_native_value_type lambda = (yQ == 0) ? 0 : 3*xQ*xQ*((2*yQ).inversed()), // if yQ = 0, lambda = 0 - z = (yQ == 0) ? 0 : yQ.inversed(), // if yQ = 0, z = 0 - xR = lambda*lambda - 2*xQ, - yR = lambda*(xQ - xR) - yQ; - - auto base_B = [&B](non_native_value_type x) { - std::array res; - non_native_integral_type t = non_native_integral_type(x.data); - for(std::size_t i = 0; i < num_chunks; i++) { - res[i] = t % B; - t /= B; - } - return res; - }; - - std::array lambda_B = base_B(lambda), - z_B = base_B(z), - xR_B = base_B(xR), - yR_B = base_B(yR); - // place to store locations for further reference - var xQ_var[num_chunks], yQ_var[num_chunks], - lambda_var[num_chunks], z_var[num_chunks], xR_var[num_chunks], yR_var[num_chunks]; - - // Store vars for future reference; fill cells with chunks of lambda, z, xR, yR consecutively - for(std::size_t i = 0; i < num_chunks; i++) { - xQ_var[i] = instance_input.xQ[i]; - yQ_var[i] = instance_input.yQ[i]; - - assignment.witness(component.W(i % WA), start_row_index + i/WA) = lambda_B[i]; - lambda_var[i] = var(component.W(i % WA), start_row_index + i/WA, false); - - assignment.witness(component.W((num_chunks + i) % WA), start_row_index + (num_chunks + i)/WA) = z_B[i]; - z_var[i] = var(component.W((num_chunks + i) % WA), start_row_index + (num_chunks + i)/WA,false); - - assignment.witness(component.W((2*num_chunks + i) % WA), start_row_index + (2*num_chunks + i)/WA) = xR_B[i]; - xR_var[i] = var(component.W((2*num_chunks + i) % WA), start_row_index + (2*num_chunks + i)/WA,false); - - assignment.witness(component.W((3*num_chunks + i) % WA), start_row_index + (3*num_chunks + i)/WA) = yR_B[i]; - yR_var[i] = var(component.W((3*num_chunks + i) % WA), start_row_index + (3*num_chunks + i)/WA,false); - } - - // the number of rows used up to now - std::size_t current_row_shift = (4*num_chunks)/WA + ((4*num_chunks) % WA > 0); - - auto check_chunked_var = [&assignment, &instance_input, &range_check_instance, &check_mod_p_instance, - &start_row_index, ¤t_row_shift ] (var x[num_chunks]) { - typename range_check_type::input_type range_check_input; - for(std::size_t i = 0; i < num_chunks; i++) { - range_check_input.x[i] = x[i]; - } - generate_assignments(range_check_instance, assignment, range_check_input, start_row_index + current_row_shift); - current_row_shift += range_check_instance.rows_amount; - - typename check_mod_p_type::input_type mod_p_check_input; - for(std::size_t i = 0; i < num_chunks; i++) { - mod_p_check_input.x[i] = x[i]; - mod_p_check_input.pp[i] = instance_input.pp[i]; - } - mod_p_check_input.zero = instance_input.zero; - generate_assignments(check_mod_p_instance, assignment, mod_p_check_input, - start_row_index + current_row_shift); // check_mod_p - current_row_shift += check_mod_p_instance.rows_amount; - }; - // perform range checks and mod p checks on all stored variables - check_chunked_var(lambda_var); - check_chunked_var(z_var); - check_chunked_var(xR_var); - check_chunked_var(yR_var); - - // assignment generation lambda expressions for mod p arithemetic - auto MultModP = [&instance_input, &mult_mod_p_instance, &assignment, &start_row_index, ¤t_row_shift] - (var x[num_chunks], var y[num_chunks]) { - typename mult_mod_p_type::input_type mult_input; - for(std::size_t i = 0; i < num_chunks; i++) { - mult_input.x[i] = x[i]; - mult_input.y[i] = y[i]; - mult_input.p[i] = instance_input.p[i]; - mult_input.pp[i] = instance_input.pp[i]; - } - mult_input.zero = instance_input.zero; - typename mult_mod_p_type::result_type res = generate_assignments(mult_mod_p_instance, assignment, mult_input, - start_row_index + current_row_shift); - current_row_shift += mult_mod_p_instance.rows_amount; - return res; - }; - auto AddModP = [&instance_input, &add_mod_p_instance, &assignment, &start_row_index, ¤t_row_shift] - (var x[num_chunks], var y[num_chunks]) { - typename add_mod_p_type::input_type add_input; - for(std::size_t i = 0; i < num_chunks; i++) { - add_input.x[i] = x[i]; - add_input.y[i] = y[i]; - add_input.p[i] = instance_input.p[i]; - add_input.pp[i] = instance_input.pp[i]; - } - add_input.zero = instance_input.zero; - typename add_mod_p_type::result_type res = generate_assignments(add_mod_p_instance, assignment, add_input, - start_row_index + current_row_shift); - current_row_shift += add_mod_p_instance.rows_amount; - return res; - }; - auto NegModP = [&instance_input, &neg_mod_p_instance, &assignment, &start_row_index, ¤t_row_shift] - (var x[num_chunks]) { - typename neg_mod_p_type::input_type neg_input; - for(std::size_t i = 0; i < num_chunks; i++) { - neg_input.x[i] = x[i]; - neg_input.p[i] = instance_input.p[i]; - neg_input.pp[i] = instance_input.pp[i]; - } - neg_input.zero = instance_input.zero; - typename neg_mod_p_type::result_type res = generate_assignments(neg_mod_p_instance, assignment, neg_input, - start_row_index + current_row_shift); - current_row_shift += neg_mod_p_instance.rows_amount; - return res; - }; - - typename mult_mod_p_type::result_type t1 = MultModP(yQ_var,lambda_var); // t1 = yQ * lambda - typename add_mod_p_type::result_type t2 = AddModP(t1.r,t1.r); // t2 = t1 + t1 = 2yQ * lambda - typename add_mod_p_type::result_type t3 = AddModP(xQ_var,xQ_var); // t3 = xQ + xQ = 2xQ - typename add_mod_p_type::result_type t4 = AddModP(xQ_var,t3.z); // t4 = xQ + t3 = 3xQ - typename mult_mod_p_type::result_type t5 = MultModP(t4.z,xQ_var); // t5 = t4 * xQ = 3xQ^2 - typename add_mod_p_type::result_type t6 = AddModP(xR_var,t3.z); // t6 = xR + t3 = xR + 2xQ - typename mult_mod_p_type::result_type t7 = MultModP(lambda_var,lambda_var); // t7 = lambda * lambda - typename add_mod_p_type::result_type t8 = AddModP(yR_var,yQ_var); // t8 = yR + yQ - typename neg_mod_p_type::result_type t9 = NegModP(xR_var); // t9 = -xR - typename add_mod_p_type::result_type t10= AddModP(xQ_var,t9.y); // t10 = xQ + t9 = xQ - xR - typename mult_mod_p_type::result_type t11= MultModP(lambda_var,t10.z); // t11 = lambda * t10 =lambda(xQ-xR) - typename mult_mod_p_type::result_type t12= MultModP(z_var,t1.r); // t12 = z * t1 = z * yQ * lambda - - return typename component_type::result_type(component, start_row_index); - } - - template - std::vector generate_gates( - const plonk_ec_double &component, - circuit> &bp, - assignment> - &assignment, - const typename plonk_ec_double::input_type - &instance_input) { - - // never actually called - return {}; - } - - template - void generate_copy_constraints( - const plonk_ec_double &component, - circuit> &bp, - assignment> - &assignment, - const typename plonk_ec_double::input_type &instance_input, - const std::size_t start_row_index) { - - // all copy constraints are moved to generate_circuit - } - - template - typename plonk_ec_double::result_type generate_circuit( - const plonk_ec_double &component, - circuit> &bp, - assignment> - &assignment, - const typename plonk_ec_double::input_type &instance_input, - const std::size_t start_row_index) { - using component_type = plonk_ec_double; - using var = typename component_type::var; - - using range_check_type = typename component_type::range_check_component; - using check_mod_p_type = typename component_type::check_mod_p_component; - using mult_mod_p_type = typename component_type::mult_mod_p_component; - using add_mod_p_type = typename component_type::add_mod_p_component; - using neg_mod_p_type = typename component_type::neg_mod_p_component; - - using value_type = typename BlueprintFieldType::value_type; - using integral_type = typename BlueprintFieldType::integral_type; - using non_native_value_type = typename NonNativeFieldType::value_type; - using non_native_integral_type = typename NonNativeFieldType::integral_type; - - const std::size_t WA = component.witness_amount(); - - // instances of used subcomponents - range_check_type range_check_instance( component._W, component._C, component._PI); - check_mod_p_type check_mod_p_instance( component._W, component._C, component._PI); - mult_mod_p_type mult_mod_p_instance( component._W, component._C, component._PI); - add_mod_p_type add_mod_p_instance( component._W, component._C, component._PI); - neg_mod_p_type neg_mod_p_instance( component._W, component._C, component._PI); - - var xQ_var[num_chunks], yQ_var[num_chunks], - lambda_var[num_chunks], z_var[num_chunks], xR_var[num_chunks], yR_var[num_chunks]; - - for(std::size_t i = 0; i < num_chunks; i++) { - xQ_var[i] = instance_input.xQ[i]; - yQ_var[i] = instance_input.yQ[i]; - lambda_var[i] = var(component.W(i % WA), start_row_index + i/WA, false); - z_var[i] = var(component.W((num_chunks + i) % WA), start_row_index + (num_chunks + i)/WA,false); - xR_var[i] = var(component.W((2*num_chunks + i) % WA), start_row_index + (2*num_chunks + i)/WA,false); - yR_var[i] = var(component.W((3*num_chunks + i) % WA), start_row_index + (3*num_chunks + i)/WA,false); - } - - // the number of rows used by data storage - std::size_t current_row_shift = (4*num_chunks)/WA + ((4*num_chunks) % WA > 0); - - auto check_chunked_var = [&bp, &assignment, &instance_input, &range_check_instance, &check_mod_p_instance, - &start_row_index, ¤t_row_shift ] (var x[num_chunks]) { - typename range_check_type::input_type range_check_input; - for(std::size_t i = 0; i < num_chunks; i++) { - range_check_input.x[i] = x[i]; - } - generate_circuit(range_check_instance, bp, assignment, range_check_input, start_row_index + current_row_shift); - current_row_shift += range_check_instance.rows_amount; - - typename check_mod_p_type::input_type mod_p_check_input; - for(std::size_t i = 0; i < num_chunks; i++) { - mod_p_check_input.x[i] = x[i]; - mod_p_check_input.pp[i] = instance_input.pp[i]; - } - mod_p_check_input.zero = instance_input.zero; - generate_circuit(check_mod_p_instance, bp, assignment, mod_p_check_input, - start_row_index + current_row_shift); // check_mod_p - current_row_shift += check_mod_p_instance.rows_amount; - }; - // perform range checks and mod p checks on all stored variables - check_chunked_var(lambda_var); - check_chunked_var(z_var); - check_chunked_var(xR_var); - check_chunked_var(yR_var); - - // circuit generation lambda expressions for mod p arithemetic - auto MultModP = [&instance_input, &mult_mod_p_instance, &bp, &assignment, &start_row_index, ¤t_row_shift] - (var x[num_chunks], var y[num_chunks]) { - typename mult_mod_p_type::input_type mult_input; - for(std::size_t i = 0; i < num_chunks; i++) { - mult_input.x[i] = x[i]; - mult_input.y[i] = y[i]; - mult_input.p[i] = instance_input.p[i]; - mult_input.pp[i] = instance_input.pp[i]; - } - mult_input.zero = instance_input.zero; - typename mult_mod_p_type::result_type res = generate_circuit(mult_mod_p_instance, bp, assignment, mult_input, - start_row_index + current_row_shift); - current_row_shift += mult_mod_p_instance.rows_amount; - return res; - }; - auto AddModP = [&instance_input, &add_mod_p_instance, &bp, &assignment, &start_row_index, ¤t_row_shift] - (var x[num_chunks], var y[num_chunks]) { -//std::cout << "Add starting at row " << (start_row_index + current_row_shift) << "\n"; - typename add_mod_p_type::input_type add_input; - for(std::size_t i = 0; i < num_chunks; i++) { - add_input.x[i] = x[i]; - add_input.y[i] = y[i]; - add_input.p[i] = instance_input.p[i]; - add_input.pp[i] = instance_input.pp[i]; - } - add_input.zero = instance_input.zero; - typename add_mod_p_type::result_type res = generate_circuit(add_mod_p_instance, bp, assignment, add_input, - start_row_index + current_row_shift); - current_row_shift += add_mod_p_instance.rows_amount; -//std::cout << "Add ending at row " << (start_row_index + current_row_shift) << "\n"; - return res; - }; - auto NegModP = [&instance_input, &neg_mod_p_instance, &bp, &assignment, &start_row_index, ¤t_row_shift] - (var x[num_chunks]) { - typename neg_mod_p_type::input_type neg_input; - for(std::size_t i = 0; i < num_chunks; i++) { - neg_input.x[i] = x[i]; - neg_input.p[i] = instance_input.p[i]; - neg_input.pp[i] = instance_input.pp[i]; - } - neg_input.zero = instance_input.zero; - typename neg_mod_p_type::result_type res = generate_circuit(neg_mod_p_instance, bp, assignment, neg_input, - start_row_index + current_row_shift); - current_row_shift += neg_mod_p_instance.rows_amount; - return res; - }; - - // Copy constraint generation lambda expression - auto CopyConstrain = [&bp](var x[num_chunks], var y[num_chunks]) { - for(std::size_t i = 0; i < num_chunks; i++) { - bp.add_copy_constraint({x[i], y[i]}); - } - }; - - typename mult_mod_p_type::result_type t1 = MultModP(yQ_var,lambda_var); // t1 = yQ * lambda - typename add_mod_p_type::result_type t2 = AddModP(t1.r,t1.r); // t2 = t1 + t1 = 2yQ * lambda - typename add_mod_p_type::result_type t3 = AddModP(xQ_var,xQ_var); // t3 = xQ + xQ = 2xQ - typename add_mod_p_type::result_type t4 = AddModP(xQ_var,t3.z); // t4 = xQ + t3 = 3xQ - typename mult_mod_p_type::result_type t5 = MultModP(t4.z,xQ_var); // t5 = t4 * xQ = 3xQ^2 - CopyConstrain(t2.z, t5.r); // 2yQ lambda = 3xQ^2 - typename add_mod_p_type::result_type t6 = AddModP(xR_var,t3.z); // t6 = xR + t3 = xR + 2xQ - typename mult_mod_p_type::result_type t7 = MultModP(lambda_var,lambda_var); // t7 = lambda * lambda - CopyConstrain(t6.z, t7.r); // xR + 2xQ = lambda^2 - typename add_mod_p_type::result_type t8 = AddModP(yR_var,yQ_var); // t8 = yR + yQ - typename neg_mod_p_type::result_type t9 = NegModP(xR_var); // t9 = -xR - typename add_mod_p_type::result_type t10= AddModP(xQ_var,t9.y); // t10 = xQ + t9 = xQ - xR - typename mult_mod_p_type::result_type t11= MultModP(lambda_var,t10.z); // t11 = lambda * t10 =lambda(xQ-xR) - CopyConstrain(t8.z, t11.r); // yR + yQ = lambda(xQ - xR) - typename mult_mod_p_type::result_type t12= MultModP(z_var,t1.r); // t12 = z * t1 = z * yQ * lambda - CopyConstrain(lambda_var, t12.r); // lambda = z yQ lambda - - generate_copy_constraints(component, bp, assignment, instance_input, start_row_index); // does nothing, may be skipped? - - return typename component_type::result_type(component, start_row_index); - } - - } // namespace components - } // namespace blueprint -} // namespace nil - -#endif // CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_EC_DOUBLE_ECDSA_HPP \ No newline at end of file diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp new file mode 100644 index 000000000..170907547 --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp @@ -0,0 +1,493 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Alexey Yashunsky +// Copyright (c) 2024 Antoine Cyr +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// +// @file Declaration of interfaces for full addition of EC points over a non-native field +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BBF_COMPONENTS_EC_FULL_ADD_ECDSA_HPP +#define CRYPTO3_BBF_COMPONENTS_EC_FULL_ADD_ECDSA_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nil { + namespace blueprint { + namespace bbf { + namespace components { + // Parameters: num_chunks = k, bit_size_chunk = b + // For points P = (x_P,y_P), Q = (x_Q,y_Q), x_P != x_Q, P,Q != O + // from an elliptic curve over F[p] + // computes R = (x_R, y_R) = P + Q + // Expects input as k-chunked values with b bits per chunk + // p' = 2^(kb) - p + // Input: xP[0],...,xP[k-1],yP[0],...,yP[k-1],xQ[0],...,xQ[k-1], + // yQ[0],...,yQ[k-1], p[0], ..., p[k-1], pp[0], ..., pp[k-1], 0 + // (expects zero constant as input) + // Output: xR[0],...,xR[k-1], + // yR[0],...,yR[k-1] + // + template + struct ec_full_add_raw_input { + using TYPE = typename FieldType::value_type; + std::vector xQ; + std::vector yQ; + std::vector xP; + std::vector yP; + std::vector p; + std::vector pp; + TYPE zero; + }; + + template + class ec_full_add : public generic_component { + using generic_component::allocate; + using generic_component::copy_constrain; + using generic_component::constrain; + using generic_component::lookup; + using component_type = generic_component; + + public: + using typename generic_component::TYPE; + using typename generic_component::context_type; + using typename generic_component::table_params; + using raw_input_type = + typename std::conditional, + std::tuple<>>::type; + + public: + std::vector inp_xP; + std::vector inp_yP; + std::vector inp_xQ; + std::vector inp_yQ; + std::vector inp_p; + std::vector inp_pp; + std::vector res_xR; + std::vector res_yR; + + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::size_t witness = 6 * num_chunks + 1; + constexpr std::size_t public_inputs = 1; + constexpr std::size_t constants = 0; + // rows = 4096-1 so that lookup table is not too hard to fit and + // padding doesn't inflate the table + constexpr std::size_t rows = 4095; + return {witness, public_inputs, constants, rows}; + } + + static std::tuple, std::vector, + std::vector, std::vector, + std::vector, std::vector, TYPE> + form_input(context_type& context_object, raw_input_type raw_input, + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::vector input_xP(num_chunks); + std::vector input_yP(num_chunks); + std::vector input_xQ(num_chunks); + std::vector input_yQ(num_chunks); + std::vector input_p(num_chunks); + std::vector input_pp(num_chunks); + TYPE input_zero; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; i++) { + input_xP[i] = raw_input.xP[i]; + input_yP[i] = raw_input.yP[i]; + input_xQ[i] = raw_input.xQ[i]; + input_yQ[i] = raw_input.yQ[i]; + input_p[i] = raw_input.p[i]; + input_pp[i] = raw_input.pp[i]; + } + input_zero = raw_input.zero; + } + for (std::size_t i = 0; i < num_chunks; i++) { + context_object.allocate(input_xP[i], 0, i, + column_type::public_input); + context_object.allocate(input_yP[i], 0, i + num_chunks, + column_type::public_input); + context_object.allocate(input_xQ[i], 0, i + 2 * num_chunks, + column_type::public_input); + context_object.allocate(input_yQ[i], 0, i + 3 * num_chunks, + column_type::public_input); + context_object.allocate(input_p[i], 0, i + 4 * num_chunks, + column_type::public_input); + context_object.allocate(input_pp[i], 0, i + 5 * num_chunks, + column_type::public_input); + } + context_object.allocate(input_zero, 0, 6 * num_chunks, + column_type::public_input); + return std::make_tuple(input_xP, input_yP, input_xQ, input_yQ, + input_p, input_pp, input_zero); + } + + ec_full_add(context_type& context_object, std::vector input_xP, + std::vector input_yP, std::vector input_xQ, + std::vector input_yQ, std::vector input_p, + std::vector input_pp, TYPE input_zero, + std::size_t num_chunks, std::size_t bit_size_chunk, + bool make_links = true) + : generic_component(context_object) { + using integral_type = typename FieldType::integral_type; + using NON_NATIVE_TYPE = typename NonNativeFieldType::value_type; + using non_native_integral_type = + typename NonNativeFieldType::integral_type; + + using Choice_Function = + typename bbf::components::choice_function; + using Range_Check = + typename bbf::components::range_check_multi; + using Check_Mod_P = + typename bbf::components::check_mod_p; + using Addition_Mod_P = + typename bbf::components::addition_mod_p; + using Negation_Mod_P = + typename bbf::components::negation_mod_p; + using Multiplication_Mod_P = + typename bbf::components::flexible_multiplication< + FieldType, stage, NonNativeFieldType>; + + std::vector XP(num_chunks); + std::vector YP(num_chunks); + std::vector XQ(num_chunks); + std::vector YQ(num_chunks); + std::vector P(num_chunks); + std::vector PP(num_chunks); + TYPE ZERO; + + std::vector LAMBDA(num_chunks); + std::vector XR(num_chunks); + std::vector YR(num_chunks); + std::vector ZP(num_chunks); + std::vector ZQ(num_chunks); + std::vector ZPQ(num_chunks); + std::vector WPQ(num_chunks); + std::vector ZEROv(num_chunks); + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; ++i) { + XP[i] = input_xP[i]; + YP[i] = input_yP[i]; + XQ[i] = input_xQ[i]; + YQ[i] = input_yQ[i]; + P[i] = input_p[i]; + PP[i] = input_pp[i]; + } + ZERO = input_zero; + + non_native_integral_type pow = 1; + NON_NATIVE_TYPE xP = 0, yP = 0, xQ = 0, yQ = 0; + + for (std::size_t i = 0; i < num_chunks; ++i) { + xP += non_native_integral_type( + integral_type(input_xP[i].data)) * + pow; + yP += non_native_integral_type( + integral_type(input_yP[i].data)) * + pow; + xQ += non_native_integral_type( + integral_type(input_xQ[i].data)) * + pow; + yQ += non_native_integral_type( + integral_type(input_yQ[i].data)) * + pow; + pow <<= bit_size_chunk; + } + + NON_NATIVE_TYPE + lambda, xR, yR, + // indicator variables + zP = (yP == 0) ? 0 : yP.inversed(), + zQ = (yQ == 0) ? 0 : yQ.inversed(), + zPQ = (xP == xQ) ? 0 : (xP - xQ).inversed(), + wPQ = ((xP == xQ) && (yP + yQ != 0)) + ? (yP + yQ).inversed() + : 0; + + if (yP == 0) { + xR = xQ; + yR = yQ; + // lambda doesn't matter for (xR,yR), but needs to satisfy + // the constraints + lambda = + (xP == xQ) ? 0 : (yQ - yP) * ((xQ - xP).inversed()); + } else if (yQ == 0) { + xR = xP; + yR = yP; + // lambda doesn't matter for (xR,yR), but needs to satisfy + // the constraints + lambda = + (xP == xQ) ? 0 : (yQ - yP) * ((xQ - xP).inversed()); + } else if ((xP == xQ) && (yP + yQ == 0)) { + xR = 0; + yR = 0; + // lambda doesn't matter for (xR,yR), but needs to satisfy + // the constraints + lambda = 3 * xP * xP * ((2 * yP).inversed()); + } else { + if (xP == xQ) { // point doubling + lambda = 3 * xP * xP * ((2 * yP).inversed()); + } else { // regular addition + NON_NATIVE_TYPE diff = xQ - xP; + lambda = (yQ - yP) * (diff.inversed()); + } + xR = lambda * lambda - xP - xQ, + yR = lambda * (xP - xR) - yP; + } + + auto base = [num_chunks, bit_size_chunk](NON_NATIVE_TYPE x) { + std::vector res(num_chunks); + non_native_integral_type mask = + (non_native_integral_type(1) << bit_size_chunk) - 1; + non_native_integral_type x_value = + non_native_integral_type(x.data); + for (std::size_t i = 0; i < num_chunks; i++) { + res[i] = TYPE(x_value & mask); + x_value >>= bit_size_chunk; + } + return res; + }; + + LAMBDA = base(lambda); + XR = base(xR); + YR = base(yR); + ZP = base(zP), ZQ = base(zQ), ZPQ = base(zPQ), + WPQ = base(wPQ); + } + + for (std::size_t i = 0; i < num_chunks; ++i) { + allocate(XP[i]); + allocate(YP[i]); + allocate(XQ[i]); + allocate(YQ[i]); + allocate(P[i]); + allocate(PP[i]); + + allocate(LAMBDA[i]); + allocate(XR[i]); + allocate(YR[i]); + allocate(ZP[i]); + allocate(ZQ[i]); + allocate(ZPQ[i]); + allocate(WPQ[i]); + + ZEROv[i] = ZERO; + allocate(ZEROv[i]); + } + allocate(ZERO); + + auto check_chunked = [&context_object, num_chunks, bit_size_chunk, + PP, ZERO](std::vector x) { + Range_Check rc = Range_Check(context_object, x, num_chunks, + bit_size_chunk); + Check_Mod_P cm = Check_Mod_P(context_object, x, PP, ZERO, + num_chunks, bit_size_chunk); + }; + + // Copy constraint generation lambda expression + auto CopyConstrain = [this, num_chunks](std::vector x, + std::vector y) { + for (std::size_t i = 0; i < num_chunks; i++) { + copy_constrain(x[i], y[i]); + } + }; + + // perform range checks and mod p checks on all stored variables + check_chunked(LAMBDA); + check_chunked(Z); + check_chunked(XR); + check_chunked(YR); + check_chunked(ZP); + check_chunked(ZQ); + check_chunked(ZPQ); + check_chunked(WPQ); + + auto MultModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x, + std::vector y) { + Multiplication_Mod_P t = + Multiplication_Mod_P(context_object, x, y, P, PP, ZERO, + num_chunks, bit_size_chunk); + return t.res_r; + }; + auto AddModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x, + std::vector y) { + Addition_Mod_P t = + Addition_Mod_P(context_object, x, y, P, PP, ZERO, + num_chunks, bit_size_chunk); + return t.res_r; + }; + auto NegModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x) { + Negation_Mod_P t = + Negation_Mod_P(context_object, x, P, PP, ZERO, num_chunks, + bit_size_chunk); + return t.res_r; + }; + + // part 1 + auto t1 = NegModP(XQ); // t1 = -xQ + auto t2 = NegModP(YQ); // t2 = -yQ + auto t3 = NegModP(XP); // t3 = -xP + auto t4 = NegModP(YP); // t4 = -yP + auto t5 = AddModP(XR, t1); // t5 = xR - xQ + auto t6 = AddModP(YR, t2); // t6 = yR - yQ + auto t7 = AddModP(XR, t3); // t5 = xR - xP + auto t8 = AddModP(YR, t4); // t6 = yR - yP + auto t9 = AddModP(XP, t1); // t9 = xP - xQ + auto t10 = MultModP(YP, ZP); // t10 = yP * zP + auto t11 = MultModP(YQ, ZQ); // t11 = yQ * zQ + auto t12 = MultModP(t9, ZPQ); // t12 = (xP - xQ) zPQ = ZPQ + auto t13 = MultModP(t5, t10); // t13 = (xR - xQ) yP zP + CopyConstrain(t5, t13); // t5 = t13 + auto t14 = MultModP(t6, t10); // t14 = (yR - yQ) yP zP + CopyConstrain(t6, t14); // t6 = t14 + auto t15 = MultModP(t7, t11); // t15 = (xR - xP) yQ zQ + CopyConstrain(t7, t15); // t7 = t15 + auto t16 = MultModP(t8, t11); // t16 = (yR - yP) yQ zQ + CopyConstrain(t8, t16); // t8 = t16 + auto t17 = MultModP(t9, t12); // t17 = (xP - xQ) ZPQ + CopyConstrain(t9, t17); // t9 = t17 + + // part 2 + auto t18 = AddModP(YP, YQ); // t18 = yP + yQ + auto t19 = MultModP(t18, WPQ); // t19 = (yP + yQ) wPQ = WPQ + auto t20 = AddModP(t12, t19); // t20 = ZPQ + WPQ + auto t21 = MultModP(XR, t20); // t21 = xR(ZPQ + WPQ) + CopyConstrain(XR, t21); // xR = t21 + auto t22 = MultModP(YR, t20); // t22 = yR(ZPQ + WPQ) + CopyConstrain(YR, t22); // yR = t22 + + // part 3 + auto t23 = NegModP(t12); // t23 = -ZPQ + auto t24 = MultModP(t18, t23); // t24 = -(yP + yQ) ZPQ + auto t25 = AddModP(t18, t24); // t25 = (yP + yQ)(1 - ZPQ) + auto t26 = AddModP(t9, t25); // t26 = (xP - xQ) + (yP + yQ)(1 - ZPQ) + auto t27 = MultModP(YP, YQ); // t27 = yP * yQ + auto t28 = MultModP(t26, t27); // t28 = yP yQ (xP - xQ + (yP + yQ)(1 - ZPQ)) + auto t29 = MultModP(LAMBDA, LAMBDA); // t29 = lambda * lambda + auto t30 = NegModP(t29); // t30 = -lambda^2 + auto t31 = AddModP(XR, t30); // t31 = xR - lambda^2 + auto t32 = AddModP(t31, XP); // t32 = xR - lambda^2 + xP + auto t33 = AddModP(t32, XQ); // t33 = xR - lambda^2 + xP + xQ + auto t34 = AddModP(YR, YP); // t34 = yR + yP + auto t35 = MultModP(t7, LAMBDA); // t35 = (xR - xP) lambda + auto t36 = AddModP(t34, t35); // t36 = yR + yP + (xR - xP)lambda + auto t37 = MultModP(t28, t33); // t37 = yP yQ (xP - xQ + (yP + yQ)(1 - ZPQ))(xR - lambda^2 + xP + xQ) + CopyConstrain(t37, ZEROv); // t37 = 0 + auto t38 = MultModP(t28, t36); // t38 = yP yQ (xP - xQ + (yP + yQ)(1 -ZPQ))(yR + yP + (xR - xP)lambda) + CopyConstrain(t38, ZEROv); // t38 = 0 + + // part 4 + auto t39 = MultModP(t9, LAMBDA); // t39 = (xP - xQ) lambda + auto t40 = AddModP(t39, t4); // t40 = (xP - xQ) lambda - yP + auto t41 = AddModP(t40, YQ); // t41 = (xP - xQ) lambda - yP + yQ + auto t42 = MultModP(t9, t41); // t42 = (xP - xQ)((xP - xQ) lambda - yP + yQ) + CopyConstrain(t42, ZEROv); // t42 = 0 + auto t43 = MultModP(XP, t3); // t43 = -xP^2 + auto t44 = AddModP(t43, t43); // t44 = -2xP^2 + auto t45 = AddModP(t43, t44); // t45 = -3xP^2 + auto t46 = AddModP(YP, YP); // t46 = 2yP + auto t47 = MultModP(t46, LAMBDA); // t47 = 2yP lambda + auto t48 = AddModP(t47, t45); // t48 = 2yP lambda - 3xP^2 + auto t49 = MultModP(t48, t12); // t49 = (2yP lambda - 3xP^2) ZPQ + CopyConstrain(t48, t49); // t38 = 0t48 = t49 + + if (make_links) { + for (std::size_t i = 0; i < num_chunks; ++i) { + copy_constrain(XP[i], input_xP[i]); + copy_constrain(YP[i], input_yP[i]); + copy_constrain(XQ[i], input_xQ[i]); + copy_constrain(YQ[i], input_yQ[i]); + copy_constrain(P[i], input_p[i]); + copy_constrain(PP[i], input_pp[i]); + } + copy_constrain(ZERO, input_zero); + } + + for (int i = 0; i < num_chunks; ++i) { + inp_xP.push_back(input_xP[i]); + inp_yP.push_back(input_yP[i]); + inp_xQ.push_back(input_xQ[i]); + inp_yQ.push_back(input_yQ[i]); + inp_pp.push_back(input_p[i]); + inp_pp.push_back(input_pp[i]); + } + for (int i = 0; i < num_chunks; ++i) { + res_xR.push_back(XR[i]); + res_yR.push_back(YR[i]); + } + } + }; + + template + class pallas_ec_full_add + : public ec_full_add< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { + using Base = + ec_full_add; + + public: + using Base::Base; + }; + + template + class vesta_ec_full_add + : public ec_full_add< + FieldType, stage, + crypto3::algebra::curves::vesta::base_field_type> { + using Base = + ec_full_add; + + public: + using Base::Base; + }; + + } // namespace components + } // namespace bbf + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BBF_COMPONENTS_EC_FULL_ADD_ECDSA_HPP diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp new file mode 100644 index 000000000..a01b01b06 --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp @@ -0,0 +1,389 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Alexey Yashunsky +// Copyright (c) 2024 Antoine Cyr +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// +// @file Declaration of interfaces for full addition of EC points over a non-native field +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BBF_COMPONENTS_EC_INCOMPLETE_ADD_ECDSA_HPP +#define CRYPTO3_BBF_COMPONENTS_EC_INCOMPLETE_ADD_ECDSA_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nil { + namespace blueprint { + namespace bbf { + namespace components { + // Parameters: num_chunks = k, bit_size_chunk = b + // For points P = (x_P,y_P), Q = (x_Q,y_Q), x_P != x_Q, P,Q != O + // from an elliptic curve over F[p] + // computes R = (x_R, y_R) = P + Q + // Expects input as k-chunked values with b bits per chunk + // p' = 2^(kb) - p + // Input: xP[0],...,xP[k-1],yP[0],...,yP[k-1],xQ[0],...,xQ[k-1], + // yQ[0],...,yQ[k-1], p[0], ..., p[k-1], pp[0], ..., pp[k-1], 0 + // (expects zero constant as input) + // Output: xR[0],...,xR[k-1], yR[0],...,yR[k-1] + // + template + struct ec_incomplete_add_raw_input { + using TYPE = typename FieldType::value_type; + std::vector xQ; + std::vector yQ; + std::vector xP; + std::vector yP; + std::vector p; + std::vector pp; + TYPE zero; + }; + + template + class ec_incomplete_add : public generic_component { + using generic_component::allocate; + using generic_component::copy_constrain; + using generic_component::constrain; + using generic_component::lookup; + using component_type = generic_component; + + public: + using typename generic_component::TYPE; + using typename generic_component::context_type; + using typename generic_component::table_params; + using raw_input_type = + typename std::conditional, + std::tuple<>>::type; + + public: + std::vector inp_xP; + std::vector inp_yP; + std::vector inp_xQ; + std::vector inp_yQ; + std::vector inp_p; + std::vector inp_pp; + std::vector res_xR; + std::vector res_yR; + + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::size_t witness = 6 * num_chunks + 1; + constexpr std::size_t public_inputs = 1; + constexpr std::size_t constants = 0; + // rows = 4096-1 so that lookup table is not too hard to fit and + // padding doesn't inflate the table + constexpr std::size_t rows = 4095; + return {witness, public_inputs, constants, rows}; + } + + static std::tuple, std::vector, + std::vector, std::vector, + std::vector, std::vector, TYPE> + form_input(context_type& context_object, raw_input_type raw_input, + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::vector input_xP(num_chunks); + std::vector input_yP(num_chunks); + std::vector input_xQ(num_chunks); + std::vector input_yQ(num_chunks); + std::vector input_p(num_chunks); + std::vector input_pp(num_chunks); + TYPE input_zero; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; i++) { + input_xP[i] = raw_input.xP[i]; + input_yP[i] = raw_input.yP[i]; + input_xQ[i] = raw_input.xQ[i]; + input_yQ[i] = raw_input.yQ[i]; + input_p[i] = raw_input.p[i]; + input_pp[i] = raw_input.pp[i]; + } + input_zero = raw_input.zero; + } + for (std::size_t i = 0; i < num_chunks; i++) { + context_object.allocate(input_xP[i], 0, i, + column_type::public_input); + context_object.allocate(input_yP[i], 0, i + num_chunks, + column_type::public_input); + context_object.allocate(input_xQ[i], 0, i + 2 * num_chunks, + column_type::public_input); + context_object.allocate(input_yQ[i], 0, i + 3 * num_chunks, + column_type::public_input); + context_object.allocate(input_p[i], 0, i + 4 * num_chunks, + column_type::public_input); + context_object.allocate(input_pp[i], 0, i + 5 * num_chunks, + column_type::public_input); + } + context_object.allocate(input_zero, 0, 6 * num_chunks, + column_type::public_input); + return std::make_tuple(input_xP, input_yP, input_xQ, input_yQ, + input_p, input_pp, input_zero); + } + + ec_incomplete_add(context_type& context_object, + std::vector input_xP, + std::vector input_yP, + std::vector input_xQ, + std::vector input_yQ, + std::vector input_p, + std::vector input_pp, TYPE input_zero, + std::size_t num_chunks, std::size_t bit_size_chunk, + bool make_links = true) + : generic_component(context_object) { + using integral_type = typename FieldType::integral_type; + using NON_NATIVE_TYPE = typename NonNativeFieldType::value_type; + using non_native_integral_type = + typename NonNativeFieldType::integral_type; + + using Choice_Function = + typename bbf::components::choice_function; + using Range_Check = + typename bbf::components::range_check_multi; + using Check_Mod_P = + typename bbf::components::check_mod_p; + using Addition_Mod_P = + typename bbf::components::addition_mod_p; + using Negation_Mod_P = + typename bbf::components::negation_mod_p; + using Multiplication_Mod_P = + typename bbf::components::flexible_multiplication< + FieldType, stage, NonNativeFieldType>; + + std::vector XP(num_chunks); + std::vector YP(num_chunks); + std::vector XQ(num_chunks); + std::vector YQ(num_chunks); + std::vector P(num_chunks); + std::vector PP(num_chunks); + TYPE ZERO; + + std::vector LAMBDA(num_chunks); + std::vector XR(num_chunks); + std::vector YR(num_chunks); + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; ++i) { + XP[i] = input_xP[i]; + YP[i] = input_yP[i]; + XQ[i] = input_xQ[i]; + YQ[i] = input_yQ[i]; + P[i] = input_p[i]; + PP[i] = input_pp[i]; + } + ZERO = input_zero; + + non_native_integral_type pow = 1; + NON_NATIVE_TYPE xP = 0, yP = 0, xQ = 0, yQ = 0; + + for (std::size_t i = 0; i < num_chunks; ++i) { + xP += non_native_integral_type( + integral_type(input_xP[i].data)) * + pow; + yP += non_native_integral_type( + integral_type(input_yP[i].data)) * + pow; + xQ += non_native_integral_type( + integral_type(input_xQ[i].data)) * + pow; + yQ += non_native_integral_type( + integral_type(input_yQ[i].data)) * + pow; + pow <<= bit_size_chunk; + } + + NON_NATIVE_TYPE lambda = + (xQ == xP) + ? 0 + : (yQ - yP) * ((xQ - xP).inversed()), + xR = lambda * lambda - xP - xQ, + yR = lambda * (xP - xR) - yP; + + auto base = [num_chunks, bit_size_chunk](NON_NATIVE_TYPE x) { + std::vector res(num_chunks); + non_native_integral_type mask = + (non_native_integral_type(1) << bit_size_chunk) - 1; + non_native_integral_type x_value = + non_native_integral_type(x.data); + for (std::size_t i = 0; i < num_chunks; i++) { + res[i] = TYPE(x_value & mask); + x_value >>= bit_size_chunk; + } + return res; + }; + + LAMBDA = base(lambda); + XR = base(xR); + YR = base(yR); + } + + for (std::size_t i = 0; i < num_chunks; ++i) { + allocate(XP[i]); + allocate(YP[i]); + allocate(XQ[i]); + allocate(YQ[i]); + allocate(P[i]); + allocate(PP[i]); + + allocate(LAMBDA[i]); + allocate(XR[i]); + allocate(YR[i]); + } + allocate(ZERO); + + auto check_chunked = [&context_object, num_chunks, bit_size_chunk, + PP, ZERO](std::vector x) { + Range_Check rc = Range_Check(context_object, x, num_chunks, + bit_size_chunk); + Check_Mod_P cm = Check_Mod_P(context_object, x, PP, ZERO, + num_chunks, bit_size_chunk); + }; + + // Copy constraint generation lambda expression + auto CopyConstrain = [this, num_chunks](std::vector x, + std::vector y) { + for (std::size_t i = 0; i < num_chunks; i++) { + copy_constrain(x[i], y[i]); + } + }; + + // perform range checks and mod p checks on all stored variables + check_chunked(LAMBDA); + check_chunked(XR); + check_chunked(YR); + + auto MultModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x, + std::vector y) { + Multiplication_Mod_P t = + Multiplication_Mod_P(context_object, x, y, P, PP, ZERO, + num_chunks, bit_size_chunk); + return t.res_r; + }; + auto AddModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x, + std::vector y) { + Addition_Mod_P t = + Addition_Mod_P(context_object, x, y, P, PP, ZERO, + num_chunks, bit_size_chunk); + return t.res_r; + }; + auto NegModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x) { + Negation_Mod_P t = + Negation_Mod_P(context_object, x, P, PP, ZERO, num_chunks, + bit_size_chunk); + return t.res_r; + }; + + auto t1 = NegModP(XP); // t1 = -xP + auto t2 = AddModP(XQ, t1); // t2 = xQ + t1 = xQ - xP + auto t3 = MultModP(t2, LAMBDA); // t3 = t2 * lambda = (xQ-xP)lambda + auto t4 = AddModP(t3, YP); // t4 = t3 + yP = (xQ-xP)lambda + yP + CopyConstrain(t4, YQ); // (xQ - xP)lambda + yP = yQ + auto t5 = AddModP(XR, XP); // t5 = xR + xP + auto t6 = AddModP(t5, XQ); // t6 = t5 + xQ = xR + xP + xQ + auto t7 = MultModP(LAMBDA, LAMBDA); // t7 = lambda * lambda + CopyConstrain(t6, t7); // xR + xP + xQ = lambda^2 + auto t8 = AddModP(YR, YP); // t8 = yR + yP + auto t9 = NegModP(XR); // t9 = -xR + auto t10 = AddModP(XP, t9); // t10 = xP + t9 = xP - xR + auto t11 = MultModP(LAMBDA,t10); // t11 = lambda * t10 =lambda(xP-xR) + CopyConstrain(t8, t11); // yR + yP = lambda(xP - xR) + + if (make_links) { + for (std::size_t i = 0; i < num_chunks; ++i) { + copy_constrain(XP[i], input_xP[i]); + copy_constrain(YP[i], input_yP[i]); + copy_constrain(XQ[i], input_xQ[i]); + copy_constrain(YQ[i], input_yQ[i]); + copy_constrain(P[i], input_p[i]); + copy_constrain(PP[i], input_pp[i]); + } + copy_constrain(ZERO, input_zero); + } + + for (int i = 0; i < num_chunks; ++i) { + inp_xP.push_back(input_xP[i]); + inp_yP.push_back(input_yP[i]); + inp_xQ.push_back(input_xQ[i]); + inp_yQ.push_back(input_yQ[i]); + inp_pp.push_back(input_p[i]); + inp_pp.push_back(input_pp[i]); + } + for (int i = 0; i < num_chunks; ++i) { + res_xR.push_back(XR[i]); + res_yR.push_back(YR[i]); + } + } + }; + + template + class pallas_ec_incomplete_add + : public ec_incomplete_add< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { + using Base = ec_incomplete_add< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type>; + + public: + using Base::Base; + }; + + template + class vesta_ec_incomplete_add + : public ec_incomplete_add< + FieldType, stage, + crypto3::algebra::curves::vesta::base_field_type> { + using Base = ec_incomplete_add< + FieldType, stage, + crypto3::algebra::curves::vesta::base_field_type>; + + public: + using Base::Base; + }; + + } // namespace components + } // namespace bbf + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BBF_COMPONENTS_EC_INCOMPLETE_ADD_ECDSA_HPP diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp index 5624e025b..8fea6ac38 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp @@ -1,6 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Valeh Farzaliyev -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -22,7 +22,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //---------------------------------------------------------------------------// -// @file Declaration of interfaces for FRI verification array swapping component. +// @file Declaration of interfaces for addition function on mod p. //---------------------------------------------------------------------------// #ifndef CRYPTO3_BBF_COMPONENTS_ADDITION_MOD_P_HPP @@ -52,8 +52,8 @@ namespace nil { // operates on k-chunked x,y, p, p' // Parameters: num_chunks = k, bit_size_chunk = b // Input: x[0], ..., x[k-1], y[0], ..., y[k-1], p[0], ..., p[k-1], p'[0], ..., p'[k-1], 0 - // Intemmediate values: q, t[0], ..., t[k-1], carry[k-1], t'[0], ..., t'[k-1], t"[0], ..., t"[k-1], carry"[k-1] - // Output: z[0] = x[0] + y[0] - qp[0], ..., z[k-1] = x[k-1] + y[k-1] -qp[k-1] + // Intermediate values: q, t[0], ..., t[k-1], carry[k-1], t'[0], ..., t'[k-1], t"[0], ..., t"[k-1], carry"[k-1] + // Output: r[0] = x[0] + y[0] - qp[0], ..., r[k-1] = x[k-1] + y[k-1] -qp[k-1] // template @@ -111,7 +111,7 @@ namespace nil { std::vector inp_y; std::vector inp_p; std::vector inp_pp; - std::vector res_z; + std::vector res_r; static table_params get_minimal_requirements( std::size_t num_chunks, std::size_t bit_size_chunk) { @@ -234,24 +234,24 @@ namespace nil { Carry_On_Addition ca_1 = Carry_On_Addition( context_object, X, Y, num_chunks, bit_size_chunk); - Range_Check rc_1 = Range_Check(context_object, ca_1.res_z, + Range_Check rc_1 = Range_Check(context_object, ca_1.res_r, num_chunks, bit_size_chunk); //(qp = 0 or p) Choice_Function cf = Choice_Function(context_object, Q, ZERO, P, num_chunks); Carry_On_Addition ca_2 = - Carry_On_Addition(context_object, cf.res_z, Z, num_chunks, + Carry_On_Addition(context_object, cf.res_r, Z, num_chunks, bit_size_chunk); // qp + z // carry_on_addition results should be equal to each other x + y = z + qp for (std::size_t i = 0; i < num_chunks; i++) { - copy_constrain(ca_1.res_z[i], ca_2.res_z[i]); + copy_constrain(ca_1.res_r[i], ca_2.res_r[i]); } copy_constrain(ca_1.res_c, ca_2.res_c); - Range_Check rc_2 = Range_Check(context_object, ca_2.res_z, + Range_Check rc_2 = Range_Check(context_object, ca_2.res_r, num_chunks, bit_size_chunk); Range_Check rc_3 = @@ -277,7 +277,7 @@ namespace nil { inp_pp.push_back(input_pp[i]); } for (int i = 0; i < num_chunks; ++i) { - res_z.push_back(Z[i]); + res_r.push_back(Z[i]); } } }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp index ff0ca66a7..bb2e916f5 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp @@ -125,7 +125,7 @@ namespace nil { using Range_Check = typename bbf::components::range_check_multi; Carry_On_Addition ca = Carry_On_Addition(context_object,input_x,input_pp,num_chunks,bit_size_chunk); - Range_Check rc = Range_Check(context_object, ca.res_z,num_chunks,bit_size_chunk); + Range_Check rc = Range_Check(context_object, ca.res_r,num_chunks,bit_size_chunk); if(expect_output){ output = ca.res_c; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp index e65666ccb..458344a76 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp @@ -86,7 +86,7 @@ namespace nil { std::vector inp_y; std::vector inp_p; std::vector inp_pp; - std::vector res_z; + std::vector res_r; static table_params get_minimal_requirements(std::size_t num_chunks,std::size_t bit_size_chunk) { //The 6 variables chunks fit in 2 rows, and there is a 3rd additionnal row available for the constraint values @@ -321,7 +321,7 @@ namespace nil { inp_pp.push_back(input_pp[i]); } for (int i = 0; i < num_chunks; ++i) { - res_z.push_back(R[i]); + res_r.push_back(R[i]); } } diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp index dafb76010..da476ba85 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp @@ -1,7 +1,7 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Georgios Fotiadis // Copyright (c) 2024 Alexey Yashunsky -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -23,7 +23,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //---------------------------------------------------------------------------// -// @file Declaration of interfaces for FRI verification array swapping component. +// @file Declaration of interfaces for negation function on mod p. //---------------------------------------------------------------------------// #ifndef CRYPTO3_BBF_COMPONENTS_NEGATION_MOD_P_HPP @@ -50,9 +50,9 @@ namespace nil { namespace bbf { namespace components { // Parameters: num_chunks = k, bit_size_chunk = b - // Finding the negative y of integer x, modulo p and checking that x + y = 0 mod p + // Finding the negative r of integer x, modulo p and checking that x + r = 0 mod p // Input: x[0], ..., x[k-1], p[0], ..., p[k-1], pp[0], ..., pp[k-1], 0 (expects zero constant as input) - // Output: y[0], ..., y[k-1] + // Output: r[0], ..., r[k-1] template struct negation_mod_p_raw_input { @@ -107,7 +107,7 @@ namespace nil { std::vector inp_x; std::vector inp_p; std::vector inp_pp; - std::vector res_z; + std::vector res_r; static table_params get_minimal_requirements( std::size_t num_chunks, std::size_t bit_size_chunk) { @@ -224,7 +224,7 @@ namespace nil { // x + y = 0 or p for (std::size_t i = 0; i < num_chunks; i++) { - copy_constrain(ca.res_z[i], cf.res_z[i]); + copy_constrain(ca.res_r[i], cf.res_r[i]); } copy_constrain(ca.res_c, ZERO[0]); @@ -249,7 +249,7 @@ namespace nil { inp_pp.push_back(input_pp[i]); } for (int i = 0; i < num_chunks; ++i) { - res_z.push_back(Y[i]); + res_r.push_back(Y[i]); } } }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp index 59c6d9c45..de5d51dac 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp @@ -66,7 +66,7 @@ namespace nil { public: std::vector inp_x; std::vector inp_y; - std::vector res_z; + std::vector res_r; TYPE res_c; static table_params get_minimal_requirements(std::size_t num_chunks,std::size_t bit_size_chunk) { @@ -137,7 +137,7 @@ namespace nil { for (int i = 0; i < num_chunks; ++i) { inp_x.push_back(input_x[i]); inp_y.push_back(input_y[i]); - res_z.push_back(Z[i]); + res_r.push_back(Z[i]); } res_c = C[num_chunks-1]; } diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp index 6b3e02396..319a86447 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp @@ -1,6 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Alexey Yashunsky -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -65,7 +65,7 @@ namespace nil { public: TYPE inp_q; - std::vector inp_x, inp_y, res_z; + std::vector inp_x, inp_y, res_r; static table_params get_minimal_requirements(std::size_t num_chunks) { std::size_t witness = num_chunks + 1; @@ -133,7 +133,7 @@ namespace nil { for (std::size_t i = 0; i < num_chunks; i++) { inp_x.push_back(X[i]); inp_y.push_back(Y[i]); - res_z.push_back(Z[i]); + res_r.push_back(Z[i]); } }; }; diff --git a/crypto3/libs/blueprint/test/CMakeLists.txt b/crypto3/libs/blueprint/test/CMakeLists.txt index afa4cd20d..8ef649a41 100644 --- a/crypto3/libs/blueprint/test/CMakeLists.txt +++ b/crypto3/libs/blueprint/test/CMakeLists.txt @@ -107,6 +107,8 @@ set(COMMON_TEST_FILES "bbf/algebra/fields/non_native/negation_mod_p" "bbf/algebra/fields/non_native/flexible_multiplication" "bbf/algebra/curves/weierstrass/ec_double" + "bbf/algebra/curves/weierstrass/ec_full_add" + "bbf/algebra/curves/weierstrass/ec_incomplete_add" ) set(NON_NATIVE_TESTS_FILES diff --git a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp index b0335aa7a..55b093ccd 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------// -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -22,7 +22,7 @@ // SOFTWARE. //---------------------------------------------------------------------------// -#define BOOST_TEST_MODULE bbf_check_mod_p_test +#define BOOST_TEST_MODULE bbf_ec_double_test #include #include diff --git a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp new file mode 100644 index 000000000..7b727ab1a --- /dev/null +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp @@ -0,0 +1,253 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Antoine Cyr +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE bbf_ec_full_add_test + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace nil; +using namespace nil::blueprint; + +template +void test_ec_full_add( + const std::vector& public_input) { + using FieldType = BlueprintFieldType; + using TYPE = typename FieldType::value_type; + using NON_NATIVE_TYPE = typename NonNativeFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using non_native_integral_type = typename BlueprintFieldType::integral_type; + + + non_native_integral_type pow = 1; + + NON_NATIVE_TYPE xP = 0, yP = 0, xQ = 0, yQ = 0; + + for (std::size_t i = 0; i < num_chunks; ++i) { + xP += non_native_integral_type( + integral_type(public_input[i].data)) * + pow; + yP += non_native_integral_type( + integral_type(public_input[i + num_chunks].data)) * + pow; + xQ += non_native_integral_type( + integral_type(public_input[i + 2* num_chunks].data)) * + pow; + yQ += non_native_integral_type( + integral_type(public_input[i + 3*num_chunks].data)) * + pow; + pow <<= bit_size_chunk; + } + + NON_NATIVE_TYPE + lambda, expected_xR, expected_yR, + // indicator variables + zP = (yP == 0)? 0 : yP.inversed(), + zQ = (yQ == 0)? 0 : yQ.inversed(), + zPQ= (xP == xQ)? 0 : (xP - xQ).inversed(), + wPQ= ((xP == xQ) && (yP + yQ != 0))? (yP + yQ).inversed() : 0; + + if (yP == 0) { + expected_xR = xQ; + expected_yR = yQ; + // lambda doesn't matter for (xR,yR), but needs to satisfy the constraints + lambda = (xP == xQ)? 0 : (yQ - yP)*((xQ - xP).inversed()); + } else if (yQ == 0) { + expected_xR = xP; + expected_yR = yP; + // lambda doesn't matter for (xR,yR), but needs to satisfy the constraints + lambda = (xP == xQ)? 0 : (yQ - yP)*((xQ - xP).inversed()); + } else if ((xP == xQ) && (yP + yQ == 0)) { + expected_xR = 0; + expected_yR = 0; + // lambda doesn't matter for (xR,yR), but needs to satisfy the constraints + lambda = 3*xP*xP*((2*yP).inversed()); + } else { + if (xP == xQ) { // point doubling + lambda = 3*xP*xP*((2*yP).inversed()); + } else { // regular addition + NON_NATIVE_TYPE diff = xQ - xP; + lambda = (yQ - yP)*(diff.inversed()); + } + expected_xR = lambda*lambda - xP - xQ, + expected_yR = lambda*(xP - expected_xR) - yP; + } + + + auto assign_and_check = [&](auto& B, auto& raw_input) { + raw_input.xP = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.yP = + std::vector(public_input.begin() + num_chunks, public_input.begin() + 2 * num_chunks); + raw_input.xQ = + std::vector(public_input.begin() + 2*num_chunks, public_input.begin() + 3 * num_chunks); + raw_input.yQ = + std::vector(public_input.begin() + 3*num_chunks, public_input.begin() + 4 * num_chunks); + raw_input.p = std::vector(public_input.begin() + 4 * num_chunks, + public_input.begin() + 5 * num_chunks); + raw_input.pp = std::vector(public_input.begin() + 5 * num_chunks, + public_input.begin() + 6 * num_chunks); + raw_input.zero = public_input[6 * num_chunks]; + + auto [at, A, desc] = B.assign(raw_input); + bool pass = B.is_satisfied(at); + std::cout << "Is_satisfied = " << pass << std::endl; + + assert(pass == true); + non_native_integral_type xR = 0; + non_native_integral_type yR = 0; + pow = 1; + for (std::size_t i = 0; i < num_chunks; i++) { + xR += non_native_integral_type(integral_type(A.res_xR[i].data)) * pow; + yR += non_native_integral_type(integral_type(A.res_yR[i].data)) * pow; + pow <<= bit_size_chunk; + } + //#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "Expected xR - yR: " << std::dec << expected_xR.data << " - " << expected_yR.data << std::endl; + std::cout << "Real res xR - yR: " << std::dec << xR << " - " << yR << std::endl; + //#endif + assert(xR == expected_xR.data); + assert(yR == expected_yR.data); + }; + + if constexpr (std::is_same_v) { + typename bbf::components::pallas_ec_full_add< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + + auto B = + bbf::circuit_builder(num_chunks, bit_size_chunk); + + assign_and_check(B, raw_input); + } + else if constexpr (std::is_same_v< + NonNativeFieldType, + crypto3::algebra::curves::vesta::base_field_type>) { + typename bbf::components::vesta_ec_full_add< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + auto B = + bbf::circuit_builder(num_chunks, bit_size_chunk); + + assign_and_check(B, raw_input); + } +} + +template +void ec_full_add_tests() { + using NonNativeFieldType = typename Curve::base_field_type; + using value_type = typename BlueprintFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using foreign_value_type = typename NonNativeFieldType::value_type; + using ec_point_value_type = typename Curve::template g1_type::value_type; + + typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> + extended_integral_type; + + static boost::random::mt19937 seed_seq; + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); + boost::random::uniform_int_distribution<> t_dist(0, 1); + + + extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; + + for (std::size_t i = 0; i < RandomTestsAmount; i++) { + std::vector public_input; + + extended_integral_type extended_base = 1, + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus, + pp = ext_pow - p; + + value_type d = generate_random(); + ec_point_value_type P = ec_point_value_type::one(), Q = ec_point_value_type::one(); + P = P * d; + Q = Q * d; + + public_input.resize(6 * num_chunks + 1); + integral_type xP = integral_type(P.X.data); + integral_type yP = integral_type(P.Y.data); + integral_type xQ = integral_type(Q.X.data); + integral_type yQ = integral_type(Q.Y.data); + for (std::size_t j = 0; j < num_chunks; j++) { + public_input[j] = value_type(xP & mask); + xP >>= bit_size_chunk; + + public_input[1 * num_chunks + j] = value_type(yP & mask); + yP >>= bit_size_chunk; + + public_input[2 * num_chunks + j] = value_type(xQ & mask); + xQ >>= bit_size_chunk; + + public_input[3 * num_chunks + j] = value_type(yQ & mask); + yQ >>= bit_size_chunk; + + public_input[4 * num_chunks + j] = value_type(p & mask); + p >>= bit_size_chunk; + + public_input[5 * num_chunks + j] = value_type(pp & mask); + pp >>= bit_size_chunk; + } + public_input.push_back(value_type(0)); // the zero + + test_ec_full_add(public_input); + } +} + +constexpr static const std::size_t random_tests_amount = 10; + +BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) + +BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_ec_full_add_test) { + using pallas = typename crypto3::algebra::curves::pallas; + using vesta = typename crypto3::algebra::curves::vesta; + + ec_full_add_tests(); + + ec_full_add_tests(); + + ec_full_add_tests(); + + ec_full_add_tests(); + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp new file mode 100644 index 000000000..11e3742e1 --- /dev/null +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp @@ -0,0 +1,215 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Antoine Cyr +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE bbf_ec_incomplete_add_test + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace nil; +using namespace nil::blueprint; + +template +void test_ec_incomplete_add( + const std::vector& public_input) { + using FieldType = BlueprintFieldType; + using TYPE = typename FieldType::value_type; + using NON_NATIVE_TYPE = typename NonNativeFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using non_native_integral_type = typename BlueprintFieldType::integral_type; + + non_native_integral_type pow = 1; + + NON_NATIVE_TYPE xP = 0, yP = 0, xQ = 0, yQ = 0; + + for (std::size_t i = 0; i < num_chunks; ++i) { + xP += non_native_integral_type(integral_type(public_input[i].data)) * pow; + yP += non_native_integral_type(integral_type(public_input[i + num_chunks].data)) * + pow; + xQ += non_native_integral_type( + integral_type(public_input[i + 2 * num_chunks].data)) * + pow; + yQ += non_native_integral_type( + integral_type(public_input[i + 3 * num_chunks].data)) * + pow; + pow <<= bit_size_chunk; + } + + NON_NATIVE_TYPE lambda = (xQ == xP) ? 0 : (yQ - yP) * ((xQ - xP).inversed()), + expected_xR = lambda * lambda - xP - xQ, + expected_yR = lambda * (xP - expected_xR) - yP; + + auto assign_and_check = [&](auto& B, auto& raw_input) { + raw_input.xP = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.yP = std::vector(public_input.begin() + num_chunks, + public_input.begin() + 2 * num_chunks); + raw_input.xQ = std::vector(public_input.begin() + 2 * num_chunks, + public_input.begin() + 3 * num_chunks); + raw_input.yQ = std::vector(public_input.begin() + 3 * num_chunks, + public_input.begin() + 4 * num_chunks); + raw_input.p = std::vector(public_input.begin() + 4 * num_chunks, + public_input.begin() + 5 * num_chunks); + raw_input.pp = std::vector(public_input.begin() + 5 * num_chunks, + public_input.begin() + 6 * num_chunks); + raw_input.zero = public_input[6 * num_chunks]; + + auto [at, A, desc] = B.assign(raw_input); + bool pass = B.is_satisfied(at); + std::cout << "Is_satisfied = " << pass << std::endl; + + assert(pass == true); + non_native_integral_type xR = 0; + non_native_integral_type yR = 0; + pow = 1; + for (std::size_t i = 0; i < num_chunks; i++) { + xR += non_native_integral_type(integral_type(A.res_xR[i].data)) * pow; + yR += non_native_integral_type(integral_type(A.res_yR[i].data)) * pow; + pow <<= bit_size_chunk; + } + // #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "Expected xR - yR: " << std::dec << expected_xR.data << " - " + << expected_yR.data << std::endl; + std::cout << "Real res xR - yR: " << std::dec << xR << " - " << yR << std::endl; + // #endif + assert(xR == expected_xR.data); + assert(yR == expected_yR.data); + }; + + if constexpr (std::is_same_v) { + typename bbf::components::pallas_ec_incomplete_add< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + + auto B = + bbf::circuit_builder(num_chunks, bit_size_chunk); + + assign_and_check(B, raw_input); + } else if constexpr (std::is_same_v< + NonNativeFieldType, + crypto3::algebra::curves::vesta::base_field_type>) { + typename bbf::components::vesta_ec_incomplete_add< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + auto B = + bbf::circuit_builder(num_chunks, bit_size_chunk); + + assign_and_check(B, raw_input); + } +} + +template +void ec_incomplete_add_tests() { + using NonNativeFieldType = typename Curve::base_field_type; + using value_type = typename BlueprintFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using foreign_value_type = typename NonNativeFieldType::value_type; + using ec_point_value_type = typename Curve::template g1_type< + nil::crypto3::algebra::curves::coordinates::affine>::value_type; + + typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> + extended_integral_type; + + static boost::random::mt19937 seed_seq; + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); + boost::random::uniform_int_distribution<> t_dist(0, 1); + + extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; + + for (std::size_t i = 0; i < RandomTestsAmount; i++) { + std::vector public_input; + + extended_integral_type extended_base = 1, + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus, pp = ext_pow - p; + + value_type d = generate_random(); + ec_point_value_type P = ec_point_value_type::one(), + Q = ec_point_value_type::one(); + P = P * d; + Q = Q * d; + + public_input.resize(6 * num_chunks + 1); + integral_type xP = integral_type(P.X.data); + integral_type yP = integral_type(P.Y.data); + integral_type xQ = integral_type(Q.X.data); + integral_type yQ = integral_type(Q.Y.data); + for (std::size_t j = 0; j < num_chunks; j++) { + public_input[j] = value_type(xP & mask); + xP >>= bit_size_chunk; + + public_input[1 * num_chunks + j] = value_type(yP & mask); + yP >>= bit_size_chunk; + + public_input[2 * num_chunks + j] = value_type(xQ & mask); + xQ >>= bit_size_chunk; + + public_input[3 * num_chunks + j] = value_type(yQ & mask); + yQ >>= bit_size_chunk; + + public_input[4 * num_chunks + j] = value_type(p & mask); + p >>= bit_size_chunk; + + public_input[5 * num_chunks + j] = value_type(pp & mask); + pp >>= bit_size_chunk; + } + public_input.push_back(value_type(0)); // the zero + + test_ec_incomplete_add(public_input); + } +} + +constexpr static const std::size_t random_tests_amount = 10; + +BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) + +BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_ec_incomplete_add_test) { + using pallas = typename crypto3::algebra::curves::pallas; + using vesta = typename crypto3::algebra::curves::vesta; + + ec_incomplete_add_tests(); + + ec_incomplete_add_tests(); + + ec_incomplete_add_tests(); + + ec_incomplete_add_tests(); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp index 4343786c2..2963351b5 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp @@ -1,6 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Valeh Farzaliyev -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -23,7 +23,7 @@ // SOFTWARE. //---------------------------------------------------------------------------// -#define BOOST_TEST_MODULE bbf_check_mod_p_test +#define BOOST_TEST_MODULE bbf_addition_mod_p_test #include #include @@ -63,9 +63,9 @@ void test_addition_mod_p(const std::vector= p) { - z -= p; + extended_integral_type r = x + y; + if (r >= p) { + r -= p; } auto assign_and_check = [&](auto &B, auto &raw_input) { @@ -84,18 +84,18 @@ void test_addition_mod_p(const std::vector &publi extended_integral_type R = 0; pow = 1; for (std::size_t i = 0; i < num_chunks; i++) { - R += extended_integral_type(integral_type(A.res_z[i].data)) * pow; + R += extended_integral_type(integral_type(A.res_r[i].data)) * pow; pow <<= bit_size_chunk; } #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp index 8a114cfac..8d367c582 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp @@ -1,6 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Valeh Farzaliyev -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -23,7 +23,7 @@ // SOFTWARE. //---------------------------------------------------------------------------// -#define BOOST_TEST_MODULE bbf_check_mod_p_test +#define BOOST_TEST_MODULE bbf_negation_mod_p_test #include #include @@ -59,7 +59,7 @@ void test_negation_mod_p( pow <<= bit_size_chunk; } - extended_integral_type y = (x == 0) ? 0 : p - x; // if x = 0, then y = 0 + extended_integral_type r = (x == 0) ? 0 : p - x; // if x = 0, then r = 0 auto assign_and_check = [&](auto &B, auto &raw_input) { raw_input.x = @@ -75,18 +75,18 @@ void test_negation_mod_p( std::cout << "Is_satisfied = " << pass << std::endl; assert(pass == true); - extended_integral_type Y = 0; + extended_integral_type R = 0; pow = 1; for (std::size_t i = 0; i < num_chunks; i++) { - Y += extended_integral_type(integral_type(A.res_z[i].data)) * pow; + R += extended_integral_type(integral_type(A.res_r[i].data)) * pow; pow <<= bit_size_chunk; } #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED std::cout << "negation_mod_p test" << std::endl; - std::cout << "Expected res: " << std::dec << z << std::endl; - std::cout << "Real res: " << std::dec << Z << std::endl; + std::cout << "Expected res: " << std::dec << r << std::endl; + std::cout << "Real res: " << std::dec << R << std::endl; #endif - assert(y == Y); + assert(r == R); }; if constexpr (std::is_same_v -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -72,9 +72,9 @@ void test_carry_on_addition(const std::vector -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -74,9 +74,9 @@ void test_choice_function( for (std::size_t i = 0; i < num_chunks; i++) { #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED std::cout << "Expected res: " << std::dec << expected_res[i] << std::endl; - std::cout << "Real res: " << std::dec << A.res_z[i].data << std::endl; + std::cout << "Real res: " << std::dec << A.res_r[i].data << std::endl; #endif - assert(A.res_z[i].data == expected_res[i].data); + assert(A.res_r[i].data == expected_res[i].data); } } From e1b5d64943fecbfe1321606cd2091b7b6eaa304c Mon Sep 17 00:00:00 2001 From: Antoine Cyr Date: Fri, 24 Jan 2025 20:34:11 -0500 Subject: [PATCH 12/14] ec arithmetic cleanup --- .../curves/weierstrass/ec_full_add.hpp | 28 ++++++++---------- .../fields/non_native/addition_mod_p.hpp | 29 ++----------------- .../fields/non_native/negation_mod_p.hpp | 29 ++----------------- .../include/nil/blueprint/bbf/tester.hpp | 10 +++---- 4 files changed, 21 insertions(+), 75 deletions(-) diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp index 170907547..443ad7ff7 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp @@ -191,7 +191,7 @@ namespace nil { std::vector YQ(num_chunks); std::vector P(num_chunks); std::vector PP(num_chunks); - TYPE ZERO; + std::vector ZERO(num_chunks); std::vector LAMBDA(num_chunks); std::vector XR(num_chunks); @@ -200,7 +200,7 @@ namespace nil { std::vector ZQ(num_chunks); std::vector ZPQ(num_chunks); std::vector WPQ(num_chunks); - std::vector ZEROv(num_chunks); + if constexpr (stage == GenerationStage::ASSIGNMENT) { for (std::size_t i = 0; i < num_chunks; ++i) { @@ -210,8 +210,8 @@ namespace nil { YQ[i] = input_yQ[i]; P[i] = input_p[i]; PP[i] = input_pp[i]; + ZERO[i] = input_zero; } - ZERO = input_zero; non_native_integral_type pow = 1; NON_NATIVE_TYPE xP = 0, yP = 0, xQ = 0, yQ = 0; @@ -300,6 +300,7 @@ namespace nil { allocate(YQ[i]); allocate(P[i]); allocate(PP[i]); + allocate(ZERO[i]); allocate(LAMBDA[i]); allocate(XR[i]); @@ -308,17 +309,13 @@ namespace nil { allocate(ZQ[i]); allocate(ZPQ[i]); allocate(WPQ[i]); - - ZEROv[i] = ZERO; - allocate(ZEROv[i]); } - allocate(ZERO); auto check_chunked = [&context_object, num_chunks, bit_size_chunk, PP, ZERO](std::vector x) { Range_Check rc = Range_Check(context_object, x, num_chunks, bit_size_chunk); - Check_Mod_P cm = Check_Mod_P(context_object, x, PP, ZERO, + Check_Mod_P cm = Check_Mod_P(context_object, x, PP, ZERO[0], num_chunks, bit_size_chunk); }; @@ -332,7 +329,6 @@ namespace nil { // perform range checks and mod p checks on all stored variables check_chunked(LAMBDA); - check_chunked(Z); check_chunked(XR); check_chunked(YR); check_chunked(ZP); @@ -344,7 +340,7 @@ namespace nil { bit_size_chunk](std::vector x, std::vector y) { Multiplication_Mod_P t = - Multiplication_Mod_P(context_object, x, y, P, PP, ZERO, + Multiplication_Mod_P(context_object, x, y, P, PP, ZERO[0], num_chunks, bit_size_chunk); return t.res_r; }; @@ -352,14 +348,14 @@ namespace nil { bit_size_chunk](std::vector x, std::vector y) { Addition_Mod_P t = - Addition_Mod_P(context_object, x, y, P, PP, ZERO, + Addition_Mod_P(context_object, x, y, P, PP, ZERO[0], num_chunks, bit_size_chunk); return t.res_r; }; auto NegModP = [&context_object, P, PP, ZERO, num_chunks, bit_size_chunk](std::vector x) { Negation_Mod_P t = - Negation_Mod_P(context_object, x, P, PP, ZERO, num_chunks, + Negation_Mod_P(context_object, x, P, PP, ZERO[0], num_chunks, bit_size_chunk); return t.res_r; }; @@ -413,16 +409,16 @@ namespace nil { auto t35 = MultModP(t7, LAMBDA); // t35 = (xR - xP) lambda auto t36 = AddModP(t34, t35); // t36 = yR + yP + (xR - xP)lambda auto t37 = MultModP(t28, t33); // t37 = yP yQ (xP - xQ + (yP + yQ)(1 - ZPQ))(xR - lambda^2 + xP + xQ) - CopyConstrain(t37, ZEROv); // t37 = 0 + CopyConstrain(t37, ZERO); // t37 = 0 auto t38 = MultModP(t28, t36); // t38 = yP yQ (xP - xQ + (yP + yQ)(1 -ZPQ))(yR + yP + (xR - xP)lambda) - CopyConstrain(t38, ZEROv); // t38 = 0 + CopyConstrain(t38, ZERO); // t38 = 0 // part 4 auto t39 = MultModP(t9, LAMBDA); // t39 = (xP - xQ) lambda auto t40 = AddModP(t39, t4); // t40 = (xP - xQ) lambda - yP auto t41 = AddModP(t40, YQ); // t41 = (xP - xQ) lambda - yP + yQ auto t42 = MultModP(t9, t41); // t42 = (xP - xQ)((xP - xQ) lambda - yP + yQ) - CopyConstrain(t42, ZEROv); // t42 = 0 + CopyConstrain(t42, ZERO); // t42 = 0 auto t43 = MultModP(XP, t3); // t43 = -xP^2 auto t44 = AddModP(t43, t43); // t44 = -2xP^2 auto t45 = AddModP(t43, t44); // t45 = -3xP^2 @@ -440,8 +436,8 @@ namespace nil { copy_constrain(YQ[i], input_yQ[i]); copy_constrain(P[i], input_p[i]); copy_constrain(PP[i], input_pp[i]); + copy_constrain(ZERO[i], input_zero); } - copy_constrain(ZERO, input_zero); } for (int i = 0; i < num_chunks; ++i) { diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp index 8fea6ac38..365c135ae 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp @@ -42,7 +42,6 @@ #include #include #include -#include namespace nil { namespace blueprint { @@ -83,28 +82,7 @@ namespace nil { typename std::conditional, std::tuple<>>::type; - using NonNativeIntegralExtendedVariant = - std::variant, - nil::crypto3::multiprecision::big_uint< - 2 * crypto3::algebra::curves::vesta:: - base_field_type::modulus_bits>>; - - template - struct NonNativeFieldTypeIndex; - - template<> - struct NonNativeFieldTypeIndex< - crypto3::algebra::curves::pallas::base_field_type> { - static constexpr std::size_t value = 0; - }; - - template<> - struct NonNativeFieldTypeIndex< - crypto3::algebra::curves::vesta::base_field_type> { - static constexpr std::size_t value = 1; - }; + public: std::vector inp_x; @@ -165,10 +143,7 @@ namespace nil { std::size_t bit_size_chunk, bool make_links = true) : generic_component(context_object) { using integral_type = typename FieldType::integral_type; - using extended_integral_type = - typename std::variant_alternative_t< - NonNativeFieldTypeIndex::value, - NonNativeIntegralExtendedVariant>; + using extended_integral_type = nil::crypto3::multiprecision::big_uint<2* NonNativeFieldType::modulus_bits>; using Carry_On_Addition = typename bbf::components::carry_on_addition; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp index da476ba85..017e86cc6 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp @@ -43,7 +43,6 @@ #include #include #include -#include namespace nil { namespace blueprint { @@ -80,28 +79,7 @@ namespace nil { typename std::conditional, std::tuple<>>::type; - using NonNativeIntegralExtendedVariant = - std::variant, - nil::crypto3::multiprecision::big_uint< - 2 * crypto3::algebra::curves::vesta:: - base_field_type::modulus_bits>>; - - template - struct NonNativeFieldTypeIndex; - - template<> - struct NonNativeFieldTypeIndex< - crypto3::algebra::curves::pallas::base_field_type> { - static constexpr std::size_t value = 0; - }; - - template<> - struct NonNativeFieldTypeIndex< - crypto3::algebra::curves::vesta::base_field_type> { - static constexpr std::size_t value = 1; - }; + public: std::vector inp_x; @@ -157,10 +135,7 @@ namespace nil { bool make_links = true) : generic_component(context_object) { using integral_type = typename FieldType::integral_type; - using extended_integral_type = - typename std::variant_alternative_t< - NonNativeFieldTypeIndex::value, - NonNativeIntegralExtendedVariant>; + using extended_integral_type = nil::crypto3::multiprecision::big_uint<2* NonNativeFieldType::modulus_bits>; using Carry_On_Addition = typename bbf::components::carry_on_addition; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/tester.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/tester.hpp index e9a7aa7c7..55e9117f5 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/tester.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/tester.hpp @@ -38,7 +38,7 @@ #include #include -#include +// #include // #include #include @@ -104,7 +104,7 @@ namespace nil { generic_component(context_object) { using Is_Zero = is_zero; - using Choice_Function = choice_function; + // using Choice_Function = choice_function; // using Carry_On_Addition = carry_on_addition; using Useless = useless; @@ -113,9 +113,9 @@ namespace nil { Is_Zero(context_object, X, make_links); // make_links delegated to subcomponent - std::vector ct2_area = {2,3,4,5}; - context_type ct2 = context_object.subcontext(ct2_area,0,4); - auto c2 = Choice_Function(ct2,Q,CX,CY, make_links); // make_links delegated to subcomponent + // std::vector ct2_area = {2,3,4,5}; + // context_type ct2 = context_object.subcontext(ct2_area,0,4); + // auto c2 = Choice_Function(ct2,Q,CX,CY, make_links); // make_links delegated to subcomponent // std::vector ct3_area = {7,8,9,10,11}; // context_type ct3 = context_object.subcontext(ct3_area,0,4); From 63ea2545b466b468aef1246a867a4b5a42eba973 Mon Sep 17 00:00:00 2001 From: Antoine Cyr Date: Wed, 29 Jan 2025 10:27:49 -0500 Subject: [PATCH 13/14] normalizing the ec arithemtic circuits --- .../algebra/curves/weierstrass/ec_double.hpp | 102 ++----- .../curves/weierstrass/ec_full_add.hpp | 233 ++++++--------- .../curves/weierstrass/ec_incomplete_add.hpp | 123 +++----- .../fields/non_native/addition_mod_p.hpp | 129 ++++---- .../algebra/fields/non_native/check_mod_p.hpp | 16 +- .../non_native/flexible_multiplication.hpp | 275 ++++++++++-------- .../fields/non_native/negation_mod_p.hpp | 104 +++---- .../components/detail/carry_on_addition.hpp | 69 +++-- .../bbf/components/detail/choice_function.hpp | 14 +- .../components/detail/range_check_multi.hpp | 58 ++-- .../algebra/curves/weierstrass/ec_double.cpp | 82 +++--- .../curves/weierstrass/ec_full_add.cpp | 119 ++++---- .../curves/weierstrass/ec_incomplete_add.cpp | 5 +- .../fields/non_native/addition_mod_p.cpp | 86 +++--- .../algebra/fields/non_native/check_mod_p.cpp | 89 +++--- .../non_native/flexible_multiplication.cpp | 76 ++--- .../fields/non_native/negation_mod_p.cpp | 15 +- .../test/bbf/detail/carry_on_addition.cpp | 65 +++-- .../test/bbf/detail/choice_function.cpp | 9 +- .../test/bbf/detail/range_check_multi.cpp | 58 ++-- 20 files changed, 769 insertions(+), 958 deletions(-) diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp index e70280e68..a292dd15e 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp @@ -89,12 +89,8 @@ namespace nil { std::tuple<>>::type; public: - std::vector inp_xQ; - std::vector inp_yQ; - std::vector inp_p; - std::vector inp_pp; - std::vector res_xR; - std::vector res_yR; + std::vector xR; + std::vector yR; static table_params get_minimal_requirements( std::size_t num_chunks, std::size_t bit_size_chunk) { @@ -169,26 +165,12 @@ namespace nil { typename bbf::components::flexible_multiplication< FieldType, stage, NonNativeFieldType>; - std::vector XQ(num_chunks); - std::vector YQ(num_chunks); - std::vector P(num_chunks); - std::vector PP(num_chunks); - TYPE ZERO; - std::vector LAMBDA(num_chunks); std::vector Z(num_chunks); std::vector XR(num_chunks); std::vector YR(num_chunks); if constexpr (stage == GenerationStage::ASSIGNMENT) { - for (std::size_t i = 0; i < num_chunks; ++i) { - XQ[i] = input_xQ[i]; - YQ[i] = input_yQ[i]; - P[i] = input_p[i]; - PP[i] = input_pp[i]; - } - ZERO = input_zero; - non_native_integral_type pow = 1; NON_NATIVE_TYPE xQ = 0, yQ = 0; @@ -232,23 +214,17 @@ namespace nil { } for (std::size_t i = 0; i < num_chunks; ++i) { - allocate(XQ[i]); - allocate(YQ[i]); - allocate(P[i]); - allocate(PP[i]); - allocate(LAMBDA[i]); allocate(Z[i]); allocate(XR[i]); allocate(YR[i]); } - allocate(ZERO); auto check_chunked = [&context_object, num_chunks, bit_size_chunk, - PP, ZERO](std::vector x) { + input_pp, input_zero](std::vector x) { Range_Check rc = Range_Check(context_object, x, num_chunks, bit_size_chunk); - Check_Mod_P cm = Check_Mod_P(context_object, x, PP, ZERO, + Check_Mod_P cm = Check_Mod_P(context_object, x, input_pp, input_zero, num_chunks, bit_size_chunk); }; @@ -266,66 +242,50 @@ namespace nil { check_chunked(XR); check_chunked(YR); - auto MultModP = [&context_object, P, PP, ZERO, num_chunks, + auto MultModP = [&context_object, input_p, input_pp, input_zero, num_chunks, bit_size_chunk](std::vector x, std::vector y) { Multiplication_Mod_P t = - Multiplication_Mod_P(context_object, x, y, P, PP, ZERO, + Multiplication_Mod_P(context_object, x, y, input_p, input_pp, input_zero, num_chunks, bit_size_chunk); - return t.res_r; + return t.r; }; - auto AddModP = [&context_object, P, PP, ZERO, num_chunks, + auto AddModP = [&context_object, input_p, input_pp, input_zero, num_chunks, bit_size_chunk](std::vector x, std::vector y) { Addition_Mod_P t = - Addition_Mod_P(context_object, x, y, P, PP, ZERO, + Addition_Mod_P(context_object, x, y, input_p, input_pp, input_zero, num_chunks, bit_size_chunk); - return t.res_r; + return t.r; }; - auto NegModP = [&context_object, P, PP, ZERO, num_chunks, + auto NegModP = [&context_object, input_p, input_pp, input_zero, num_chunks, bit_size_chunk](std::vector x) { Negation_Mod_P t = - Negation_Mod_P(context_object, x, P, PP, ZERO, num_chunks, + Negation_Mod_P(context_object, x, input_p, input_pp, input_zero, num_chunks, bit_size_chunk); - return t.res_r; + return t.r; }; - auto t1 = MultModP(YQ,LAMBDA); // t1 = yQ * lambda - auto t2 = AddModP(t1,t1); // t2 = t1 + t1 = 2yQ * lambda - auto t3 = AddModP(XQ,XQ); // t3 = xQ + xQ = 2xQ - auto t4 = AddModP(XQ,t3); // t4 = xQ + t3 = 3xQ - auto t5 = MultModP(t4,XQ); // t5 = t4 * xQ = 3xQ^2 - CopyConstrain(t2, t5); // 2yQ lambda = 3xQ^2 - auto t6 = AddModP(XR,t3); // t6 = xR + t3 = xR + 2xQ - auto t7 = MultModP(LAMBDA,LAMBDA); // t7 = lambda * lambda - CopyConstrain(t6, t7); // xR + 2xQ = lambda^2 - auto t8 = AddModP(YR,YQ); // t8 = yR + yQ - auto t9 = NegModP(XR); // t9 = -xR - auto t10 = AddModP(XQ,t9); // t10 = xQ + t9 = xQ - xR - auto t11 = MultModP(LAMBDA,t10); // t11 = lambda * t10 =lambda(xQ-xR) - CopyConstrain(t8, t11); // yR + yQ = lambda(xQ - xR) - auto t12 = MultModP(Z,t1); // t12 = z * t1 = z * yQ * lambda - CopyConstrain(LAMBDA, t12); // lambda = z yQ lambda - - if (make_links) { - for (std::size_t i = 0; i < num_chunks; ++i) { - copy_constrain(XQ[i], input_xQ[i]); - copy_constrain(YQ[i], input_yQ[i]); - copy_constrain(P[i], input_p[i]); - copy_constrain(PP[i], input_pp[i]); - } - copy_constrain(ZERO, input_zero); - } + auto t1 = MultModP(input_yQ,LAMBDA); // t1 = yQ * lambda + auto t2 = AddModP(t1,t1); // t2 = t1 + t1 = 2yQ * lambda + auto t3 = AddModP(input_xQ,input_xQ); // t3 = xQ + xQ = 2xQ + auto t4 = AddModP(input_xQ,t3); // t4 = xQ + t3 = 3xQ + auto t5 = MultModP(t4,input_xQ); // t5 = t4 * xQ = 3xQ^2 + CopyConstrain(t2, t5); // 2yQ lambda = 3xQ^2 + auto t6 = AddModP(XR,t3); // t6 = xR + t3 = xR + 2xQ + auto t7 = MultModP(LAMBDA,LAMBDA); // t7 = lambda * lambda + CopyConstrain(t6, t7); // xR + 2xQ = lambda^2 + auto t8 = AddModP(YR,input_yQ); // t8 = yR + yQ + auto t9 = NegModP(XR); // t9 = -xR + auto t10 = AddModP(input_xQ,t9); // t10 = xQ + t9 = xQ - xR + auto t11 = MultModP(LAMBDA,t10); // t11 = lambda * t10 =lambda(xQ-xR) + CopyConstrain(t8, t11); // yR + yQ = lambda(xQ - xR) + auto t12 = MultModP(Z,t1); // t12 = z * t1 = z * yQ * lambda + CopyConstrain(LAMBDA, t12); // lambda = z yQ lambda for (int i = 0; i < num_chunks; ++i) { - inp_xQ.push_back(input_xQ[i]); - inp_yQ.push_back(input_yQ[i]); - inp_pp.push_back(input_p[i]); - inp_pp.push_back(input_pp[i]); - } - for (int i = 0; i < num_chunks; ++i) { - res_xR.push_back(XR[i]); - res_yR.push_back(YR[i]); + xR.push_back(XR[i]); + yR.push_back(YR[i]); } } }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp index 443ad7ff7..b322a8527 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp @@ -58,7 +58,7 @@ namespace nil { // p' = 2^(kb) - p // Input: xP[0],...,xP[k-1],yP[0],...,yP[k-1],xQ[0],...,xQ[k-1], // yQ[0],...,yQ[k-1], p[0], ..., p[k-1], pp[0], ..., pp[k-1], 0 - // (expects zero constant as input) + // (expects zero constant as input) // Output: xR[0],...,xR[k-1], // yR[0],...,yR[k-1] // @@ -93,14 +93,8 @@ namespace nil { std::tuple<>>::type; public: - std::vector inp_xP; - std::vector inp_yP; - std::vector inp_xQ; - std::vector inp_yQ; - std::vector inp_p; - std::vector inp_pp; - std::vector res_xR; - std::vector res_yR; + std::vector xR; + std::vector yR; static table_params get_minimal_requirements( std::size_t num_chunks, std::size_t bit_size_chunk) { @@ -185,14 +179,6 @@ namespace nil { typename bbf::components::flexible_multiplication< FieldType, stage, NonNativeFieldType>; - std::vector XP(num_chunks); - std::vector YP(num_chunks); - std::vector XQ(num_chunks); - std::vector YQ(num_chunks); - std::vector P(num_chunks); - std::vector PP(num_chunks); - std::vector ZERO(num_chunks); - std::vector LAMBDA(num_chunks); std::vector XR(num_chunks); std::vector YR(num_chunks); @@ -200,19 +186,8 @@ namespace nil { std::vector ZQ(num_chunks); std::vector ZPQ(num_chunks); std::vector WPQ(num_chunks); - if constexpr (stage == GenerationStage::ASSIGNMENT) { - for (std::size_t i = 0; i < num_chunks; ++i) { - XP[i] = input_xP[i]; - YP[i] = input_yP[i]; - XQ[i] = input_xQ[i]; - YQ[i] = input_yQ[i]; - P[i] = input_p[i]; - PP[i] = input_pp[i]; - ZERO[i] = input_zero; - } - non_native_integral_type pow = 1; NON_NATIVE_TYPE xP = 0, yP = 0, xQ = 0, yQ = 0; @@ -294,14 +269,6 @@ namespace nil { } for (std::size_t i = 0; i < num_chunks; ++i) { - allocate(XP[i]); - allocate(YP[i]); - allocate(XQ[i]); - allocate(YQ[i]); - allocate(P[i]); - allocate(PP[i]); - allocate(ZERO[i]); - allocate(LAMBDA[i]); allocate(XR[i]); allocate(YR[i]); @@ -312,11 +279,12 @@ namespace nil { } auto check_chunked = [&context_object, num_chunks, bit_size_chunk, - PP, ZERO](std::vector x) { + input_pp, input_zero](std::vector x) { Range_Check rc = Range_Check(context_object, x, num_chunks, bit_size_chunk); - Check_Mod_P cm = Check_Mod_P(context_object, x, PP, ZERO[0], - num_chunks, bit_size_chunk); + Check_Mod_P cm = + Check_Mod_P(context_object, x, input_pp, input_zero, + num_chunks, bit_size_chunk); }; // Copy constraint generation lambda expression @@ -327,6 +295,13 @@ namespace nil { } }; + auto CopyConstrainZero = + [this, num_chunks, input_zero](std::vector x) mutable { + for (std::size_t i = 0; i < num_chunks; i++) { + copy_constrain(x[i], input_zero); + } + }; + // perform range checks and mod p checks on all stored variables check_chunked(LAMBDA); check_chunked(XR); @@ -336,121 +311,101 @@ namespace nil { check_chunked(ZPQ); check_chunked(WPQ); - auto MultModP = [&context_object, P, PP, ZERO, num_chunks, - bit_size_chunk](std::vector x, - std::vector y) { - Multiplication_Mod_P t = - Multiplication_Mod_P(context_object, x, y, P, PP, ZERO[0], - num_chunks, bit_size_chunk); - return t.res_r; + auto MultModP = [&context_object, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk]( + std::vector x, std::vector y) { + Multiplication_Mod_P t = Multiplication_Mod_P( + context_object, x, y, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk); + return t.r; }; - auto AddModP = [&context_object, P, PP, ZERO, num_chunks, - bit_size_chunk](std::vector x, - std::vector y) { + auto AddModP = [&context_object, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk](std::vector x, + std::vector y) { Addition_Mod_P t = - Addition_Mod_P(context_object, x, y, P, PP, ZERO[0], - num_chunks, bit_size_chunk); - return t.res_r; + Addition_Mod_P(context_object, x, y, input_p, input_pp, + input_zero, num_chunks, bit_size_chunk); + return t.r; }; - auto NegModP = [&context_object, P, PP, ZERO, num_chunks, - bit_size_chunk](std::vector x) { + auto NegModP = [&context_object, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk](std::vector x) { Negation_Mod_P t = - Negation_Mod_P(context_object, x, P, PP, ZERO[0], num_chunks, - bit_size_chunk); - return t.res_r; + Negation_Mod_P(context_object, x, input_p, input_pp, + input_zero, num_chunks, bit_size_chunk); + return t.r; }; // part 1 - auto t1 = NegModP(XQ); // t1 = -xQ - auto t2 = NegModP(YQ); // t2 = -yQ - auto t3 = NegModP(XP); // t3 = -xP - auto t4 = NegModP(YP); // t4 = -yP - auto t5 = AddModP(XR, t1); // t5 = xR - xQ - auto t6 = AddModP(YR, t2); // t6 = yR - yQ - auto t7 = AddModP(XR, t3); // t5 = xR - xP - auto t8 = AddModP(YR, t4); // t6 = yR - yP - auto t9 = AddModP(XP, t1); // t9 = xP - xQ - auto t10 = MultModP(YP, ZP); // t10 = yP * zP - auto t11 = MultModP(YQ, ZQ); // t11 = yQ * zQ - auto t12 = MultModP(t9, ZPQ); // t12 = (xP - xQ) zPQ = ZPQ - auto t13 = MultModP(t5, t10); // t13 = (xR - xQ) yP zP - CopyConstrain(t5, t13); // t5 = t13 - auto t14 = MultModP(t6, t10); // t14 = (yR - yQ) yP zP - CopyConstrain(t6, t14); // t6 = t14 - auto t15 = MultModP(t7, t11); // t15 = (xR - xP) yQ zQ - CopyConstrain(t7, t15); // t7 = t15 - auto t16 = MultModP(t8, t11); // t16 = (yR - yP) yQ zQ - CopyConstrain(t8, t16); // t8 = t16 - auto t17 = MultModP(t9, t12); // t17 = (xP - xQ) ZPQ - CopyConstrain(t9, t17); // t9 = t17 + auto t1 = NegModP(input_xQ); // t1 = -xQ + auto t2 = NegModP(input_yQ); // t2 = -yQ + auto t3 = NegModP(input_xP); // t3 = -xP + auto t4 = NegModP(input_yP); // t4 = -yP + auto t5 = AddModP(XR, t1); // t5 = xR - xQ + auto t6 = AddModP(YR, t2); // t6 = yR - yQ + auto t7 = AddModP(XR, t3); // t5 = xR - xP + auto t8 = AddModP(YR, t4); // t6 = yR - yP + auto t9 = AddModP(input_xP, t1); // t9 = xP - xQ + auto t10 = MultModP(input_yP, ZP); // t10 = yP * zP + auto t11 = MultModP(input_yQ, ZQ); // t11 = yQ * zQ + auto t12 = MultModP(t9, ZPQ); // t12 = (xP - xQ) zPQ = ZPQ + auto t13 = MultModP(t5, t10); // t13 = (xR - xQ) yP zP + CopyConstrain(t5, t13); // t5 = t13 + auto t14 = MultModP(t6, t10); // t14 = (yR - yQ) yP zP + CopyConstrain(t6, t14); // t6 = t14 + auto t15 = MultModP(t7, t11); // t15 = (xR - xP) yQ zQ + CopyConstrain(t7, t15); // t7 = t15 + auto t16 = MultModP(t8, t11); // t16 = (yR - yP) yQ zQ + CopyConstrain(t8, t16); // t8 = t16 + auto t17 = MultModP(t9, t12); // t17 = (xP - xQ) ZPQ + CopyConstrain(t9, t17); // t9 = t17 // part 2 - auto t18 = AddModP(YP, YQ); // t18 = yP + yQ - auto t19 = MultModP(t18, WPQ); // t19 = (yP + yQ) wPQ = WPQ - auto t20 = AddModP(t12, t19); // t20 = ZPQ + WPQ - auto t21 = MultModP(XR, t20); // t21 = xR(ZPQ + WPQ) - CopyConstrain(XR, t21); // xR = t21 - auto t22 = MultModP(YR, t20); // t22 = yR(ZPQ + WPQ) - CopyConstrain(YR, t22); // yR = t22 + auto t18 = AddModP(input_yP, input_yQ); // t18 = yP + yQ + auto t19 = MultModP(t18, WPQ); // t19 = (yP + yQ) wPQ = WPQ + auto t20 = AddModP(t12, t19); // t20 = ZPQ + WPQ + auto t21 = MultModP(XR, t20); // t21 = xR(ZPQ + WPQ) + CopyConstrain(XR, t21); // xR = t21 + auto t22 = MultModP(YR, t20); // t22 = yR(ZPQ + WPQ) + CopyConstrain(YR, t22); // yR = t22 // part 3 - auto t23 = NegModP(t12); // t23 = -ZPQ - auto t24 = MultModP(t18, t23); // t24 = -(yP + yQ) ZPQ - auto t25 = AddModP(t18, t24); // t25 = (yP + yQ)(1 - ZPQ) - auto t26 = AddModP(t9, t25); // t26 = (xP - xQ) + (yP + yQ)(1 - ZPQ) - auto t27 = MultModP(YP, YQ); // t27 = yP * yQ - auto t28 = MultModP(t26, t27); // t28 = yP yQ (xP - xQ + (yP + yQ)(1 - ZPQ)) - auto t29 = MultModP(LAMBDA, LAMBDA); // t29 = lambda * lambda - auto t30 = NegModP(t29); // t30 = -lambda^2 - auto t31 = AddModP(XR, t30); // t31 = xR - lambda^2 - auto t32 = AddModP(t31, XP); // t32 = xR - lambda^2 + xP - auto t33 = AddModP(t32, XQ); // t33 = xR - lambda^2 + xP + xQ - auto t34 = AddModP(YR, YP); // t34 = yR + yP - auto t35 = MultModP(t7, LAMBDA); // t35 = (xR - xP) lambda - auto t36 = AddModP(t34, t35); // t36 = yR + yP + (xR - xP)lambda - auto t37 = MultModP(t28, t33); // t37 = yP yQ (xP - xQ + (yP + yQ)(1 - ZPQ))(xR - lambda^2 + xP + xQ) - CopyConstrain(t37, ZERO); // t37 = 0 - auto t38 = MultModP(t28, t36); // t38 = yP yQ (xP - xQ + (yP + yQ)(1 -ZPQ))(yR + yP + (xR - xP)lambda) - CopyConstrain(t38, ZERO); // t38 = 0 + auto t23 = NegModP(t12); // t23 = -ZPQ + auto t24 = MultModP(t18, t23); // t24 = -(yP + yQ) ZPQ + auto t25 = AddModP(t18, t24); // t25 = (yP + yQ)(1 - ZPQ) + auto t26 = AddModP(t9, t25); // t26 = (xP - xQ) + (yP + yQ)(1 - ZPQ) + auto t27 = MultModP(input_yP, input_yQ); // t27 = yP * yQ + auto t28 = MultModP(t26, t27); // t28 = yP yQ (xP - xQ + (yP + yQ)(1 - ZPQ)) + auto t29 = MultModP(LAMBDA, LAMBDA); // t29 = lambda * lambda + auto t30 = NegModP(t29); // t30 = -lambda^2 + auto t31 = AddModP(XR, t30); // t31 = xR - lambda^2 + auto t32 = AddModP(t31, input_xP); // t32 = xR - lambda^2 + xP + auto t33 = AddModP(t32, input_xQ); // t33 = xR - lambda^2 + xP + xQ + auto t34 = AddModP(YR, input_yP); // t34 = yR + yP + auto t35 = MultModP(t7, LAMBDA); // t35 = (xR - xP) lambda + auto t36 = AddModP(t34, t35); // t36 = yR + yP + (xR - xP)lambda + auto t37 = MultModP(t28, t33); // t37 = yP yQ (xP - xQ + (yP + yQ)(1 - ZPQ))(xR - lambda^2 + xP + xQ) + CopyConstrainZero(t37); // t37 = 0 + auto t38 = MultModP(t28, t36); // t38 = yP yQ (xP - xQ + (yP + yQ)(1 -ZPQ))(yR + yP + (xR - xP)lambda) + CopyConstrainZero(t38); // t38 = 0 // part 4 - auto t39 = MultModP(t9, LAMBDA); // t39 = (xP - xQ) lambda - auto t40 = AddModP(t39, t4); // t40 = (xP - xQ) lambda - yP - auto t41 = AddModP(t40, YQ); // t41 = (xP - xQ) lambda - yP + yQ - auto t42 = MultModP(t9, t41); // t42 = (xP - xQ)((xP - xQ) lambda - yP + yQ) - CopyConstrain(t42, ZERO); // t42 = 0 - auto t43 = MultModP(XP, t3); // t43 = -xP^2 - auto t44 = AddModP(t43, t43); // t44 = -2xP^2 - auto t45 = AddModP(t43, t44); // t45 = -3xP^2 - auto t46 = AddModP(YP, YP); // t46 = 2yP - auto t47 = MultModP(t46, LAMBDA); // t47 = 2yP lambda - auto t48 = AddModP(t47, t45); // t48 = 2yP lambda - 3xP^2 - auto t49 = MultModP(t48, t12); // t49 = (2yP lambda - 3xP^2) ZPQ - CopyConstrain(t48, t49); // t38 = 0t48 = t49 - - if (make_links) { - for (std::size_t i = 0; i < num_chunks; ++i) { - copy_constrain(XP[i], input_xP[i]); - copy_constrain(YP[i], input_yP[i]); - copy_constrain(XQ[i], input_xQ[i]); - copy_constrain(YQ[i], input_yQ[i]); - copy_constrain(P[i], input_p[i]); - copy_constrain(PP[i], input_pp[i]); - copy_constrain(ZERO[i], input_zero); - } - } + auto t39 = MultModP(t9, LAMBDA); // t39 = (xP - xQ) lambda + auto t40 = AddModP(t39, t4); // t40 = (xP - xQ) lambda - yP + auto t41 = AddModP(t40, input_yQ); // t41 = (xP - xQ) lambda - yP + yQ + auto t42 = MultModP(t9, t41); // t42 = (xP - xQ)((xP - xQ) lambda - yP + yQ) + CopyConstrainZero(t42); // t42 = 0 + auto t43 = MultModP(input_xP, t3); // t43 = -xP^2 + auto t44 = AddModP(t43, t43); // t44 = -2xP^2 + auto t45 = AddModP(t43, t44); // t45 = -3xP^2 + auto t46 = AddModP(input_yP, input_yP); // t46 = 2yP + auto t47 = MultModP(t46, LAMBDA); // t47 = 2yP lambda + auto t48 = AddModP(t47, t45); // t48 = 2yP lambda - 3xP^2 + auto t49 = MultModP(t48, t12); // t49 = (2yP lambda - 3xP^2) ZPQ + CopyConstrain(t48, t49); // t48 = t49 for (int i = 0; i < num_chunks; ++i) { - inp_xP.push_back(input_xP[i]); - inp_yP.push_back(input_yP[i]); - inp_xQ.push_back(input_xQ[i]); - inp_yQ.push_back(input_yQ[i]); - inp_pp.push_back(input_p[i]); - inp_pp.push_back(input_pp[i]); - } - for (int i = 0; i < num_chunks; ++i) { - res_xR.push_back(XR[i]); - res_yR.push_back(YR[i]); + xR.push_back(XR[i]); + yR.push_back(YR[i]); } } }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp index a01b01b06..6f7023ad9 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp @@ -92,14 +92,8 @@ namespace nil { std::tuple<>>::type; public: - std::vector inp_xP; - std::vector inp_yP; - std::vector inp_xQ; - std::vector inp_yQ; - std::vector inp_p; - std::vector inp_pp; - std::vector res_xR; - std::vector res_yR; + std::vector xR; + std::vector yR; static table_params get_minimal_requirements( std::size_t num_chunks, std::size_t bit_size_chunk) { @@ -187,29 +181,11 @@ namespace nil { typename bbf::components::flexible_multiplication< FieldType, stage, NonNativeFieldType>; - std::vector XP(num_chunks); - std::vector YP(num_chunks); - std::vector XQ(num_chunks); - std::vector YQ(num_chunks); - std::vector P(num_chunks); - std::vector PP(num_chunks); - TYPE ZERO; - std::vector LAMBDA(num_chunks); std::vector XR(num_chunks); std::vector YR(num_chunks); if constexpr (stage == GenerationStage::ASSIGNMENT) { - for (std::size_t i = 0; i < num_chunks; ++i) { - XP[i] = input_xP[i]; - YP[i] = input_yP[i]; - XQ[i] = input_xQ[i]; - YQ[i] = input_yQ[i]; - P[i] = input_p[i]; - PP[i] = input_pp[i]; - } - ZERO = input_zero; - non_native_integral_type pow = 1; NON_NATIVE_TYPE xP = 0, yP = 0, xQ = 0, yQ = 0; @@ -255,25 +231,18 @@ namespace nil { } for (std::size_t i = 0; i < num_chunks; ++i) { - allocate(XP[i]); - allocate(YP[i]); - allocate(XQ[i]); - allocate(YQ[i]); - allocate(P[i]); - allocate(PP[i]); - allocate(LAMBDA[i]); allocate(XR[i]); allocate(YR[i]); } - allocate(ZERO); auto check_chunked = [&context_object, num_chunks, bit_size_chunk, - PP, ZERO](std::vector x) { + input_pp, input_zero](std::vector x) { Range_Check rc = Range_Check(context_object, x, num_chunks, bit_size_chunk); - Check_Mod_P cm = Check_Mod_P(context_object, x, PP, ZERO, - num_chunks, bit_size_chunk); + Check_Mod_P cm = + Check_Mod_P(context_object, x, input_pp, input_zero, + num_chunks, bit_size_chunk); }; // Copy constraint generation lambda expression @@ -289,68 +258,48 @@ namespace nil { check_chunked(XR); check_chunked(YR); - auto MultModP = [&context_object, P, PP, ZERO, num_chunks, - bit_size_chunk](std::vector x, - std::vector y) { - Multiplication_Mod_P t = - Multiplication_Mod_P(context_object, x, y, P, PP, ZERO, - num_chunks, bit_size_chunk); - return t.res_r; + auto MultModP = [&context_object, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk]( + std::vector x, std::vector y) { + Multiplication_Mod_P t = Multiplication_Mod_P( + context_object, x, y, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk); + return t.r; }; - auto AddModP = [&context_object, P, PP, ZERO, num_chunks, - bit_size_chunk](std::vector x, - std::vector y) { + auto AddModP = [&context_object, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk](std::vector x, + std::vector y) { Addition_Mod_P t = - Addition_Mod_P(context_object, x, y, P, PP, ZERO, - num_chunks, bit_size_chunk); - return t.res_r; + Addition_Mod_P(context_object, x, y, input_p, input_pp, + input_zero, num_chunks, bit_size_chunk); + return t.r; }; - auto NegModP = [&context_object, P, PP, ZERO, num_chunks, - bit_size_chunk](std::vector x) { + auto NegModP = [&context_object, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk](std::vector x) { Negation_Mod_P t = - Negation_Mod_P(context_object, x, P, PP, ZERO, num_chunks, - bit_size_chunk); - return t.res_r; + Negation_Mod_P(context_object, x, input_p, input_pp, + input_zero, num_chunks, bit_size_chunk); + return t.r; }; - auto t1 = NegModP(XP); // t1 = -xP - auto t2 = AddModP(XQ, t1); // t2 = xQ + t1 = xQ - xP + auto t1 = NegModP(input_xP); // t1 = -xP + auto t2 = AddModP(input_xQ, t1); // t2 = xQ + t1 = xQ - xP auto t3 = MultModP(t2, LAMBDA); // t3 = t2 * lambda = (xQ-xP)lambda - auto t4 = AddModP(t3, YP); // t4 = t3 + yP = (xQ-xP)lambda + yP - CopyConstrain(t4, YQ); // (xQ - xP)lambda + yP = yQ - auto t5 = AddModP(XR, XP); // t5 = xR + xP - auto t6 = AddModP(t5, XQ); // t6 = t5 + xQ = xR + xP + xQ + auto t4 = AddModP(t3, input_yP); // t4 = t3 + yP = (xQ-xP)lambda + yP + CopyConstrain(t4, input_yQ); // (xQ - xP)lambda + yP = yQ + auto t5 = AddModP(XR, input_xP); // t5 = xR + xP + auto t6 = AddModP(t5, input_xQ); // t6 = t5 + xQ = xR + xP + xQ auto t7 = MultModP(LAMBDA, LAMBDA); // t7 = lambda * lambda - CopyConstrain(t6, t7); // xR + xP + xQ = lambda^2 - auto t8 = AddModP(YR, YP); // t8 = yR + yP + CopyConstrain(t6, t7); // xR + xP + xQ = lambda^2 + auto t8 = AddModP(YR, input_yP); // t8 = yR + yP auto t9 = NegModP(XR); // t9 = -xR - auto t10 = AddModP(XP, t9); // t10 = xP + t9 = xP - xR + auto t10 = AddModP(input_xP, t9); // t10 = xP + t9 = xP - xR auto t11 = MultModP(LAMBDA,t10); // t11 = lambda * t10 =lambda(xP-xR) - CopyConstrain(t8, t11); // yR + yP = lambda(xP - xR) + CopyConstrain(t8, t11); // yR + yP = lambda(xP - xR) - if (make_links) { - for (std::size_t i = 0; i < num_chunks; ++i) { - copy_constrain(XP[i], input_xP[i]); - copy_constrain(YP[i], input_yP[i]); - copy_constrain(XQ[i], input_xQ[i]); - copy_constrain(YQ[i], input_yQ[i]); - copy_constrain(P[i], input_p[i]); - copy_constrain(PP[i], input_pp[i]); - } - copy_constrain(ZERO, input_zero); - } - - for (int i = 0; i < num_chunks; ++i) { - inp_xP.push_back(input_xP[i]); - inp_yP.push_back(input_yP[i]); - inp_xQ.push_back(input_xQ[i]); - inp_yQ.push_back(input_yQ[i]); - inp_pp.push_back(input_p[i]); - inp_pp.push_back(input_pp[i]); - } for (int i = 0; i < num_chunks; ++i) { - res_xR.push_back(XR[i]); - res_yR.push_back(YR[i]); + xR.push_back(XR[i]); + yR.push_back(YR[i]); } } }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp index 365c135ae..ada2a200e 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp @@ -50,9 +50,11 @@ namespace nil { // Addition mod p // operates on k-chunked x,y, p, p' // Parameters: num_chunks = k, bit_size_chunk = b - // Input: x[0], ..., x[k-1], y[0], ..., y[k-1], p[0], ..., p[k-1], p'[0], ..., p'[k-1], 0 - // Intermediate values: q, t[0], ..., t[k-1], carry[k-1], t'[0], ..., t'[k-1], t"[0], ..., t"[k-1], carry"[k-1] - // Output: r[0] = x[0] + y[0] - qp[0], ..., r[k-1] = x[k-1] + y[k-1] -qp[k-1] + // Input: x[0], ..., x[k-1], y[0], ..., y[k-1], p[0], ..., p[k-1], p'[0], + // ..., p'[k-1], 0[0], ..., 0[k-1] (expects zero vector constant as input) + // Intermediate values: q, t[0], ..., t[k-1], carry[k-1], t'[0], ..., + // t'[k-1], t"[0], ..., t"[k-1], carry"[k-1] Output: r[0] = x[0] + y[0] - + // qp[0], ..., r[k-1] = x[k-1] + y[k-1] -qp[k-1] // template @@ -62,7 +64,7 @@ namespace nil { std::vector y; std::vector p; std::vector pp; - TYPE zero; + std::vector zero; }; template, std::tuple<>>::type; - public: - std::vector inp_x; - std::vector inp_y; - std::vector inp_p; - std::vector inp_pp; - std::vector res_r; + std::vector r; static table_params get_minimal_requirements( std::size_t num_chunks, std::size_t bit_size_chunk) { std::size_t witness = 4 * num_chunks + 1; constexpr std::size_t public_inputs = 1; constexpr std::size_t constants = 0; - // rows = 4096-1 so that lookup table is not too hard to fit and padding doesn't inflate the table + // rows = 4096-1 so that lookup table is not too hard to fit and + // padding doesn't inflate the table constexpr std::size_t rows = 4095; return {witness, public_inputs, constants, rows}; } static std::tuple, std::vector, - std::vector, std::vector, TYPE> + std::vector, std::vector, + std::vector> form_input(context_type &context_object, raw_input_type raw_input, std::size_t num_chunks, std::size_t bit_size_chunk) { std::vector input_x(num_chunks); std::vector input_y(num_chunks); std::vector input_p(num_chunks); std::vector input_pp(num_chunks); - TYPE input_zero; + std::vector input_zero(num_chunks); if constexpr (stage == GenerationStage::ASSIGNMENT) { for (std::size_t i = 0; i < num_chunks; i++) { @@ -117,8 +116,8 @@ namespace nil { input_y[i] = raw_input.y[i]; input_p[i] = raw_input.p[i]; input_pp[i] = raw_input.pp[i]; + input_zero[i] = raw_input.zero[i]; } - input_zero = raw_input.zero; } for (std::size_t i = 0; i < num_chunks; i++) { context_object.allocate(input_x[i], 0, i, @@ -129,9 +128,9 @@ namespace nil { column_type::public_input); context_object.allocate(input_pp[i], 0, i + 3 * num_chunks, column_type::public_input); + context_object.allocate(input_zero[i], 0, i + 4 * num_chunks, + column_type::public_input); } - context_object.allocate(input_zero, 0, 4 * num_chunks, - column_type::public_input); return std::make_tuple(input_x, input_y, input_p, input_pp, input_zero); } @@ -139,11 +138,13 @@ namespace nil { addition_mod_p(context_type &context_object, std::vector input_x, std::vector input_y, std::vector input_p, std::vector input_pp, - TYPE input_zero, std::size_t num_chunks, + std::vector input_zero, std::size_t num_chunks, std::size_t bit_size_chunk, bool make_links = true) : generic_component(context_object) { using integral_type = typename FieldType::integral_type; - using extended_integral_type = nil::crypto3::multiprecision::big_uint<2* NonNativeFieldType::modulus_bits>; + using extended_integral_type = + nil::crypto3::multiprecision::big_uint< + 2 * NonNativeFieldType::modulus_bits>; using Carry_On_Addition = typename bbf::components::carry_on_addition; @@ -154,105 +155,77 @@ namespace nil { using Range_Check = typename bbf::components::range_check_multi; - std::vector X(num_chunks); - std::vector Y(num_chunks); - std::vector P(num_chunks); - std::vector PP(num_chunks); - std::vector Z(num_chunks); - std::vector ZERO(num_chunks); + std::vector R(num_chunks); TYPE Q; if constexpr (stage == GenerationStage::ASSIGNMENT) { Q = 0; - for (std::size_t i = 0; i < num_chunks; ++i) { - X[i] = input_x[i]; - Y[i] = input_y[i]; - P[i] = input_p[i]; - PP[i] = input_pp[i]; - ZERO[i] = input_zero; - } - extended_integral_type x = 0, y = 0, z = 0, p = 0, pow = 1; + extended_integral_type x = 0, y = 0, r = 0, p = 0, pow = 1; // Populate x, y, p for (std::size_t i = 0; i < num_chunks; ++i) { - x += extended_integral_type(integral_type(X[i].data)) * + x += extended_integral_type( + integral_type(input_x[i].data)) * pow; - y += extended_integral_type(integral_type(Y[i].data)) * + y += extended_integral_type( + integral_type(input_y[i].data)) * pow; - p += extended_integral_type(integral_type(P[i].data)) * + p += extended_integral_type( + integral_type(input_p[i].data)) * pow; pow <<= bit_size_chunk; } - z = x + y; // x + y = z + qp - if (z >= p) { - z -= p; + r = x + y; // x + y = r + qp + if (r >= p) { + r -= p; Q = 1; } extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; for (std::size_t i = 0; i < num_chunks; ++i) { - Z[i] = TYPE(z & mask); - z >>= bit_size_chunk; + R[i] = TYPE(r & mask); + r >>= bit_size_chunk; } } for (std::size_t i = 0; i < num_chunks; ++i) { - allocate(X[i]); - allocate(Y[i]); - allocate(P[i]); - allocate(PP[i]); - allocate(Z[i]); - allocate(ZERO[i]); + allocate(R[i]); } allocate(Q); Carry_On_Addition ca_1 = Carry_On_Addition( - context_object, X, Y, num_chunks, bit_size_chunk); - Range_Check rc_1 = Range_Check(context_object, ca_1.res_r, - num_chunks, bit_size_chunk); + context_object, input_x, input_y, num_chunks, bit_size_chunk); + Range_Check rc_1 = Range_Check(context_object, ca_1.r, num_chunks, + bit_size_chunk); //(qp = 0 or p) - Choice_Function cf = - Choice_Function(context_object, Q, ZERO, P, num_chunks); + Choice_Function cf = Choice_Function( + context_object, Q, input_zero, input_p, num_chunks); Carry_On_Addition ca_2 = - Carry_On_Addition(context_object, cf.res_r, Z, num_chunks, - bit_size_chunk); // qp + z + Carry_On_Addition(context_object, cf.r, R, num_chunks, + bit_size_chunk); // qp + r - // carry_on_addition results should be equal to each other x + y = z + qp + // carry_on_addition results should be equal to each other x + y + // = r + qp for (std::size_t i = 0; i < num_chunks; i++) { - copy_constrain(ca_1.res_r[i], ca_2.res_r[i]); + copy_constrain(ca_1.r[i], ca_2.r[i]); } - copy_constrain(ca_1.res_c, ca_2.res_c); + copy_constrain(ca_1.c, ca_2.c); - Range_Check rc_2 = Range_Check(context_object, ca_2.res_r, - num_chunks, bit_size_chunk); + Range_Check rc_2 = Range_Check(context_object, ca_2.r, num_chunks, + bit_size_chunk); Range_Check rc_3 = - Range_Check(context_object, Z, num_chunks, bit_size_chunk); - - Check_Mod_P cm = Check_Mod_P(context_object, Z, PP, ZERO[0], - num_chunks, bit_size_chunk); + Range_Check(context_object, R, num_chunks, bit_size_chunk); - if (make_links) { - for (std::size_t i = 0; i < num_chunks; ++i) { - copy_constrain(X[i], input_x[i]); - copy_constrain(Y[i], input_y[i]); - copy_constrain(P[i], input_p[i]); - copy_constrain(PP[i], input_pp[i]); - copy_constrain(ZERO[i], input_zero); - } - } + Check_Mod_P cm = + Check_Mod_P(context_object, R, input_pp, input_zero[0], + num_chunks, bit_size_chunk); for (int i = 0; i < num_chunks; ++i) { - inp_x.push_back(input_x[i]); - inp_y.push_back(input_y[i]); - inp_p.push_back(input_p[i]); - inp_pp.push_back(input_pp[i]); - } - for (int i = 0; i < num_chunks; ++i) { - res_r.push_back(Z[i]); + r.push_back(R[i]); } } }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp index bb2e916f5..54bc9d2bb 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp @@ -44,7 +44,8 @@ namespace nil { // Parameters: num_chunks = k, bit_size_chunk = b // Checking that x is in the interval [0;p-1] // operates on k-chunked x and p' = 2^(kb) - p - // Input: x[0], ..., x[k-1], pp[0], ..., pp[k-1] + // Input: x[0], ..., x[k-1], pp[0], ..., pp[k-1], 0 + // (expects zero constant as input) // Output: none template @@ -72,8 +73,6 @@ namespace nil { check_mod_p_raw_input, std::tuple<>>::type; public: - std::vector inp_x; - std::vector inp_pp; TYPE output; static table_params get_minimal_requirements(std::size_t num_chunks, @@ -125,18 +124,13 @@ namespace nil { using Range_Check = typename bbf::components::range_check_multi; Carry_On_Addition ca = Carry_On_Addition(context_object,input_x,input_pp,num_chunks,bit_size_chunk); - Range_Check rc = Range_Check(context_object, ca.res_r,num_chunks,bit_size_chunk); + Range_Check rc = Range_Check(context_object, ca.r,num_chunks,bit_size_chunk); if(expect_output){ - output = ca.res_c; + output = ca.c; } else{ - copy_constrain(ca.res_c,input_zero); - } - - for (std::size_t i = 0; i < num_chunks; i++) { - inp_x.push_back(input_x[i]); - inp_pp.push_back(input_pp[i]); + copy_constrain(ca.c,input_zero); } } diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp index 458344a76..1690f953f 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp @@ -23,7 +23,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //---------------------------------------------------------------------------// -// @file Declaration of interfaces for PLONK component wrapping the BBF-component interface +// @file Declaration of interfaces for PLONK component wrapping the BBF-component +// interface //---------------------------------------------------------------------------// #ifndef CRYPTO3_BBF_COMPONENTS_FLEXIBLE_MULTIPLICATION_HPP @@ -34,13 +35,13 @@ #include #include #include -#include #include #include +#include -#include #include -#include +#include +#include namespace nil { namespace blueprint { @@ -50,9 +51,10 @@ namespace nil { // Parameters: num_chunks = k, bit_size_chunk = b, T = k*b // native field module = n, non-native field module = p, pp = 2^T - p ( or -p(mod2^t)) // NB: 2^T * n > p^2 + p - // Input: x[0],..., x[k-1], y[0],..., y[k-1], p[0],..., p[k-1], pp[0],...,p[k-1] + // Input: x[0],..., x[k-1], y[0],..., y[k-1], p[0],..., p[k-1], pp[0],...,p[k-1], 0 + // (expects zero constant as input) // Output: r[0],..., r[k-1] - + template struct flexible_multiplication_raw_input { using TYPE = typename FieldType::value_type; @@ -63,8 +65,10 @@ namespace nil { TYPE zero; }; - template - class flexible_multiplication : public generic_component { + template + class flexible_multiplication + : public generic_component { using generic_component::allocate; using generic_component::copy_constrain; using generic_component::constrain; @@ -75,39 +79,36 @@ namespace nil { using typename generic_component::TYPE; using typename generic_component::context_type; using typename generic_component::table_params; - using raw_input_type = - typename std::conditional, - std::tuple<>>::type; - + using raw_input_type = typename std::conditional< + stage == GenerationStage::ASSIGNMENT, + flexible_multiplication_raw_input, std::tuple<>>::type; public: - std::vector inp_x; - std::vector inp_y; - std::vector inp_p; - std::vector inp_pp; - std::vector res_r; - - static table_params get_minimal_requirements(std::size_t num_chunks,std::size_t bit_size_chunk) { - //The 6 variables chunks fit in 2 rows, and there is a 3rd additionnal row available for the constraint values - std::size_t witness =3*num_chunks; + std::vector r; + + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { + // The 6 variables chunks fit in 2 rows, and there is a 3rd + // additionnal row available for the constraint values + std::size_t witness = 3 * num_chunks; constexpr std::size_t public_inputs = 1; constexpr std::size_t constants = 0; - //rows = 4096-1 so that lookup table is not too hard to fit and padding doesn't inflate the table + // rows = 4096-1 so that lookup table is not too hard to fit and + // padding doesn't inflate the table constexpr std::size_t rows = 4095; return {witness, public_inputs, constants, rows}; } - static std::tuple,std::vector,std::vector,std::vector,TYPE> form_input(context_type &context_object, - raw_input_type raw_input, - std::size_t num_chunks, - std::size_t bit_size_chunk) { + static std::tuple, std::vector, + std::vector, std::vector, TYPE> + form_input(context_type &context_object, raw_input_type raw_input, + std::size_t num_chunks, std::size_t bit_size_chunk) { std::vector input_x(num_chunks); std::vector input_y(num_chunks); std::vector input_p(num_chunks); - std::vector input_pp(num_chunks); - TYPE input_zero; - + std::vector input_pp(num_chunks); + TYPE input_zero; + if constexpr (stage == GenerationStage::ASSIGNMENT) { for (std::size_t i = 0; i < num_chunks; i++) { input_x[i] = raw_input.x[i]; @@ -117,41 +118,53 @@ namespace nil { } input_zero = raw_input.zero; } - for (std::size_t i = 0; i < num_chunks; i++) - { - context_object.allocate(input_x[i], 0, i, column_type::public_input); - context_object.allocate(input_y[i], 0, i+num_chunks, column_type::public_input); - context_object.allocate(input_p[i], 0, i+2*num_chunks, column_type::public_input); - context_object.allocate(input_pp[i], 0, i+3*num_chunks, column_type::public_input); + for (std::size_t i = 0; i < num_chunks; i++) { + context_object.allocate(input_x[i], 0, i, + column_type::public_input); + context_object.allocate(input_y[i], 0, i + num_chunks, + column_type::public_input); + context_object.allocate(input_p[i], 0, i + 2 * num_chunks, + column_type::public_input); + context_object.allocate(input_pp[i], 0, i + 3 * num_chunks, + column_type::public_input); } - context_object.allocate(input_zero, 0, 4*num_chunks, column_type::public_input); - return std::make_tuple(input_x,input_y,input_p,input_pp,input_zero); + context_object.allocate(input_zero, 0, 4 * num_chunks, + column_type::public_input); + return std::make_tuple(input_x, input_y, input_p, input_pp, + input_zero); } - - flexible_multiplication(context_type &context_object, std::vector input_x, std::vector input_y,std::vector input_p,std::vector input_pp, TYPE input_zero, - std::size_t num_chunks, std::size_t bit_size_chunk, + flexible_multiplication(context_type &context_object, + std::vector input_x, + std::vector input_y, + std::vector input_p, + std::vector input_pp, TYPE input_zero, + std::size_t num_chunks, + std::size_t bit_size_chunk, bool make_links = true) : generic_component(context_object) { - - using extended_integral_type = nil::crypto3::multiprecision::big_uint<2* NonNativeFieldType::modulus_bits>; - + using extended_integral_type = + nil::crypto3::multiprecision::big_uint< + 2 * NonNativeFieldType::modulus_bits>; + using integral_type = typename FieldType::integral_type; - using Check_Mod_P = typename bbf::components::check_mod_p; - using Range_Check = typename bbf::components::range_check_multi; - + using Check_Mod_P = + typename bbf::components::check_mod_p; + using Range_Check = + typename bbf::components::range_check_multi; + std::vector X(num_chunks); std::vector Y(num_chunks); std::vector P(num_chunks); std::vector PP(num_chunks); - std::vector Q(num_chunks); - std::vector R(num_chunks); + std::vector Q(num_chunks); + std::vector R(num_chunks); std::vector Z(num_chunks); std::vector A(num_chunks); - std::vector B(2*(num_chunks - 2)); + std::vector B(2 * (num_chunks - 2)); TYPE x_n; TYPE y_n; @@ -166,31 +179,37 @@ namespace nil { P[i] = input_p[i]; PP[i] = input_pp[i]; } - extended_integral_type foreign_p = 0, - foreign_x = 0, - foreign_y = 0, - pow = 1; - + extended_integral_type foreign_p = 0, foreign_x = 0, + foreign_y = 0, pow = 1; + for (std::size_t i = 0; i < num_chunks; ++i) { - foreign_x += extended_integral_type(integral_type(X[i].data)) * pow; - foreign_y += extended_integral_type(integral_type(Y[i].data)) * pow; - foreign_p += extended_integral_type(integral_type(P[i].data)) * pow; + foreign_x += + extended_integral_type(integral_type(X[i].data)) * + pow; + foreign_y += + extended_integral_type(integral_type(Y[i].data)) * + pow; + foreign_p += + extended_integral_type(integral_type(P[i].data)) * + pow; pow <<= bit_size_chunk; } - extended_integral_type foreign_r = (foreign_x * foreign_y) % foreign_p, // r = x*y % p - foreign_q = (foreign_x * foreign_y - foreign_r) / foreign_p; // q = (x*y - r)/p - extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; + extended_integral_type foreign_r = (foreign_x * foreign_y) % + foreign_p, // r = x*y % p + foreign_q = (foreign_x * foreign_y - foreign_r) / + foreign_p; // q = (x*y - r)/p + extended_integral_type mask = + (extended_integral_type(1) << bit_size_chunk) - 1; for (std::size_t j = 0; j < num_chunks; ++j) { Q[j] = TYPE(foreign_q & mask); R[j] = TYPE(foreign_r & mask); foreign_q >>= bit_size_chunk; foreign_r >>= bit_size_chunk; } - } - for (std::size_t i = 0; i < num_chunks; ++i){ + for (std::size_t i = 0; i < num_chunks; ++i) { allocate(X[i]); allocate(Y[i]); allocate(PP[i]); @@ -214,43 +233,50 @@ namespace nil { allocate(q_n); allocate(p_n); allocate(r_n); - //constrain X*Y - Q*P - R = 0 + // constrain X*Y - Q*P - R = 0 constrain(x_n * y_n - q_n * p_n - r_n); // computation mod 2^T - // (mod 2^t)xy + qp' = [x_0, x_1, x_2, x_3] â‹… [y_0, y_1, y_2, y_3] + [q_0, q_1, q_2, q_3] â‹… [pp_0, pp_1, pp_2, pp_3] + // (mod 2^t)xy + qp' = [x_0, x_1, x_2, x_3] â‹… [y_0, y_1, y_2, y_3] + // + [q_0, q_1, q_2, q_3] â‹… [pp_0, pp_1, pp_2, pp_3] // z_0 = x_0 â‹… y_0 + q_0 â‹… pp_0 // z_1 = x_0 â‹… y_1 + x_1 â‹… y_0 + q_0 â‹… pp_1 + q_1 â‹… pp_0 - // z_2 = x_0 â‹… y_2 + x_1 â‹… y_1 + x_2 â‹… y_0 + q_0 â‹… pp_2 + q_1 â‹… pp_1 + q_2 â‹… pp_0 - // z_3 = x_0 â‹… y_3 + x_1 â‹… y_2 + x_2 â‹… y_1 + x_3 â‹… y_0 + q_0 â‹… pp_3 + q_1 â‹… pp_2 + q_2 â‹… pp_1 + q_3 â‹… pp_0 - // Result = z_0 â‹… 2^{0b} + z_1 â‹… 2^{1b} + z_2 â‹… 2^{2b} + z_3 â‹… 2^{3b} + // z_2 = x_0 â‹… y_2 + x_1 â‹… y_1 + x_2 â‹… y_0 + q_0 â‹… pp_2 + q_1 â‹… + // pp_1 + q_2 â‹… pp_0 z_3 = x_0 â‹… y_3 + x_1 â‹… y_2 + x_2 â‹… y_1 + + // x_3 â‹… y_0 + q_0 â‹… pp_3 + q_1 â‹… pp_2 + q_2 â‹… pp_1 + q_3 â‹… + // pp_0 + // Result = z_0 â‹… 2^{0b} + z_1 â‹… 2^{1b} + z_2 â‹… 2^{2b} + z_3 â‹… + // 2^{3b} for (std::size_t i = 0; i < num_chunks; ++i) { Z[i] = TYPE(0); for (std::size_t j = 0; j <= i; ++j) { - Z[i] += X[j] * Y[i-j] + PP[j] * Q[i-j]; + Z[i] += X[j] * Y[i - j] + PP[j] * Q[i - j]; } allocate(Z[i]); } - if constexpr (stage == GenerationStage::ASSIGNMENT) { A[0] = Z[0] - R[0]; - integral_type a_integral = integral_type(A[0].data) >> bit_size_chunk; + integral_type a_integral = + integral_type(A[0].data) >> bit_size_chunk; A[0] = TYPE(a_integral); for (std::size_t i = 1; i < num_chunks; ++i) { - A[i] = (Z[i] + A[i-1] - R[i]); + A[i] = (Z[i] + A[i - 1] - R[i]); a_integral = integral_type(A[i].data) >> bit_size_chunk; A[i] = TYPE(a_integral); } for (std::size_t i = 0; i < num_chunks - 2; ++i) { - B[2*i] = TYPE(integral_type(A[i].data) & ((integral_type(1) << bit_size_chunk) - 1)); - B[2*i + 1] =TYPE(integral_type(A[i].data) >> bit_size_chunk); + B[2 * i] = + TYPE(integral_type(A[i].data) & + ((integral_type(1) << bit_size_chunk) - 1)); + B[2 * i + 1] = + TYPE(integral_type(A[i].data) >> bit_size_chunk); } } integral_type b_shift = integral_type(1) << bit_size_chunk; allocate(A[0]); - constrain(A[0]*b_shift - Z[0] + R[0]); + constrain(A[0] * b_shift - Z[0] + R[0]); // constrain that the last t bits of z are equal to r: // z_0 - r_0 = a_0 â‹… 2^b // z_1 + a_0 - r_1 = a_1 â‹… 2^b @@ -258,36 +284,42 @@ namespace nil { // z_3 + a_2 - r_3 = a_3 â‹… 2^b for (std::size_t i = 1; i < num_chunks; ++i) { allocate(A[i]); - constrain(A[i]*b_shift - Z[i] - A[i-1]+ R[i]); + constrain(A[i] * b_shift - Z[i] - A[i - 1] + R[i]); } // If there is a fault in the computation: - // a'_0 = a_0 + 2^{3b+1} + // a'_0 = a_0 + 2^{3b+1} // a'_1 = a_1 + 2^{2b+1}, a'_2 = a_2 + 2^{b+1} // - // This results in a faulty `a_2`, which can cause an error in `z_3 - r_3`. - // The same issue applies for `a_1`. However, higher `a_i` values will only - // interfere with other `a_j` values and not with `z_i` or `r_i`. + // This results in a faulty `a_2`, which can cause an error in + // `z_3 - r_3`. The same issue applies for `a_1`. However, higher + // `a_i` values will only interfere with other `a_j` values and + // not with `z_i` or `r_i`. // // a_0 = b_0 + b_1 â‹… 2^b // a_1 = b_2 + b_3 â‹… 2^b for (std::size_t i = 0; i < num_chunks - 2; ++i) { - allocate(B[2*i]); - allocate(B[2*i+1]); - constrain(B[2*i] + B[2*i+1]*b_shift - A[i]); + allocate(B[2 * i]); + allocate(B[2 * i + 1]); + constrain(B[2 * i] + B[2 * i + 1] * b_shift - A[i]); } - Range_Check rc1 = Range_Check(context_object, R,num_chunks,bit_size_chunk); - Range_Check rc2 = Range_Check(context_object, Q,num_chunks,bit_size_chunk); - Range_Check rc3 = Range_Check(context_object, B,num_chunks,bit_size_chunk); - - Check_Mod_P c1 = Check_Mod_P(context_object, R,PP,input_zero,num_chunks,bit_size_chunk,false); - Check_Mod_P c2 = Check_Mod_P(context_object, Q,PP,input_zero,num_chunks,bit_size_chunk,false); - - //Starting b\n - if(num_chunks>2){ - std::vector B_X[2 * (num_chunks > 2)]; + Range_Check rc1 = + Range_Check(context_object, R, num_chunks, bit_size_chunk); + Range_Check rc2 = + Range_Check(context_object, Q, num_chunks, bit_size_chunk); + Range_Check rc3 = + Range_Check(context_object, B, num_chunks, bit_size_chunk); + + Check_Mod_P c1 = Check_Mod_P(context_object, R, PP, input_zero, + num_chunks, bit_size_chunk, false); + Check_Mod_P c2 = Check_Mod_P(context_object, Q, PP, input_zero, + num_chunks, bit_size_chunk, false); + + // Starting b\n + if (num_chunks > 2) { + std::vector B_X[2 * (num_chunks > 2)]; for (int i = 0; i < 2 * (num_chunks > 2); ++i) { B_X[i].resize(num_chunks); @@ -296,14 +328,14 @@ namespace nil { allocate(B_X[i][j]); } - B_X[i].push_back(X[num_chunks - 3]); B_X[i].push_back(X[num_chunks - 3]); - allocate(B_X[i][num_chunks-2]); - allocate(B_X[i][num_chunks-1]); - Range_Check(context_object, B_X[i],num_chunks,bit_size_chunk); - } + B_X[i].push_back(X[num_chunks - 3]); + allocate(B_X[i][num_chunks - 2]); + allocate(B_X[i][num_chunks - 1]); + Range_Check(context_object, B_X[i], num_chunks, + bit_size_chunk); + } } - if (make_links) { for (std::size_t i = 0; i < num_chunks; ++i) { @@ -315,39 +347,40 @@ namespace nil { } for (int i = 0; i < num_chunks; ++i) { - inp_x.push_back(input_x[i]); - inp_y.push_back(input_y[i]); - inp_p.push_back(input_p[i]); - inp_pp.push_back(input_pp[i]); - } - for (int i = 0; i < num_chunks; ++i) { - res_r.push_back(R[i]); + r.push_back(R[i]); } } - }; template - class pallas_flexible_multiplication : public flexible_multiplication { - - using Base = flexible_multiplication; - public: - using Base::Base; + class pallas_flexible_multiplication + : public flexible_multiplication< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { + using Base = flexible_multiplication< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type>; + + public: + using Base::Base; }; template - class vesta_flexible_multiplication : public flexible_multiplication { - - using Base = flexible_multiplication; - public: - using Base::Base; + class vesta_flexible_multiplication + : public flexible_multiplication< + FieldType, stage, + crypto3::algebra::curves::vesta::base_field_type> { + using Base = flexible_multiplication< + FieldType, stage, + crypto3::algebra::curves::vesta::base_field_type>; + + public: + using Base::Base; }; - + } // namespace components } // namespace bbf } // namespace blueprint } // namespace nil -#endif // CRYPTO3_BBF_COMPONENTS_FLEXIBLE_MULTIPLICATION_HPP \ No newline at end of file +#endif // CRYPTO3_BBF_COMPONENTS_FLEXIBLE_MULTIPLICATION_HPP diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp index 017e86cc6..f3bf3c21e 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp @@ -50,7 +50,8 @@ namespace nil { namespace components { // Parameters: num_chunks = k, bit_size_chunk = b // Finding the negative r of integer x, modulo p and checking that x + r = 0 mod p - // Input: x[0], ..., x[k-1], p[0], ..., p[k-1], pp[0], ..., pp[k-1], 0 (expects zero constant as input) + // Input: x[0], ..., x[k-1], p[0], ..., p[k-1], pp[0], ..., pp[k-1], 0[0], ..., 0[k-1] + // (expects zero vector constant as input) // Output: r[0], ..., r[k-1] template @@ -59,7 +60,7 @@ namespace nil { std::vector x; std::vector p; std::vector pp; - TYPE zero; + std::vector zero; }; template, std::tuple<>>::type; - public: - std::vector inp_x; - std::vector inp_p; - std::vector inp_pp; - std::vector res_r; + std::vector r; static table_params get_minimal_requirements( std::size_t num_chunks, std::size_t bit_size_chunk) { @@ -99,22 +96,23 @@ namespace nil { } static std::tuple, std::vector, - std::vector, TYPE> + std::vector, std::vector> form_input(context_type &context_object, raw_input_type raw_input, std::size_t num_chunks, std::size_t bit_size_chunk) { std::vector input_x(num_chunks); std::vector input_p(num_chunks); std::vector input_pp(num_chunks); - TYPE input_zero; + std::vector input_zero(num_chunks); if constexpr (stage == GenerationStage::ASSIGNMENT) { for (std::size_t i = 0; i < num_chunks; i++) { input_x[i] = raw_input.x[i]; input_p[i] = raw_input.p[i]; input_pp[i] = raw_input.pp[i]; + input_zero[i] = raw_input.zero[i]; } - input_zero = raw_input.zero; } + for (std::size_t i = 0; i < num_chunks; i++) { context_object.allocate(input_x[i], 0, i, column_type::public_input); @@ -122,20 +120,23 @@ namespace nil { column_type::public_input); context_object.allocate(input_pp[i], 0, i + 2 * num_chunks, column_type::public_input); + context_object.allocate(input_zero[i], 0, i + 3 * num_chunks, + column_type::public_input); } - context_object.allocate(input_zero, 0, 3 * num_chunks, - column_type::public_input); + return std::make_tuple(input_x, input_p, input_pp, input_zero); } negation_mod_p(context_type &context_object, std::vector input_x, std::vector input_p, - std::vector input_pp, TYPE input_zero, - std::size_t num_chunks, std::size_t bit_size_chunk, - bool make_links = true) + std::vector input_pp, + std::vector input_zero, std::size_t num_chunks, + std::size_t bit_size_chunk, bool make_links = true) : generic_component(context_object) { using integral_type = typename FieldType::integral_type; - using extended_integral_type = nil::crypto3::multiprecision::big_uint<2* NonNativeFieldType::modulus_bits>; + using extended_integral_type = + nil::crypto3::multiprecision::big_uint< + 2 * NonNativeFieldType::modulus_bits>; using Carry_On_Addition = typename bbf::components::carry_on_addition; @@ -146,85 +147,58 @@ namespace nil { using Range_Check = typename bbf::components::range_check_multi; - std::vector X(num_chunks); - std::vector Y(num_chunks); - std::vector P(num_chunks); - std::vector PP(num_chunks); - std::vector ZERO(num_chunks); + std::vector R(num_chunks); TYPE Q; if constexpr (stage == GenerationStage::ASSIGNMENT) { - for (std::size_t i = 0; i < num_chunks; ++i) { - X[i] = input_x[i]; - P[i] = input_p[i]; - PP[i] = input_pp[i]; - ZERO[i] = input_zero; - } - - extended_integral_type x = 0, y = 0, p = 0, pow = 1; + extended_integral_type x = 0, r = 0, p = 0, pow = 1; // Populate x, p for (std::size_t i = 0; i < num_chunks; ++i) { - x += extended_integral_type(integral_type(X[i].data)) * + x += extended_integral_type( + integral_type(input_x[i].data)) * pow; - p += extended_integral_type(integral_type(P[i].data)) * + p += extended_integral_type( + integral_type(input_p[i].data)) * pow; pow <<= bit_size_chunk; } Q = (x == 0) ? 0 : 1; - y = (x == 0) ? 0 : p - x; // if x = 0, then y = 0 + r = (x == 0) ? 0 : p - x; // if x = 0, then r = 0 extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; for (std::size_t i = 0; i < num_chunks; ++i) { - Y[i] = TYPE(y & mask); - y >>= bit_size_chunk; + R[i] = TYPE(r & mask); + r >>= bit_size_chunk; } } - + allocate(Q); for (std::size_t i = 0; i < num_chunks; ++i) { - allocate(X[i]); - allocate(Y[i]); - allocate(P[i]); - allocate(PP[i]); - allocate(ZERO[i]); + allocate(R[i]); } - allocate(Q); - Choice_Function cf = - Choice_Function(context_object, Q, ZERO, P, num_chunks); + Choice_Function cf = Choice_Function( + context_object, Q, input_zero, input_p, num_chunks); Carry_On_Addition ca = Carry_On_Addition( - context_object, X, Y, num_chunks, bit_size_chunk); + context_object, input_x, R, num_chunks, bit_size_chunk); - // x + y = 0 or p + // x + r = 0 or p for (std::size_t i = 0; i < num_chunks; i++) { - copy_constrain(ca.res_r[i], cf.res_r[i]); + copy_constrain(ca.r[i], cf.r[i]); } - copy_constrain(ca.res_c, ZERO[0]); + copy_constrain(ca.c, input_zero[0]); Range_Check rc = - Range_Check(context_object, Y, num_chunks, bit_size_chunk); + Range_Check(context_object, R, num_chunks, bit_size_chunk); - Check_Mod_P cm = Check_Mod_P(context_object, Y, PP, ZERO[0], - num_chunks, bit_size_chunk); - - if (make_links) { - for (std::size_t i = 0; i < num_chunks; ++i) { - copy_constrain(X[i], input_x[i]); - copy_constrain(P[i], input_p[i]); - copy_constrain(PP[i], input_pp[i]); - copy_constrain(ZERO[i], input_zero); - } - } + Check_Mod_P cm = + Check_Mod_P(context_object, R, input_pp, input_zero[0], + num_chunks, bit_size_chunk); for (int i = 0; i < num_chunks; ++i) { - inp_x.push_back(input_x[i]); - inp_p.push_back(input_p[i]); - inp_pp.push_back(input_pp[i]); - } - for (int i = 0; i < num_chunks; ++i) { - res_r.push_back(Y[i]); + r.push_back(R[i]); } } }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp index de5d51dac..cc9dc1bde 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp @@ -22,7 +22,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //---------------------------------------------------------------------------// -// @file Declaration of interfaces for PLONK component wrapping the BBF-component interface +// @file Declaration of interfaces for PLONK component wrapping the BBF-component +// interface //---------------------------------------------------------------------------// #ifndef CRYPTO3_BBF_COMPONENTS_CARRY_ON_ADDITION_HPP @@ -64,23 +65,21 @@ namespace nil { std::tuple<>>::type; public: - std::vector inp_x; - std::vector inp_y; - std::vector res_r; - TYPE res_c; + std::vector r; + TYPE c; - static table_params get_minimal_requirements(std::size_t num_chunks,std::size_t bit_size_chunk) { + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { std::size_t witness = 2; constexpr std::size_t public_inputs = 1; constexpr std::size_t constants = 0; - std::size_t rows = 3*num_chunks + 1; + std::size_t rows = 3 * num_chunks + 1; return {witness, public_inputs, constants, rows}; } - static std::tuple,std::vector> form_input(context_type &context_object, - raw_input_type raw_input, - std::size_t num_chunks, - std::size_t bit_size_chunk) { + static std::tuple, std::vector> form_input( + context_type &context_object, raw_input_type raw_input, + std::size_t num_chunks, std::size_t bit_size_chunk) { std::vector input_x(num_chunks); std::vector input_y(num_chunks); if constexpr (stage == GenerationStage::ASSIGNMENT) { @@ -89,57 +88,57 @@ namespace nil { input_y[i] = raw_input.y[i]; } } - for (std::size_t i = 0; i < num_chunks; ++i) - { - context_object.allocate(input_x[i], 0, i, column_type::public_input); - context_object.allocate(input_y[i], 0, i+num_chunks, column_type::public_input); + for (std::size_t i = 0; i < num_chunks; ++i) { + context_object.allocate(input_x[i], 0, i, + column_type::public_input); + context_object.allocate(input_y[i], 0, i + num_chunks, + column_type::public_input); } - return std::make_tuple(input_x,input_y); + return std::make_tuple(input_x, input_y); } - carry_on_addition(context_type &context_object, std::vector input_x,std::vector input_y, - std::size_t num_chunks, std::size_t bit_size_chunk, - bool make_links = true) + carry_on_addition(context_type &context_object, + std::vector input_x, + std::vector input_y, std::size_t num_chunks, + std::size_t bit_size_chunk, bool make_links = true) : generic_component(context_object) { using integral_type = typename FieldType::integral_type; - TYPE X[num_chunks], Y[num_chunks], C[num_chunks], Z[num_chunks]; + TYPE X[num_chunks], Y[num_chunks], C[num_chunks], R[num_chunks]; integral_type BASE = integral_type(1) << bit_size_chunk; if constexpr (stage == GenerationStage::ASSIGNMENT) { - for(std::size_t i = 0; i < num_chunks; i++) { + for (std::size_t i = 0; i < num_chunks; i++) { X[i] = input_x[i]; Y[i] = input_y[i]; } } - for(std::size_t i = 0; i < num_chunks; i++) { + for (std::size_t i = 0; i < num_chunks; i++) { allocate(X[i]); allocate(Y[i]); - if (make_links){ - copy_constrain(X[i],input_x[i]); - copy_constrain(Y[i],input_y[i]); + if (make_links) { + copy_constrain(X[i], input_x[i]); + copy_constrain(Y[i], input_y[i]); } - Z[i] = X[i] + Y[i]; + R[i] = X[i] + Y[i]; if (i > 0) { - Z[i] += C[i-1]; + R[i] += C[i - 1]; } if constexpr (stage == GenerationStage::ASSIGNMENT) { - C[i] = (Z[i] >= BASE); + C[i] = (R[i] >= BASE); } allocate(C[i]); - constrain(C[i]*(1-C[i])); + constrain(C[i] * (1 - C[i])); - Z[i] -= TYPE(BASE)*C[i]; - allocate(Z[i]); + R[i] -= TYPE(BASE) * C[i]; + allocate(R[i]); } for (int i = 0; i < num_chunks; ++i) { - inp_x.push_back(input_x[i]); - inp_y.push_back(input_y[i]); - res_r.push_back(Z[i]); + r.push_back(R[i]); } - res_c = C[num_chunks-1]; + c = C[num_chunks - 1]; } }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp index 319a86447..0fc746599 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp @@ -64,8 +64,7 @@ namespace nil { std::tuple<>>::type; public: - TYPE inp_q; - std::vector inp_x, inp_y, res_r; + std::vector r; static table_params get_minimal_requirements(std::size_t num_chunks) { std::size_t witness = num_chunks + 1; @@ -102,7 +101,7 @@ namespace nil { std::vector input_x, std::vector input_y, std::size_t num_chunks, bool make_links = true) : generic_component(context_object) { - TYPE Q, X[num_chunks], Y[num_chunks], Z[num_chunks]; + TYPE Q, X[num_chunks], Y[num_chunks], R[num_chunks]; if constexpr (stage == GenerationStage::ASSIGNMENT) { Q = input_q; @@ -117,8 +116,8 @@ namespace nil { for (std::size_t i = 0; i < num_chunks; i++) { allocate(X[i]); allocate(Y[i]); - Z[i] = (1 - Q) * X[i] + Q * Y[i]; - allocate(Z[i]); + R[i] = (1 - Q) * X[i] + Q * Y[i]; + allocate(R[i]); } if (make_links) { @@ -129,11 +128,8 @@ namespace nil { } } - inp_q = input_q; for (std::size_t i = 0; i < num_chunks; i++) { - inp_x.push_back(X[i]); - inp_y.push_back(Y[i]); - res_r.push_back(Z[i]); + r.push_back(R[i]); } }; }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/range_check_multi.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/range_check_multi.hpp index eb9eb06bf..2c65bc6e5 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/range_check_multi.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/range_check_multi.hpp @@ -22,7 +22,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //---------------------------------------------------------------------------// -// @file Declaration of interfaces for PLONK component wrapping the BBF-component interface +// @file Declaration of interfaces for PLONK component wrapping the BBF-component +// interface //---------------------------------------------------------------------------// #ifndef CRYPTO3_BBF_COMPONENTS_RANGE_CHECK_MULTI_HPP @@ -39,10 +40,10 @@ namespace nil { namespace blueprint { namespace bbf { namespace components { - // Constraints value to be of a certain bit size at most - // Parameters: num_chunks, bit_size_chunk - // Input: x - // Output: none + // Constraints value to be of a certain bit size at most + // Parameters: num_chunks, bit_size_chunk + // Input: x + // Output: none template struct range_check_multi_raw_input { @@ -69,41 +70,40 @@ namespace nil { static const std::size_t bit_size_rc = 16; public: - std::vector input; - - static table_params get_minimal_requirements(std::size_t num_chunks, - std::size_t bit_size_chunk) { - std::size_t num_rc_chunks = (bit_size_chunk / bit_size_rc) + (bit_size_chunk % bit_size_rc > 0); - std::size_t witness = (num_rc_chunks+1)/2 +1; + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::size_t num_rc_chunks = (bit_size_chunk / bit_size_rc) + + (bit_size_chunk % bit_size_rc > 0); + std::size_t witness = (num_rc_chunks + 1) / 2 + 1; constexpr std::size_t public_inputs = 1; constexpr std::size_t constants = 0; - // rows = 4096-1 so that lookup table is not too hard to fit and padding - // doesn't inflate the table + // rows = 4096-1 so that lookup table is not too hard to fit and + // padding doesn't inflate the table constexpr std::size_t rows = 4095; return {witness, public_inputs, constants, rows}; } - static std::tuple> form_input(context_type &context_object, - raw_input_type raw_input, - std::size_t num_chunks, - std::size_t bit_size_chunk) { + static std::tuple> form_input( + context_type &context_object, raw_input_type raw_input, + std::size_t num_chunks, std::size_t bit_size_chunk) { std::vector X(num_chunks); for (std::size_t i = 0; i < num_chunks; i++) { if constexpr (stage == GenerationStage::ASSIGNMENT) { X[i] = raw_input.state[i]; } - context_object.allocate(X[i], 0, i, column_type::public_input); + context_object.allocate(X[i], 0, i, + column_type::public_input); } return std::make_tuple(X); } - range_check_multi(context_type &context_object, std::vector input_x, - std::size_t num_chunks, std::size_t bit_size_chunk, - bool make_links = true) + range_check_multi(context_type &context_object, + std::vector input_x, std::size_t num_chunks, + std::size_t bit_size_chunk, bool make_links = true) : generic_component(context_object) { using integral_type = typename FieldType::integral_type; - std::size_t num_rc_chunks = - (bit_size_chunk / bit_size_rc) + (bit_size_chunk % bit_size_rc > 0); + std::size_t num_rc_chunks = (bit_size_chunk / bit_size_rc) + + (bit_size_chunk % bit_size_rc > 0); std::size_t first_chunk_size = bit_size_chunk % bit_size_rc; integral_type mask = (1 << bit_size_rc) - 1; @@ -125,9 +125,9 @@ namespace nil { } } } - + for (std::size_t i = 0; i < num_chunks; ++i) { - integral_type power = 1; + integral_type power = 1; allocate(X[i]); C[i] = X[i]; for (std::size_t j = 0; j < num_rc_chunks; ++j) { @@ -139,14 +139,16 @@ namespace nil { constrain(C[i]); if (first_chunk_size != 0) { - lookup(Y[i][num_rc_chunks - 1] *(integral_type(1) << (bit_size_rc - first_chunk_size)), "chunk_16_bits/full"); + lookup(Y[i][num_rc_chunks - 1] * + (integral_type(1) + << (bit_size_rc - first_chunk_size)), + "chunk_16_bits/full"); } if (make_links) { copy_constrain(X[i], input_x[i]); } - input.push_back(X[i]); - } + } } }; diff --git a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp index 55b093ccd..f1e1febda 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp @@ -40,7 +40,7 @@ using namespace nil; using namespace nil::blueprint; template + std::size_t bit_size_chunk> void test_ec_double( const std::vector& public_input) { using FieldType = BlueprintFieldType; @@ -49,35 +49,33 @@ void test_ec_double( using integral_type = typename BlueprintFieldType::integral_type; using non_native_integral_type = typename BlueprintFieldType::integral_type; - non_native_integral_type pow = 1; NON_NATIVE_TYPE xQ = 0, yQ = 0; for (std::size_t i = 0; i < num_chunks; ++i) { xQ += non_native_integral_type(integral_type(public_input[i].data)) * pow; - yQ += non_native_integral_type(integral_type(public_input[i + num_chunks].data)) * pow; + yQ += non_native_integral_type(integral_type(public_input[i + num_chunks].data)) * + pow; pow <<= bit_size_chunk; } - - NON_NATIVE_TYPE lambda = - (yQ == 0) - ? 0 - : 3 * xQ * xQ * - ((2 * yQ).inversed()), // if yQ = 0, lambda = 0 - z = (yQ == 0) ? 0 : yQ.inversed(), // if yQ = 0, z = 0 - expected_xR = lambda * lambda - 2 * xQ, expected_yR = lambda * (xQ - expected_xR) - yQ; - + NON_NATIVE_TYPE lambda = (yQ == 0) + ? 0 + : 3 * xQ * xQ * + ((2 * yQ).inversed()), // if yQ = 0, lambda = 0 + z = (yQ == 0) ? 0 : yQ.inversed(), // if yQ = 0, z = 0 + expected_xR = lambda * lambda - 2 * xQ, + expected_yR = lambda * (xQ - expected_xR) - yQ; auto assign_and_check = [&](auto& B, auto& raw_input) { raw_input.xQ = std::vector(public_input.begin(), public_input.begin() + num_chunks); - raw_input.yQ = - std::vector(public_input.begin() + num_chunks, public_input.begin() + 2 * num_chunks); + raw_input.yQ = std::vector(public_input.begin() + num_chunks, + public_input.begin() + 2 * num_chunks); raw_input.p = std::vector(public_input.begin() + 2 * num_chunks, - public_input.begin() + 3 * num_chunks); + public_input.begin() + 3 * num_chunks); raw_input.pp = std::vector(public_input.begin() + 3 * num_chunks, - public_input.begin() + 4 * num_chunks); + public_input.begin() + 4 * num_chunks); raw_input.zero = public_input[4 * num_chunks]; auto [at, A, desc] = B.assign(raw_input); @@ -89,50 +87,51 @@ void test_ec_double( non_native_integral_type yR = 0; pow = 1; for (std::size_t i = 0; i < num_chunks; i++) { - xR += non_native_integral_type(integral_type(A.res_xR[i].data)) * pow; - yR += non_native_integral_type(integral_type(A.res_yR[i].data)) * pow; + xR += non_native_integral_type(integral_type(A.xR[i].data)) * pow; + yR += non_native_integral_type(integral_type(A.yR[i].data)) * pow; pow <<= bit_size_chunk; } - //#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED - std::cout << "Expected xR - yR: " << std::dec << expected_xR.data << " - " << expected_yR.data << std::endl; + #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "Expected xR - yR: " << std::dec << expected_xR.data << " - " + << expected_yR.data << std::endl; std::cout << "Real res xR - yR: " << std::dec << xR << " - " << yR << std::endl; - //#endif + #endif assert(xR == expected_xR.data); assert(yR == expected_yR.data); - }; + }; if constexpr (std::is_same_v) { + crypto3::algebra::curves::pallas::base_field_type>) { typename bbf::components::pallas_ec_double< FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; auto B = bbf::circuit_builder(num_chunks, bit_size_chunk); + std::size_t, std::size_t>(num_chunks, bit_size_chunk); assign_and_check(B, raw_input); - } - else if constexpr (std::is_same_v< - NonNativeFieldType, - crypto3::algebra::curves::vesta::base_field_type>) { + } else if constexpr (std::is_same_v< + NonNativeFieldType, + crypto3::algebra::curves::vesta::base_field_type>) { typename bbf::components::vesta_ec_double< FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; auto B = - bbf::circuit_builder(num_chunks, bit_size_chunk); + bbf::circuit_builder(num_chunks, bit_size_chunk); assign_and_check(B, raw_input); } } template + std::size_t bit_size_chunk, std::size_t RandomTestsAmount> void ec_double_tests() { using NonNativeFieldType = typename Curve::base_field_type; using value_type = typename BlueprintFieldType::value_type; using integral_type = typename BlueprintFieldType::integral_type; using foreign_value_type = typename NonNativeFieldType::value_type; - using ec_point_value_type = typename Curve::template g1_type::value_type; + using ec_point_value_type = typename Curve::template g1_type< + nil::crypto3::algebra::curves::coordinates::affine>::value_type; typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> extended_integral_type; @@ -142,16 +141,14 @@ void ec_double_tests() { seed_seq); boost::random::uniform_int_distribution<> t_dist(0, 1); - extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input; extended_integral_type extended_base = 1, - ext_pow = extended_base << (num_chunks * bit_size_chunk), - p = NonNativeFieldType::modulus, - pp = ext_pow - p; + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus, pp = ext_pow - p; value_type d = generate_random(); ec_point_value_type Q = ec_point_value_type::one(); @@ -176,7 +173,7 @@ void ec_double_tests() { public_input.push_back(value_type(0)); // the zero test_ec_double(public_input); + bit_size_chunk>(public_input); } } @@ -185,20 +182,17 @@ constexpr static const std::size_t random_tests_amount = 10; BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_ec_double_test) { + // The curve is passed in as an argument to access additionnal properties using pallas = typename crypto3::algebra::curves::pallas; using vesta = typename crypto3::algebra::curves::vesta; - ec_double_tests(); + ec_double_tests(); ec_double_tests(); - ec_double_tests(); - - ec_double_tests(); + ec_double_tests(); + ec_double_tests(); } BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp index 7b727ab1a..4cb544617 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp @@ -40,7 +40,7 @@ using namespace nil; using namespace nil::blueprint; template + std::size_t bit_size_chunk> void test_ec_full_add( const std::vector& public_input) { using FieldType = BlueprintFieldType; @@ -49,75 +49,69 @@ void test_ec_full_add( using integral_type = typename BlueprintFieldType::integral_type; using non_native_integral_type = typename BlueprintFieldType::integral_type; - non_native_integral_type pow = 1; NON_NATIVE_TYPE xP = 0, yP = 0, xQ = 0, yQ = 0; for (std::size_t i = 0; i < num_chunks; ++i) { - xP += non_native_integral_type( - integral_type(public_input[i].data)) * - pow; - yP += non_native_integral_type( - integral_type(public_input[i + num_chunks].data)) * - pow; + xP += non_native_integral_type(integral_type(public_input[i].data)) * pow; + yP += non_native_integral_type(integral_type(public_input[i + num_chunks].data)) * + pow; xQ += non_native_integral_type( - integral_type(public_input[i + 2* num_chunks].data)) * - pow; + integral_type(public_input[i + 2 * num_chunks].data)) * + pow; yQ += non_native_integral_type( - integral_type(public_input[i + 3*num_chunks].data)) * - pow; + integral_type(public_input[i + 3 * num_chunks].data)) * + pow; pow <<= bit_size_chunk; } NON_NATIVE_TYPE - lambda, expected_xR, expected_yR, - // indicator variables - zP = (yP == 0)? 0 : yP.inversed(), - zQ = (yQ == 0)? 0 : yQ.inversed(), - zPQ= (xP == xQ)? 0 : (xP - xQ).inversed(), - wPQ= ((xP == xQ) && (yP + yQ != 0))? (yP + yQ).inversed() : 0; + lambda, expected_xR, expected_yR, + // indicator variables + zP = (yP == 0) ? 0 : yP.inversed(), zQ = (yQ == 0) ? 0 : yQ.inversed(), + zPQ = (xP == xQ) ? 0 : (xP - xQ).inversed(), + wPQ = ((xP == xQ) && (yP + yQ != 0)) ? (yP + yQ).inversed() : 0; if (yP == 0) { expected_xR = xQ; expected_yR = yQ; // lambda doesn't matter for (xR,yR), but needs to satisfy the constraints - lambda = (xP == xQ)? 0 : (yQ - yP)*((xQ - xP).inversed()); + lambda = (xP == xQ) ? 0 : (yQ - yP) * ((xQ - xP).inversed()); } else if (yQ == 0) { expected_xR = xP; expected_yR = yP; // lambda doesn't matter for (xR,yR), but needs to satisfy the constraints - lambda = (xP == xQ)? 0 : (yQ - yP)*((xQ - xP).inversed()); + lambda = (xP == xQ) ? 0 : (yQ - yP) * ((xQ - xP).inversed()); } else if ((xP == xQ) && (yP + yQ == 0)) { expected_xR = 0; expected_yR = 0; // lambda doesn't matter for (xR,yR), but needs to satisfy the constraints - lambda = 3*xP*xP*((2*yP).inversed()); + lambda = 3 * xP * xP * ((2 * yP).inversed()); } else { - if (xP == xQ) { // point doubling - lambda = 3*xP*xP*((2*yP).inversed()); - } else { // regular addition + if (xP == xQ) { // point doubling + lambda = 3 * xP * xP * ((2 * yP).inversed()); + } else { // regular addition NON_NATIVE_TYPE diff = xQ - xP; - lambda = (yQ - yP)*(diff.inversed()); + lambda = (yQ - yP) * (diff.inversed()); } - expected_xR = lambda*lambda - xP - xQ, - expected_yR = lambda*(xP - expected_xR) - yP; + expected_xR = lambda * lambda - xP - xQ, + expected_yR = lambda * (xP - expected_xR) - yP; } - auto assign_and_check = [&](auto& B, auto& raw_input) { raw_input.xP = std::vector(public_input.begin(), public_input.begin() + num_chunks); - raw_input.yP = - std::vector(public_input.begin() + num_chunks, public_input.begin() + 2 * num_chunks); - raw_input.xQ = - std::vector(public_input.begin() + 2*num_chunks, public_input.begin() + 3 * num_chunks); - raw_input.yQ = - std::vector(public_input.begin() + 3*num_chunks, public_input.begin() + 4 * num_chunks); + raw_input.yP = std::vector(public_input.begin() + num_chunks, + public_input.begin() + 2 * num_chunks); + raw_input.xQ = std::vector(public_input.begin() + 2 * num_chunks, + public_input.begin() + 3 * num_chunks); + raw_input.yQ = std::vector(public_input.begin() + 3 * num_chunks, + public_input.begin() + 4 * num_chunks); raw_input.p = std::vector(public_input.begin() + 4 * num_chunks, - public_input.begin() + 5 * num_chunks); + public_input.begin() + 5 * num_chunks); raw_input.pp = std::vector(public_input.begin() + 5 * num_chunks, - public_input.begin() + 6 * num_chunks); + public_input.begin() + 6 * num_chunks); raw_input.zero = public_input[6 * num_chunks]; auto [at, A, desc] = B.assign(raw_input); @@ -129,50 +123,51 @@ void test_ec_full_add( non_native_integral_type yR = 0; pow = 1; for (std::size_t i = 0; i < num_chunks; i++) { - xR += non_native_integral_type(integral_type(A.res_xR[i].data)) * pow; - yR += non_native_integral_type(integral_type(A.res_yR[i].data)) * pow; + xR += non_native_integral_type(integral_type(A.xR[i].data)) * pow; + yR += non_native_integral_type(integral_type(A.yR[i].data)) * pow; pow <<= bit_size_chunk; } - //#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED - std::cout << "Expected xR - yR: " << std::dec << expected_xR.data << " - " << expected_yR.data << std::endl; + #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "Expected xR - yR: " << std::dec << expected_xR.data << " - " + << expected_yR.data << std::endl; std::cout << "Real res xR - yR: " << std::dec << xR << " - " << yR << std::endl; - //#endif + #endif assert(xR == expected_xR.data); assert(yR == expected_yR.data); - }; + }; if constexpr (std::is_same_v) { + crypto3::algebra::curves::pallas::base_field_type>) { typename bbf::components::pallas_ec_full_add< FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; auto B = bbf::circuit_builder(num_chunks, bit_size_chunk); + std::size_t, std::size_t>(num_chunks, bit_size_chunk); assign_and_check(B, raw_input); - } - else if constexpr (std::is_same_v< - NonNativeFieldType, - crypto3::algebra::curves::vesta::base_field_type>) { + } else if constexpr (std::is_same_v< + NonNativeFieldType, + crypto3::algebra::curves::vesta::base_field_type>) { typename bbf::components::vesta_ec_full_add< FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; auto B = bbf::circuit_builder(num_chunks, bit_size_chunk); + std::size_t, std::size_t>(num_chunks, bit_size_chunk); assign_and_check(B, raw_input); } } template + std::size_t bit_size_chunk, std::size_t RandomTestsAmount> void ec_full_add_tests() { using NonNativeFieldType = typename Curve::base_field_type; using value_type = typename BlueprintFieldType::value_type; using integral_type = typename BlueprintFieldType::integral_type; using foreign_value_type = typename NonNativeFieldType::value_type; - using ec_point_value_type = typename Curve::template g1_type::value_type; + using ec_point_value_type = typename Curve::template g1_type< + nil::crypto3::algebra::curves::coordinates::affine>::value_type; typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> extended_integral_type; @@ -182,19 +177,18 @@ void ec_full_add_tests() { seed_seq); boost::random::uniform_int_distribution<> t_dist(0, 1); - extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input; extended_integral_type extended_base = 1, - ext_pow = extended_base << (num_chunks * bit_size_chunk), - p = NonNativeFieldType::modulus, - pp = ext_pow - p; + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus, pp = ext_pow - p; value_type d = generate_random(); - ec_point_value_type P = ec_point_value_type::one(), Q = ec_point_value_type::one(); + ec_point_value_type P = ec_point_value_type::one(), + Q = ec_point_value_type::one(); P = P * d; Q = Q * d; @@ -225,7 +219,7 @@ void ec_full_add_tests() { public_input.push_back(value_type(0)); // the zero test_ec_full_add(public_input); + bit_size_chunk>(public_input); } } @@ -234,20 +228,17 @@ constexpr static const std::size_t random_tests_amount = 10; BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_ec_full_add_test) { + // The curve is passed in as an argument to access additionnal properties using pallas = typename crypto3::algebra::curves::pallas; using vesta = typename crypto3::algebra::curves::vesta; - ec_full_add_tests(); + ec_full_add_tests(); ec_full_add_tests(); - ec_full_add_tests(); - - ec_full_add_tests(); + ec_full_add_tests(); + ec_full_add_tests(); } BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp index 11e3742e1..14a45df05 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp @@ -94,8 +94,8 @@ void test_ec_incomplete_add( non_native_integral_type yR = 0; pow = 1; for (std::size_t i = 0; i < num_chunks; i++) { - xR += non_native_integral_type(integral_type(A.res_xR[i].data)) * pow; - yR += non_native_integral_type(integral_type(A.res_yR[i].data)) * pow; + xR += non_native_integral_type(integral_type(A.xR[i].data)) * pow; + yR += non_native_integral_type(integral_type(A.yR[i].data)) * pow; pow <<= bit_size_chunk; } // #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED @@ -199,6 +199,7 @@ constexpr static const std::size_t random_tests_amount = 10; BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_ec_incomplete_add_test) { + // The curve is passed in as an argument to access additionnal properties using pallas = typename crypto3::algebra::curves::pallas; using vesta = typename crypto3::algebra::curves::vesta; diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp index 2963351b5..8b8e7d98b 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp @@ -26,24 +26,21 @@ #define BOOST_TEST_MODULE bbf_addition_mod_p_test #include +#include +#include #include #include -#include - -#include - -#include -#include -#include #include +#include +#include using namespace nil; using namespace nil::blueprint; - template -void test_addition_mod_p(const std::vector &public_input) { +void test_addition_mod_p( + const std::vector &public_input) { using FieldType = BlueprintFieldType; using TYPE = typename FieldType::value_type; using integral_type = typename BlueprintFieldType::integral_type; @@ -54,12 +51,11 @@ void test_addition_mod_p(const std::vector= p) { r -= p; } - + auto assign_and_check = [&](auto &B, auto &raw_input) { raw_input.x = std::vector(public_input.begin(), public_input.begin() + num_chunks); @@ -77,7 +73,8 @@ void test_addition_mod_p(const std::vector(public_input.begin() + 3 * num_chunks, public_input.begin() + 4 * num_chunks); - raw_input.zero = public_input[4 * num_chunks]; + raw_input.zero = std::vector(public_input.begin() + 4 * num_chunks, + public_input.begin() + 5 * num_chunks); auto [at, A, desc] = B.assign(raw_input); bool pass = B.is_satisfied(at); @@ -87,7 +84,7 @@ void test_addition_mod_p(const std::vector::raw_input_type raw_input; auto B = - bbf::circuit_builder(num_chunks, bit_size_chunk); assign_and_check(B, raw_input); @@ -116,16 +111,15 @@ void test_addition_mod_p(const std::vector::raw_input_type raw_input; auto B = - bbf::circuit_builder(num_chunks, bit_size_chunk); assign_and_check(B, raw_input); } } - -template +template void addition_mod_p_tests() { using value_type = typename BlueprintFieldType::value_type; using integral_type = typename BlueprintFieldType::integral_type; @@ -137,25 +131,21 @@ void addition_mod_p_tests() { static nil::crypto3::random::algebraic_engine generate_random( seed_seq); boost::random::uniform_int_distribution<> t_dist(0, 1); - extended_integral_type mask = - (extended_integral_type(1) << bit_size_chunk) - 1; + extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input; foreign_value_type src_x = generate_random(), src_y = generate_random(); - extended_integral_type x = extended_integral_type( - integral_type(src_x.data)), - y = extended_integral_type( - integral_type(src_y.data)), - extended_base = 1, - ext_pow = extended_base - << (num_chunks * bit_size_chunk), - p = NonNativeFieldType::modulus; + extended_integral_type x = extended_integral_type(integral_type(src_x.data)), + y = extended_integral_type(integral_type(src_y.data)), + extended_base = 1, + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus; extended_integral_type pp = ext_pow - p; - public_input.resize(4 * num_chunks + 1); + public_input.resize(5 * num_chunks); for (std::size_t j = 0; j < num_chunks; j++) { public_input[j] = value_type(x & mask); x >>= bit_size_chunk; @@ -168,10 +158,12 @@ void addition_mod_p_tests() { public_input[3 * num_chunks + j] = value_type(pp & mask); pp >>= bit_size_chunk; + + public_input[4 * num_chunks + j] = value_type(0); } - public_input.push_back(value_type(0)); // the zero - test_addition_mod_p(public_input); + test_addition_mod_p(public_input); } } @@ -183,17 +175,23 @@ BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_addition_mod_p_test) { using pallas_field_type = typename crypto3::algebra::curves::pallas::base_field_type; using vesta_field_type = typename crypto3::algebra::curves::vesta::base_field_type; - addition_mod_p_tests(); + addition_mod_p_tests(); - addition_mod_p_tests(); + addition_mod_p_tests(); - addition_mod_p_tests(); + addition_mod_p_tests(); - addition_mod_p_tests(); + addition_mod_p_tests(); - addition_mod_p_tests(); + addition_mod_p_tests(); - addition_mod_p_tests(); + addition_mod_p_tests(); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/check_mod_p.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/check_mod_p.cpp index 6824d4b8f..f4069095d 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/check_mod_p.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/check_mod_p.cpp @@ -26,79 +26,84 @@ #define BOOST_TEST_MODULE bbf_check_mod_p_test #include +#include +#include #include #include -#include - -#include - -#include -#include -#include #include +#include +#include using namespace nil; using namespace nil::blueprint; - -template -void test_mod_p_check(const std::vector &public_input){ - +template +void test_mod_p_check( + const std::vector &public_input) { using FieldType = BlueprintFieldType; using TYPE = typename FieldType::value_type; - typename bbf::components::check_mod_p::raw_input_type raw_input; - raw_input.x = std::vector(public_input.begin(), public_input.begin() + num_chunks); - raw_input.pp = std::vector(public_input.begin() + num_chunks, public_input.begin() + 2 * num_chunks); + typename bbf::components::check_mod_p< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + raw_input.x = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.pp = std::vector(public_input.begin() + num_chunks, + public_input.begin() + 2 * num_chunks); raw_input.zero = TYPE(0); - auto B = bbf::circuit_builder(num_chunks,bit_size_chunk,expect_output); + auto B = bbf::circuit_builder(num_chunks, bit_size_chunk, + expect_output); auto [at, A, desc] = B.assign(raw_input); bool pass = B.is_satisfied(at); std::cout << "Is_satisfied = " << pass << std::endl; assert(pass == to_pass); - - if (to_pass && expect_output) { - #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED - std::cout << "Expected output: " << std::dec << overflow << std::endl; - std::cout << "Real output: " << std::dec << A.output.data << std::endl; - #endif - assert(overflow == A.output.data); - } + if (to_pass && expect_output) { +#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "Expected output: " << std::dec << overflow << std::endl; + std::cout << "Real output: " << std::dec << A.output.data << std::endl; +#endif + assert(overflow == A.output.data); + } } - -template +template void mod_p_check_tests() { using integral_type = typename BlueprintFieldType::integral_type; using value_type = typename BlueprintFieldType::value_type; static boost::random::mt19937 seed_seq; - static nil::crypto3::random::algebraic_engine generate_random(seed_seq); + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); boost::random::uniform_int_distribution<> t_dist(0, 1); const integral_type B = integral_type(1) << bit_size_chunk; for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input; integral_type p = integral_type(generate_random().data); - p = (p == 0) ? 1 : p; // avoid p == 0 + p = (p == 0) ? 1 : p; // avoid p == 0 - integral_type x = overflow ? p + 1:(integral_type(generate_random().data) % p); + integral_type x = overflow ? p + 1 : (integral_type(generate_random().data) % p); - for(std::size_t j = 0; j < num_chunks; j++) { // the x's + for (std::size_t j = 0; j < num_chunks; j++) { // the x's public_input.push_back(value_type(x % B)); x /= B; } - for(std::size_t j = 0; j < num_chunks; j++) { // the pp's - public_input.push_back(value_type(B - (j > 0) - (p % B))); // these are B-base digits of (2^{kb} - p) + for (std::size_t j = 0; j < num_chunks; j++) { // the pp's + public_input.push_back(value_type( + B - (j > 0) - (p % B))); // these are B-base digits of (2^{kb} - p) p /= B; } - //Test with output, should always succeed - test_mod_p_check(public_input); + // Test with output, should always succeed + test_mod_p_check(public_input); - //Test without output, should fail when there is an overflow - test_mod_p_check(public_input); + // Test without output, should fail when there is an overflow + test_mod_p_check(public_input); } } @@ -123,13 +128,13 @@ BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_check_mod_p_test_overflow) { using pallas_field_type = typename crypto3::algebra::curves::pallas::base_field_type; using vesta_field_type = typename crypto3::algebra::curves::vesta::base_field_type; - mod_p_check_tests(); - mod_p_check_tests(); - mod_p_check_tests(); + mod_p_check_tests(); + mod_p_check_tests(); + mod_p_check_tests(); - mod_p_check_tests(); - mod_p_check_tests(); - mod_p_check_tests(); + mod_p_check_tests(); + mod_p_check_tests(); + mod_p_check_tests(); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp index 01c127607..d4a7ee487 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp @@ -26,25 +26,14 @@ #define BOOST_TEST_MODULE bbf_flexible_multiplication_test -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - #include +#include #include #include #include - -#include +#include +#include +#include using namespace nil; using namespace nil::blueprint; @@ -63,12 +52,11 @@ void test_mult(const std::vector &publi // Populate x, y, p for (std::size_t i = 0; i < num_chunks; ++i) { x += extended_integral_type(integral_type(public_input[i].data)) * pow; - y += extended_integral_type( - integral_type(public_input[i + num_chunks].data)) * - pow; - p += extended_integral_type( - integral_type(public_input[i + 2 * num_chunks].data)) * + y += extended_integral_type(integral_type(public_input[i + num_chunks].data)) * pow; + p += + extended_integral_type(integral_type(public_input[i + 2 * num_chunks].data)) * + pow; pow <<= bit_size_chunk; } @@ -83,7 +71,7 @@ void test_mult(const std::vector &publi public_input.begin() + 3 * num_chunks); raw_input.pp = std::vector(public_input.begin() + 3 * num_chunks, public_input.begin() + 4 * num_chunks); - raw_input.zero = public_input.back(); + raw_input.zero = public_input[4 * num_chunks]; auto [at, A, desc] = B.assign(raw_input); bool pass = B.is_satisfied(at); @@ -96,7 +84,7 @@ void test_mult(const std::vector &publi extended_integral_type R = 0; pow = 1; for (std::size_t i = 0; i < num_chunks; i++) { - R += extended_integral_type(integral_type(A.res_r[i].data)) * pow; + R += extended_integral_type(integral_type(A.r[i].data)) * pow; pow <<= bit_size_chunk; } #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED @@ -147,27 +135,21 @@ void mult_tests() { static nil::crypto3::random::algebraic_engine generate_random( seed_seq); boost::random::uniform_int_distribution<> t_dist(0, 1); - extended_integral_type mask = - (extended_integral_type(1) << bit_size_chunk) - 1; + extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input; foreign_value_type src_x = generate_random(), src_y = generate_random(); - extended_integral_type x = extended_integral_type( - integral_type(src_x.data)), - y = extended_integral_type( - integral_type(src_y.data)), - extended_base = 1, - ext_pow = extended_base - << (num_chunks * bit_size_chunk), - p = NonNativeFieldType::modulus, pp = ext_pow - p; - - public_input.resize(4 * num_chunks + 1); // public_input should contain x,y,p,pp,zero - // std::cout << "PI x = " << x << std::endl; - // std::cout << "PI y = " << y << std::endl; - // std::cout << "PI p = " << p << std::endl; + extended_integral_type x = extended_integral_type(integral_type(src_x.data)), + y = extended_integral_type(integral_type(src_y.data)), + extended_base = 1, + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus, pp = ext_pow - p; + + public_input.resize(5 * num_chunks); + // public_input should contain x,y,p,pp,zero for (std::size_t j = 0; j < num_chunks; j++) { public_input[j] = value_type(x & mask); x >>= bit_size_chunk; @@ -180,8 +162,9 @@ void mult_tests() { public_input[3 * num_chunks + j] = value_type(pp & mask); pp >>= bit_size_chunk; + + public_input[4 * num_chunks + j] = value_type(0); } - public_input[4*num_chunks] = value_type(0); test_mult( public_input); @@ -202,23 +185,22 @@ void mult_tests_to_fail() { static nil::crypto3::random::algebraic_engine generate_random( seed_seq); boost::random::uniform_int_distribution<> t_dist(0, 1); - extended_integral_type mask = - (extended_integral_type(1) << bit_size_chunk) - 1; + extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input; foreign_value_type src_x = generate_random(), src_y = generate_random(); - extended_integral_type - x = extended_integral_type(integral_type(src_x.data)), - y = extended_integral_type(integral_type(src_y.data)), - extended_base = 1, ext_pow = extended_base << (num_chunks * bit_size_chunk), - p = NonNativeFieldType::modulus, - // Forcing the test to fail by substracting pp by 1 + extended_integral_type x = extended_integral_type(integral_type(src_x.data)), + y = extended_integral_type(integral_type(src_y.data)), + extended_base = 1, + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus, + // Forcing the test to fail by substracting pp by 1 pp = ext_pow - p - 1; - public_input.resize(4 * num_chunks); + public_input.resize(4 * num_chunks + 1); for (std::size_t j = 0; j < num_chunks; j++) { public_input[j] = value_type(x & mask); x >>= (bit_size_chunk); diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp index 8d367c582..93a74031a 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp @@ -26,15 +26,12 @@ #define BOOST_TEST_MODULE bbf_negation_mod_p_test #include +#include #include #include #include - -#include - #include #include -#include #include using namespace nil; @@ -68,7 +65,8 @@ void test_negation_mod_p( public_input.begin() + 2 * num_chunks); raw_input.pp = std::vector(public_input.begin() + 2 * num_chunks, public_input.begin() + 3 * num_chunks); - raw_input.zero = public_input[3 * num_chunks]; + raw_input.zero = std::vector(public_input.begin() + 3 * num_chunks, + public_input.begin() + 4 * num_chunks); auto [at, A, desc] = B.assign(raw_input); bool pass = B.is_satisfied(at); @@ -78,7 +76,7 @@ void test_negation_mod_p( extended_integral_type R = 0; pow = 1; for (std::size_t i = 0; i < num_chunks; i++) { - R += extended_integral_type(integral_type(A.res_r[i].data)) * pow; + R += extended_integral_type(integral_type(A.r[i].data)) * pow; pow <<= bit_size_chunk; } #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED @@ -138,7 +136,7 @@ void negation_mod_p_tests() { p = NonNativeFieldType::modulus; extended_integral_type pp = ext_pow - p; - public_input.resize(3 * num_chunks + 1); + public_input.resize(4 * num_chunks); for (std::size_t j = 0; j < num_chunks; j++) { public_input[j] = value_type(x & mask); x >>= bit_size_chunk; @@ -148,8 +146,9 @@ void negation_mod_p_tests() { public_input[2 * num_chunks + j] = value_type(pp & mask); pp >>= bit_size_chunk; + + public_input[3 * num_chunks + j] = value_type(0); // the zeros } - public_input.push_back(value_type(0)); // the zero test_negation_mod_p(public_input); diff --git a/crypto3/libs/blueprint/test/bbf/detail/carry_on_addition.cpp b/crypto3/libs/blueprint/test/bbf/detail/carry_on_addition.cpp index 939de6cde..9ecdb9e4e 100644 --- a/crypto3/libs/blueprint/test/bbf/detail/carry_on_addition.cpp +++ b/crypto3/libs/blueprint/test/bbf/detail/carry_on_addition.cpp @@ -26,74 +26,79 @@ #define BOOST_TEST_MODULE carry_on_addition_test #include -#include +#include +#include #include #include -#include - -#include - -#include -#include -#include #include +#include +#include using namespace nil; using namespace nil::blueprint; -template -void test_carry_on_addition(const std::vector &public_input){ +template +void test_carry_on_addition( + const std::vector &public_input) { using FieldType = BlueprintFieldType; using integral_type = typename FieldType::integral_type; using TYPE = typename FieldType::value_type; - typename bbf::components::carry_on_addition::raw_input_type raw_input; - raw_input.x = std::vector(public_input.begin(), public_input.begin() + num_chunks); - raw_input.y = std::vector(public_input.begin() + num_chunks, public_input.end()); - auto B = bbf::circuit_builder(num_chunks,bit_size_chunk); + typename bbf::components::carry_on_addition< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + raw_input.x = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.y = + std::vector(public_input.begin() + num_chunks, public_input.end()); + auto B = bbf::circuit_builder(num_chunks, bit_size_chunk); auto [at, A, desc] = B.assign(raw_input); bool pass = B.is_satisfied(at); std::cout << "Is_satisfied = " << pass << std::endl; assert(pass == true); - integral_type BASE = integral_type(1) << bit_size_chunk; // the representation base + integral_type BASE = integral_type(1) << bit_size_chunk; // the representation base TYPE expected_res[num_chunks], carry[num_chunks]; - for(std::size_t i = 0; i < num_chunks; i++) { + for (std::size_t i = 0; i < num_chunks; i++) { expected_res[i] = public_input[i] + public_input[num_chunks + i]; if (i > 0) { - expected_res[i] += carry[i-1]; + expected_res[i] += carry[i - 1]; } carry[i] = (expected_res[i] >= BASE); - expected_res[i] -= carry[i]*BASE; + expected_res[i] -= carry[i] * BASE; } std::cout << "Carry on addition test" << std::endl; - for(std::size_t i = 0; i < num_chunks; i++) { - #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + for (std::size_t i = 0; i < num_chunks; i++) { +#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED std::cout << "Expected res: " << std::dec << expected_res[i] << std::endl; - std::cout << "Real res: " << std::dec << A.res_r[i].data << std::endl; - #endif - assert(A.res_r[i].data == expected_res[i].data); + std::cout << "Real res: " << std::dec << A.r[i].data << std::endl; +#endif + assert(A.r[i].data == expected_res[i].data); } - assert(carry[num_chunks-1] == A.res_c.data); + assert(carry[num_chunks - 1] == A.c.data); } -template +template void carry_on_addition_tests() { using integral_type = typename BlueprintFieldType::integral_type; using value_type = typename BlueprintFieldType::value_type; integral_type chunk_size = (integral_type(1) << bit_size_chunk); static boost::random::mt19937 seed_seq; - static nil::crypto3::random::algebraic_engine generate_random(seed_seq); + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input = {}; - for(std::size_t j = 0; j < 2*num_chunks; j++) { - public_input.push_back(value_type(integral_type(generate_random().data) % chunk_size)); + for (std::size_t j = 0; j < 2 * num_chunks; j++) { + public_input.push_back( + value_type(integral_type(generate_random().data) % chunk_size)); } - test_carry_on_addition(public_input); + test_carry_on_addition( + public_input); } } @@ -145,4 +150,4 @@ BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_carry_on_addition_pallas_test) { carry_on_addition_tests(); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/detail/choice_function.cpp b/crypto3/libs/blueprint/test/bbf/detail/choice_function.cpp index 5939a0084..d08e6823a 100644 --- a/crypto3/libs/blueprint/test/bbf/detail/choice_function.cpp +++ b/crypto3/libs/blueprint/test/bbf/detail/choice_function.cpp @@ -26,16 +26,13 @@ #define BOOST_TEST_MODULE choice_function_test #include +#include #include #include #include #include - -#include - #include #include -#include #include using namespace nil; @@ -74,9 +71,9 @@ void test_choice_function( for (std::size_t i = 0; i < num_chunks; i++) { #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED std::cout << "Expected res: " << std::dec << expected_res[i] << std::endl; - std::cout << "Real res: " << std::dec << A.res_r[i].data << std::endl; + std::cout << "Real res: " << std::dec << A.r[i].data << std::endl; #endif - assert(A.res_r[i].data == expected_res[i].data); + assert(A.r[i].data == expected_res[i].data); } } diff --git a/crypto3/libs/blueprint/test/bbf/detail/range_check_multi.cpp b/crypto3/libs/blueprint/test/bbf/detail/range_check_multi.cpp index 86f78b0ae..695d3421b 100644 --- a/crypto3/libs/blueprint/test/bbf/detail/range_check_multi.cpp +++ b/crypto3/libs/blueprint/test/bbf/detail/range_check_multi.cpp @@ -26,29 +26,27 @@ #define BOOST_TEST_MODULE bbf_range_check_multi_test #include -#include +#include +#include #include #include -#include - -#include - -#include -#include -#include #include +#include +#include using namespace nil; using namespace nil::blueprint; - -template -void test_range_check(const std::vector &public_input){ - +template +void test_range_check( + const std::vector &public_input) { using FieldType = BlueprintFieldType; - typename bbf::components::range_check_multi::raw_input_type raw_input; + typename bbf::components::range_check_multi< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; raw_input.state = public_input; - auto B = bbf::circuit_builder(num_chunks,bit_size_chunk); + auto B = bbf::circuit_builder(num_chunks, bit_size_chunk); auto [at, A, desc] = B.assign(raw_input); bool pass = B.is_satisfied(at); std::cout << "Is_satisfied = " << pass << std::endl; @@ -56,45 +54,52 @@ void test_range_check(const std::vector assert(pass == to_pass); } - -template +template void range_check_tests() { using integral_type = typename BlueprintFieldType::integral_type; using value_type = typename BlueprintFieldType::value_type; static boost::random::mt19937 seed_seq; - static nil::crypto3::random::algebraic_engine generate_random(seed_seq); + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); boost::random::uniform_int_distribution<> t_dist(0, 1); integral_type mask = (integral_type(1) << bit_size_chunk) - 1; for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input; for (std::size_t j = 0; j < num_chunks; j++) { - public_input.push_back(value_type(integral_type(generate_random().data) & mask)); + public_input.push_back( + value_type(integral_type(generate_random().data) & mask)); } - test_range_check(public_input); + test_range_check(public_input); } } -template +template void range_check_tests_to_fail() { using integral_type = typename BlueprintFieldType::integral_type; using value_type = typename BlueprintFieldType::value_type; static boost::random::mt19937 seed_seq; - static nil::crypto3::random::algebraic_engine generate_random(seed_seq); + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); boost::random::uniform_int_distribution<> t_dist(0, 1); integral_type mask = (integral_type(1) << bit_size_chunk) - 1; for (std::size_t i = 0; i < RandomTestsAmount; i++) { integral_type most_significant_bit = integral_type(1) << (bit_size_chunk); std::vector public_input; - //Adding a faulty bits - public_input.push_back(value_type(integral_type(generate_random().data) & mask | most_significant_bit)); + // Adding a faulty bits + public_input.push_back(value_type(integral_type(generate_random().data) & mask | + most_significant_bit)); for (std::size_t j = 1; j < num_chunks; j++) { - public_input.push_back(value_type(integral_type(generate_random().data) & mask)); + public_input.push_back( + value_type(integral_type(generate_random().data) & mask)); } - test_range_check(public_input); + test_range_check( + public_input); } } @@ -106,7 +111,6 @@ BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_range_check_multi_test) { using pallas_field_type = typename crypto3::algebra::curves::pallas::base_field_type; using vesta_field_type = typename crypto3::algebra::curves::vesta::base_field_type; - range_check_tests(); range_check_tests(); range_check_tests(); @@ -129,4 +133,4 @@ BOOST_AUTO_TEST_CASE(blueprint_plonk_field_operations_test_to_fail) { range_check_tests_to_fail(); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END() From 331cae78af80aaf5aefacb90f1270bf89daee0df Mon Sep 17 00:00:00 2001 From: Antoine Cyr Date: Wed, 29 Jan 2025 10:58:13 -0500 Subject: [PATCH 14/14] ec arithmetic input_zero vector --- .../algebra/curves/weierstrass/ec_double.hpp | 22 +++++------ .../curves/weierstrass/ec_full_add.hpp | 38 ++++++++----------- .../curves/weierstrass/ec_incomplete_add.hpp | 24 ++++++------ .../algebra/curves/weierstrass/ec_double.cpp | 8 ++-- .../curves/weierstrass/ec_full_add.cpp | 8 ++-- .../curves/weierstrass/ec_incomplete_add.cpp | 8 ++-- 6 files changed, 55 insertions(+), 53 deletions(-) diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp index a292dd15e..62f60e6f2 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp @@ -56,8 +56,8 @@ namespace nil { // Expects input as k-chunked values with b bits per chunk // p' = 2^(kb) - p // Input: xQ[0],...,xQ[k-1], yQ[0],...,yQ[k-1], p[0],...,p[k-1], - // pp[0],...,pp[k-1], 0 - // (expects zero constant as input) + // pp[0],...,pp[k-1], 0[0], ..., 0[k-1] + // (expects zero vector constant as input) // Output: xR[0],...,xR[k-1], yR[0],...,yR[k-1] template @@ -67,7 +67,7 @@ namespace nil { std::vector yQ; std::vector p; std::vector pp; - TYPE zero; + std::vector zero; }; template, std::vector, - std::vector, std::vector, TYPE> + std::vector, std::vector, std::vector> form_input(context_type& context_object, raw_input_type raw_input, std::size_t num_chunks, std::size_t bit_size_chunk) { std::vector input_xQ(num_chunks); std::vector input_yQ(num_chunks); std::vector input_p(num_chunks); std::vector input_pp(num_chunks); - TYPE input_zero; + std::vector input_zero(num_chunks); if constexpr (stage == GenerationStage::ASSIGNMENT) { for (std::size_t i = 0; i < num_chunks; i++) { @@ -119,8 +119,8 @@ namespace nil { input_yQ[i] = raw_input.yQ[i]; input_p[i] = raw_input.p[i]; input_pp[i] = raw_input.pp[i]; + input_zero[i] = raw_input.zero[i]; } - input_zero = raw_input.zero; } for (std::size_t i = 0; i < num_chunks; i++) { context_object.allocate(input_xQ[i], 0, i, @@ -131,16 +131,16 @@ namespace nil { column_type::public_input); context_object.allocate(input_pp[i], 0, i + 3 * num_chunks, column_type::public_input); + context_object.allocate(input_zero[i], 0, i + 4 * num_chunks, + column_type::public_input); } - context_object.allocate(input_zero, 0, 4 * num_chunks, - column_type::public_input); return std::make_tuple(input_xQ, input_yQ, input_p, input_pp, input_zero); } ec_double(context_type& context_object, std::vector input_xQ, std::vector input_yQ, std::vector input_p, - std::vector input_pp, TYPE input_zero, + std::vector input_pp, std::vector input_zero, std::size_t num_chunks, std::size_t bit_size_chunk, bool make_links = true) : generic_component(context_object) { @@ -224,7 +224,7 @@ namespace nil { input_pp, input_zero](std::vector x) { Range_Check rc = Range_Check(context_object, x, num_chunks, bit_size_chunk); - Check_Mod_P cm = Check_Mod_P(context_object, x, input_pp, input_zero, + Check_Mod_P cm = Check_Mod_P(context_object, x, input_pp, input_zero[0], num_chunks, bit_size_chunk); }; @@ -246,7 +246,7 @@ namespace nil { bit_size_chunk](std::vector x, std::vector y) { Multiplication_Mod_P t = - Multiplication_Mod_P(context_object, x, y, input_p, input_pp, input_zero, + Multiplication_Mod_P(context_object, x, y, input_p, input_pp, input_zero[0], num_chunks, bit_size_chunk); return t.r; }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp index b322a8527..7c6bd649d 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp @@ -57,8 +57,9 @@ namespace nil { // Expects input as k-chunked values with b bits per chunk // p' = 2^(kb) - p // Input: xP[0],...,xP[k-1],yP[0],...,yP[k-1],xQ[0],...,xQ[k-1], - // yQ[0],...,yQ[k-1], p[0], ..., p[k-1], pp[0], ..., pp[k-1], 0 - // (expects zero constant as input) + // yQ[0],...,yQ[k-1], p[0], ..., p[k-1], pp[0], ..., pp[k-1], + // 0[0], ..., 0[k-1] + // (expects zero vector constant as input) // Output: xR[0],...,xR[k-1], // yR[0],...,yR[k-1] // @@ -71,7 +72,7 @@ namespace nil { std::vector yP; std::vector p; std::vector pp; - TYPE zero; + std::vector zero; }; template, std::vector, std::vector, std::vector, - std::vector, std::vector, TYPE> + std::vector, std::vector, std::vector> form_input(context_type& context_object, raw_input_type raw_input, std::size_t num_chunks, std::size_t bit_size_chunk) { std::vector input_xP(num_chunks); @@ -118,7 +119,7 @@ namespace nil { std::vector input_yQ(num_chunks); std::vector input_p(num_chunks); std::vector input_pp(num_chunks); - TYPE input_zero; + std::vector input_zero(num_chunks); if constexpr (stage == GenerationStage::ASSIGNMENT) { for (std::size_t i = 0; i < num_chunks; i++) { @@ -128,8 +129,8 @@ namespace nil { input_yQ[i] = raw_input.yQ[i]; input_p[i] = raw_input.p[i]; input_pp[i] = raw_input.pp[i]; + input_zero[i] = raw_input.zero[i]; } - input_zero = raw_input.zero; } for (std::size_t i = 0; i < num_chunks; i++) { context_object.allocate(input_xP[i], 0, i, @@ -144,9 +145,9 @@ namespace nil { column_type::public_input); context_object.allocate(input_pp[i], 0, i + 5 * num_chunks, column_type::public_input); - } - context_object.allocate(input_zero, 0, 6 * num_chunks, + context_object.allocate(input_zero[i], 0, i + 6 * num_chunks, column_type::public_input); + } return std::make_tuple(input_xP, input_yP, input_xQ, input_yQ, input_p, input_pp, input_zero); } @@ -154,7 +155,7 @@ namespace nil { ec_full_add(context_type& context_object, std::vector input_xP, std::vector input_yP, std::vector input_xQ, std::vector input_yQ, std::vector input_p, - std::vector input_pp, TYPE input_zero, + std::vector input_pp, std::vector input_zero, std::size_t num_chunks, std::size_t bit_size_chunk, bool make_links = true) : generic_component(context_object) { @@ -283,7 +284,7 @@ namespace nil { Range_Check rc = Range_Check(context_object, x, num_chunks, bit_size_chunk); Check_Mod_P cm = - Check_Mod_P(context_object, x, input_pp, input_zero, + Check_Mod_P(context_object, x, input_pp, input_zero[0], num_chunks, bit_size_chunk); }; @@ -295,13 +296,6 @@ namespace nil { } }; - auto CopyConstrainZero = - [this, num_chunks, input_zero](std::vector x) mutable { - for (std::size_t i = 0; i < num_chunks; i++) { - copy_constrain(x[i], input_zero); - } - }; - // perform range checks and mod p checks on all stored variables check_chunked(LAMBDA); check_chunked(XR); @@ -315,7 +309,7 @@ namespace nil { num_chunks, bit_size_chunk]( std::vector x, std::vector y) { Multiplication_Mod_P t = Multiplication_Mod_P( - context_object, x, y, input_p, input_pp, input_zero, + context_object, x, y, input_p, input_pp, input_zero[0], num_chunks, bit_size_chunk); return t.r; }; @@ -384,16 +378,16 @@ namespace nil { auto t35 = MultModP(t7, LAMBDA); // t35 = (xR - xP) lambda auto t36 = AddModP(t34, t35); // t36 = yR + yP + (xR - xP)lambda auto t37 = MultModP(t28, t33); // t37 = yP yQ (xP - xQ + (yP + yQ)(1 - ZPQ))(xR - lambda^2 + xP + xQ) - CopyConstrainZero(t37); // t37 = 0 + CopyConstrain(t37, input_zero); // t37 = 0 auto t38 = MultModP(t28, t36); // t38 = yP yQ (xP - xQ + (yP + yQ)(1 -ZPQ))(yR + yP + (xR - xP)lambda) - CopyConstrainZero(t38); // t38 = 0 + CopyConstrain(t38, input_zero); // t38 = 0 // part 4 auto t39 = MultModP(t9, LAMBDA); // t39 = (xP - xQ) lambda auto t40 = AddModP(t39, t4); // t40 = (xP - xQ) lambda - yP auto t41 = AddModP(t40, input_yQ); // t41 = (xP - xQ) lambda - yP + yQ auto t42 = MultModP(t9, t41); // t42 = (xP - xQ)((xP - xQ) lambda - yP + yQ) - CopyConstrainZero(t42); // t42 = 0 + CopyConstrain(t42, input_zero); // t42 = 0 auto t43 = MultModP(input_xP, t3); // t43 = -xP^2 auto t44 = AddModP(t43, t43); // t44 = -2xP^2 auto t45 = AddModP(t43, t44); // t45 = -3xP^2 @@ -401,7 +395,7 @@ namespace nil { auto t47 = MultModP(t46, LAMBDA); // t47 = 2yP lambda auto t48 = AddModP(t47, t45); // t48 = 2yP lambda - 3xP^2 auto t49 = MultModP(t48, t12); // t49 = (2yP lambda - 3xP^2) ZPQ - CopyConstrain(t48, t49); // t48 = t49 + CopyConstrain(t48, t49); // t48 = t49 for (int i = 0; i < num_chunks; ++i) { xR.push_back(XR[i]); diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp index 6f7023ad9..658140450 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp @@ -57,8 +57,9 @@ namespace nil { // Expects input as k-chunked values with b bits per chunk // p' = 2^(kb) - p // Input: xP[0],...,xP[k-1],yP[0],...,yP[k-1],xQ[0],...,xQ[k-1], - // yQ[0],...,yQ[k-1], p[0], ..., p[k-1], pp[0], ..., pp[k-1], 0 - // (expects zero constant as input) + // yQ[0],...,yQ[k-1], p[0], ..., p[k-1], pp[0], ..., pp[k-1], + // 0[0], ..., 0[k-1] + // (expects zero vector constant as input) // Output: xR[0],...,xR[k-1], yR[0],...,yR[k-1] // template @@ -70,7 +71,7 @@ namespace nil { std::vector yP; std::vector p; std::vector pp; - TYPE zero; + std::vector zero; }; template, std::vector, std::vector, std::vector, - std::vector, std::vector, TYPE> + std::vector, std::vector, std::vector> form_input(context_type& context_object, raw_input_type raw_input, std::size_t num_chunks, std::size_t bit_size_chunk) { std::vector input_xP(num_chunks); @@ -117,7 +118,7 @@ namespace nil { std::vector input_yQ(num_chunks); std::vector input_p(num_chunks); std::vector input_pp(num_chunks); - TYPE input_zero; + std::vector input_zero(num_chunks); if constexpr (stage == GenerationStage::ASSIGNMENT) { for (std::size_t i = 0; i < num_chunks; i++) { @@ -127,8 +128,8 @@ namespace nil { input_yQ[i] = raw_input.yQ[i]; input_p[i] = raw_input.p[i]; input_pp[i] = raw_input.pp[i]; + input_zero[i] = raw_input.zero[i]; } - input_zero = raw_input.zero; } for (std::size_t i = 0; i < num_chunks; i++) { context_object.allocate(input_xP[i], 0, i, @@ -143,9 +144,9 @@ namespace nil { column_type::public_input); context_object.allocate(input_pp[i], 0, i + 5 * num_chunks, column_type::public_input); - } - context_object.allocate(input_zero, 0, 6 * num_chunks, + context_object.allocate(input_zero[i], 0, i + 6 * num_chunks, column_type::public_input); + } return std::make_tuple(input_xP, input_yP, input_xQ, input_yQ, input_p, input_pp, input_zero); } @@ -156,7 +157,8 @@ namespace nil { std::vector input_xQ, std::vector input_yQ, std::vector input_p, - std::vector input_pp, TYPE input_zero, + std::vector input_pp, + std::vector input_zero, std::size_t num_chunks, std::size_t bit_size_chunk, bool make_links = true) : generic_component(context_object) { @@ -241,7 +243,7 @@ namespace nil { Range_Check rc = Range_Check(context_object, x, num_chunks, bit_size_chunk); Check_Mod_P cm = - Check_Mod_P(context_object, x, input_pp, input_zero, + Check_Mod_P(context_object, x, input_pp, input_zero[0], num_chunks, bit_size_chunk); }; @@ -262,7 +264,7 @@ namespace nil { num_chunks, bit_size_chunk]( std::vector x, std::vector y) { Multiplication_Mod_P t = Multiplication_Mod_P( - context_object, x, y, input_p, input_pp, input_zero, + context_object, x, y, input_p, input_pp, input_zero[0], num_chunks, bit_size_chunk); return t.r; }; diff --git a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp index f1e1febda..8e68a36dc 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp @@ -76,7 +76,8 @@ void test_ec_double( public_input.begin() + 3 * num_chunks); raw_input.pp = std::vector(public_input.begin() + 3 * num_chunks, public_input.begin() + 4 * num_chunks); - raw_input.zero = public_input[4 * num_chunks]; + raw_input.zero = std::vector(public_input.begin() + 4 * num_chunks, + public_input.begin() + 5 * num_chunks); auto [at, A, desc] = B.assign(raw_input); bool pass = B.is_satisfied(at); @@ -154,7 +155,7 @@ void ec_double_tests() { ec_point_value_type Q = ec_point_value_type::one(); Q = Q * d; - public_input.resize(4 * num_chunks + 1); + public_input.resize(5 * num_chunks); integral_type xQ = integral_type(Q.X.data); integral_type yQ = integral_type(Q.Y.data); for (std::size_t j = 0; j < num_chunks; j++) { @@ -169,8 +170,9 @@ void ec_double_tests() { public_input[3 * num_chunks + j] = value_type(pp & mask); pp >>= bit_size_chunk; + + public_input[4 * num_chunks + j] = value_type(0); } - public_input.push_back(value_type(0)); // the zero test_ec_double(public_input); diff --git a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp index 4cb544617..903929433 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp @@ -112,7 +112,8 @@ void test_ec_full_add( public_input.begin() + 5 * num_chunks); raw_input.pp = std::vector(public_input.begin() + 5 * num_chunks, public_input.begin() + 6 * num_chunks); - raw_input.zero = public_input[6 * num_chunks]; + raw_input.zero = std::vector(public_input.begin() + 6 * num_chunks, + public_input.begin() + 7 * num_chunks); auto [at, A, desc] = B.assign(raw_input); bool pass = B.is_satisfied(at); @@ -192,7 +193,7 @@ void ec_full_add_tests() { P = P * d; Q = Q * d; - public_input.resize(6 * num_chunks + 1); + public_input.resize(7 * num_chunks); integral_type xP = integral_type(P.X.data); integral_type yP = integral_type(P.Y.data); integral_type xQ = integral_type(Q.X.data); @@ -215,8 +216,9 @@ void ec_full_add_tests() { public_input[5 * num_chunks + j] = value_type(pp & mask); pp >>= bit_size_chunk; + + public_input[6 * num_chunks + j] = value_type(0); } - public_input.push_back(value_type(0)); // the zero test_ec_full_add(public_input); diff --git a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp index 14a45df05..1cbb6f7ed 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp @@ -83,7 +83,8 @@ void test_ec_incomplete_add( public_input.begin() + 5 * num_chunks); raw_input.pp = std::vector(public_input.begin() + 5 * num_chunks, public_input.begin() + 6 * num_chunks); - raw_input.zero = public_input[6 * num_chunks]; + raw_input.zero = std::vector(public_input.begin() + 6 * num_chunks, + public_input.begin() + 7 * num_chunks); auto [at, A, desc] = B.assign(raw_input); bool pass = B.is_satisfied(at); @@ -163,7 +164,7 @@ void ec_incomplete_add_tests() { P = P * d; Q = Q * d; - public_input.resize(6 * num_chunks + 1); + public_input.resize(7 * num_chunks); integral_type xP = integral_type(P.X.data); integral_type yP = integral_type(P.Y.data); integral_type xQ = integral_type(Q.X.data); @@ -186,8 +187,9 @@ void ec_incomplete_add_tests() { public_input[5 * num_chunks + j] = value_type(pp & mask); pp >>= bit_size_chunk; + + public_input[6 * num_chunks + j] = value_type(0); } - public_input.push_back(value_type(0)); // the zero test_ec_incomplete_add(public_input);