|
| 1 | +//---------------------------------------------------------------------------// |
| 2 | +// Copyright (c) 2023 Alexey Yashunsky <[email protected]> |
| 3 | +// |
| 4 | +// MIT License |
| 5 | +// |
| 6 | +// Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | +// of this software and associated documentation files (the "Software"), to deal |
| 8 | +// in the Software without restriction, including without limitation the rights |
| 9 | +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 10 | +// copies of the Software, and to permit persons to whom the Software is |
| 11 | +// furnished to do so, subject to the following conditions: |
| 12 | +// |
| 13 | +// The above copyright notice and this permission notice shall be included in all |
| 14 | +// copies or substantial portions of the Software. |
| 15 | +// |
| 16 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 17 | +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 18 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 19 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 20 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 | +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 22 | +// SOFTWARE. |
| 23 | +//---------------------------------------------------------------------------// |
| 24 | +// @file Declaration of interfaces for point addition in the elliptic |
| 25 | +// curve group G2 = E'(F_p^2) : y^2 = x^3 + 4(1+u) with |
| 26 | +// F_p^2 = F_p[u]/(u^2 - (-1)). |
| 27 | +//---------------------------------------------------------------------------// |
| 28 | + |
| 29 | +#ifndef CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_BLS12_G2_POINT_ADDITION_HPP |
| 30 | +#define CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_BLS12_G2_POINT_ADDITION_HPP |
| 31 | + |
| 32 | +#include <nil/crypto3/zk/snark/arithmetization/plonk/constraint_system.hpp> |
| 33 | + |
| 34 | +#include <nil/blueprint/blueprint/plonk/assignment.hpp> |
| 35 | +#include <nil/blueprint/blueprint/plonk/circuit.hpp> |
| 36 | +#include <nil/blueprint/component.hpp> |
| 37 | +#include <nil/blueprint/manifest.hpp> |
| 38 | + |
| 39 | +#include <nil/crypto3/algebra/fields/detail/element/fp2.hpp> |
| 40 | +#include <nil/crypto3/algebra/fields/fp2.hpp> |
| 41 | + |
| 42 | +#include <nil/blueprint/components/algebra/fields/plonk/non_native/detail/abstract_fp2.hpp> |
| 43 | + |
| 44 | +namespace nil { |
| 45 | + namespace blueprint { |
| 46 | + namespace components { |
| 47 | + // E'(F_p^2) : y^2 = x^3 + 4(1+u) point addition gate. |
| 48 | + // Expects point at infinity encoded by (0,0) in input and output |
| 49 | + // Input: (xP, yP) = P[4], (xQ, yQ) = Q[4] |
| 50 | + // Output: (xR, yR) = R[4], R = P + Q as element of E'(F_p^2) |
| 51 | + // |
| 52 | + // We organize the computations in 2-cell blocks for storing Fp2 elements |
| 53 | + // The 12 blocks used are stored in 1 row with 24 cells or 2 rows with 12 cells. |
| 54 | + // Block contents are: |
| 55 | + // 0 1 2 3 4 5 6 7 8 9 10 11 |
| 56 | + // +--+--+--+--+--+--+---+---+--+--+--+--+ |
| 57 | + // |xP|yP|xQ|yQ|zP|zQ|zPQ|wPQ|la| |xR|yR| |
| 58 | + // +--+--+--+--+--+--+---+---+--+--+--+--+ |
| 59 | + // |
| 60 | + |
| 61 | + template<typename ArithmetizationType, typename BlueprintFieldType> |
| 62 | + class bls12_g2_point_addition; |
| 63 | + |
| 64 | + template<typename BlueprintFieldType, typename ArithmetizationParams> |
| 65 | + class bls12_g2_point_addition<crypto3::zk::snark::plonk_constraint_system<BlueprintFieldType, ArithmetizationParams>, |
| 66 | + BlueprintFieldType> |
| 67 | + : public plonk_component<BlueprintFieldType, ArithmetizationParams, 0, 0> { |
| 68 | + |
| 69 | + public: |
| 70 | + using component_type = plonk_component<BlueprintFieldType, ArithmetizationParams, 0, 0>; |
| 71 | + |
| 72 | + using var = typename component_type::var; |
| 73 | + using manifest_type = plonk_component_manifest; |
| 74 | + |
| 75 | + class gate_manifest_type : public component_gate_manifest { |
| 76 | + public: |
| 77 | + std::uint32_t gates_amount() const override { |
| 78 | + return bls12_g2_point_addition::gates_amount; |
| 79 | + } |
| 80 | + }; |
| 81 | + |
| 82 | + static gate_manifest get_gate_manifest(std::size_t witness_amount, |
| 83 | + std::size_t lookup_column_amount) { |
| 84 | + static gate_manifest manifest = gate_manifest(gate_manifest_type()); |
| 85 | + return manifest; |
| 86 | + } |
| 87 | + |
| 88 | + static manifest_type get_manifest() { |
| 89 | + static manifest_type manifest = manifest_type( |
| 90 | + std::shared_ptr<manifest_param>(new manifest_range_param(12,24,12)), // 12 or 24 |
| 91 | + false |
| 92 | + ); |
| 93 | + return manifest; |
| 94 | + } |
| 95 | + |
| 96 | + constexpr static std::size_t get_rows_amount(std::size_t witness_amount, |
| 97 | + std::size_t lookup_column_amount) { |
| 98 | + return 1 + (witness_amount < 24); |
| 99 | + } |
| 100 | + |
| 101 | + constexpr static const std::size_t gates_amount = 1; |
| 102 | + const std::size_t rows_amount = get_rows_amount(this->witness_amount(), 0); |
| 103 | + |
| 104 | + struct input_type { |
| 105 | + std::array<var,4> P, Q; |
| 106 | + |
| 107 | + std::vector<var> all_vars() const { |
| 108 | + std::vector<var> res = {}; |
| 109 | + for(auto & e : P) { res.push_back(e); } |
| 110 | + for(auto & e : Q) { res.push_back(e); } |
| 111 | + return res; |
| 112 | + } |
| 113 | + }; |
| 114 | + |
| 115 | + struct result_type { |
| 116 | + std::array<var,4> R; |
| 117 | + |
| 118 | + result_type(const bls12_g2_point_addition &component, std::uint32_t start_row_index) { |
| 119 | + const std::size_t WA = component.witness_amount(); |
| 120 | + |
| 121 | + for(std::size_t i = 0; i < 4; i++) { |
| 122 | + R[i] = var(component.W(WA - 4 + i), start_row_index + (WA < 24), false, var::column_type::witness); |
| 123 | + } |
| 124 | + } |
| 125 | + |
| 126 | + std::vector<var> all_vars() const { |
| 127 | + std::vector<var> res = {}; |
| 128 | + |
| 129 | + for(auto & e : R) { res.push_back(e); } |
| 130 | + return res; |
| 131 | + } |
| 132 | + }; |
| 133 | + |
| 134 | + template<typename ContainerType> |
| 135 | + explicit bls12_g2_point_addition(ContainerType witness) : component_type(witness, {}, {}, get_manifest()) {}; |
| 136 | + |
| 137 | + template<typename WitnessContainerType, typename ConstantContainerType, |
| 138 | + typename PublicInputContainerType> |
| 139 | + bls12_g2_point_addition(WitnessContainerType witness, ConstantContainerType constant, |
| 140 | + PublicInputContainerType public_input) : |
| 141 | + component_type(witness, constant, public_input, get_manifest()) {}; |
| 142 | + |
| 143 | + bls12_g2_point_addition( |
| 144 | + std::initializer_list<typename component_type::witness_container_type::value_type> |
| 145 | + witnesses, |
| 146 | + std::initializer_list<typename component_type::constant_container_type::value_type> |
| 147 | + constants, |
| 148 | + std::initializer_list<typename component_type::public_input_container_type::value_type> |
| 149 | + public_inputs) : |
| 150 | + component_type(witnesses, constants, public_inputs, get_manifest()) {}; |
| 151 | + }; |
| 152 | + |
| 153 | + template<typename BlueprintFieldType, typename ArithmetizationParams> |
| 154 | + using plonk_bls12_g2_point_addition = |
| 155 | + bls12_g2_point_addition< |
| 156 | + crypto3::zk::snark::plonk_constraint_system<BlueprintFieldType, ArithmetizationParams>, |
| 157 | + BlueprintFieldType>; |
| 158 | + |
| 159 | + template<typename BlueprintFieldType, typename ArithmetizationParams> |
| 160 | + typename plonk_bls12_g2_point_addition<BlueprintFieldType, ArithmetizationParams>::result_type generate_assignments( |
| 161 | + const plonk_bls12_g2_point_addition<BlueprintFieldType, ArithmetizationParams> &component, |
| 162 | + assignment<crypto3::zk::snark::plonk_constraint_system<BlueprintFieldType, ArithmetizationParams>> |
| 163 | + &assignment, |
| 164 | + const typename plonk_bls12_g2_point_addition<BlueprintFieldType, ArithmetizationParams>::input_type |
| 165 | + &instance_input, |
| 166 | + const std::uint32_t start_row_index) { |
| 167 | + |
| 168 | + using value_type = typename BlueprintFieldType::value_type; |
| 169 | + |
| 170 | + const std::size_t WA = component.witness_amount(); |
| 171 | + |
| 172 | + using policy_type_fp2 = crypto3::algebra::fields::fp2<BlueprintFieldType>; |
| 173 | + using fp2_element = typename policy_type_fp2::value_type; |
| 174 | + |
| 175 | + fp2_element fp2zero = fp2_element(0,0), |
| 176 | + xP = fp2_element(var_value(assignment, instance_input.P[0]), |
| 177 | + var_value(assignment, instance_input.P[1])), |
| 178 | + yP = fp2_element(var_value(assignment, instance_input.P[2]), |
| 179 | + var_value(assignment, instance_input.P[3])), |
| 180 | + xQ = fp2_element(var_value(assignment, instance_input.Q[0]), |
| 181 | + var_value(assignment, instance_input.Q[1])), |
| 182 | + yQ = fp2_element(var_value(assignment, instance_input.Q[2]), |
| 183 | + var_value(assignment, instance_input.Q[3])), |
| 184 | + zP = yP.inversed(), // NB: division by 0 is defined as 0 |
| 185 | + zQ = yQ.inversed(), |
| 186 | + zPQ = (xP - xQ).inversed(), |
| 187 | + wPQ = (yP + yQ).inversed(), |
| 188 | + lambda = (xP == xQ)? (3*xP.pow(2) / (2*yP)) : ((yP-yQ)/(xP-xQ)), |
| 189 | + nu = yP - lambda*xP, |
| 190 | + xR, yR; |
| 191 | + if (yP == fp2zero) { |
| 192 | + xR = xQ; |
| 193 | + yR = yQ; |
| 194 | + } else { |
| 195 | + if (yQ == fp2zero) { |
| 196 | + xR = xP; |
| 197 | + yR = yP; |
| 198 | + } else { |
| 199 | + if ((xP == xQ) && (yP == -yQ)) { |
| 200 | + xR = fp2zero; |
| 201 | + yR = fp2zero; |
| 202 | + } else { |
| 203 | + xR = lambda.pow(2) - xP - xQ, |
| 204 | + yR = -(lambda*xR + nu); |
| 205 | + } |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + for(std::size_t i = 0; i < 2; i++) { |
| 210 | + assignment.witness(component.W(i),start_row_index) = xP.data[i]; |
| 211 | + assignment.witness(component.W(2 + i),start_row_index) = yP.data[i]; |
| 212 | + assignment.witness(component.W(4 + i),start_row_index) = xQ.data[i]; |
| 213 | + assignment.witness(component.W(6 + i),start_row_index) = yQ.data[i]; |
| 214 | + assignment.witness(component.W(8 + i),start_row_index) = zP.data[i]; |
| 215 | + assignment.witness(component.W(10 + i),start_row_index) = zQ.data[i]; |
| 216 | + |
| 217 | + assignment.witness(component.W((12 + i) % WA),start_row_index + (WA < 24)) = zPQ.data[i]; |
| 218 | + assignment.witness(component.W((14 + i) % WA),start_row_index + (WA < 24)) = wPQ.data[i]; |
| 219 | + assignment.witness(component.W((16 + i) % WA),start_row_index + (WA < 24)) = lambda.data[i]; |
| 220 | + // block #9 is skipped for alignment purposes |
| 221 | + assignment.witness(component.W((20 + i) % WA),start_row_index + (WA < 24)) = xR.data[i]; |
| 222 | + assignment.witness(component.W((22 + i) % WA),start_row_index + (WA < 24)) = yR.data[i]; |
| 223 | + } |
| 224 | + |
| 225 | + return typename plonk_bls12_g2_point_addition<BlueprintFieldType, ArithmetizationParams>::result_type( |
| 226 | + component, start_row_index); |
| 227 | + } |
| 228 | + |
| 229 | + template<typename BlueprintFieldType, typename ArithmetizationParams> |
| 230 | + std::size_t generate_gates( |
| 231 | + const plonk_bls12_g2_point_addition<BlueprintFieldType, ArithmetizationParams> &component, |
| 232 | + circuit<crypto3::zk::snark::plonk_constraint_system<BlueprintFieldType, ArithmetizationParams>> &bp, |
| 233 | + assignment<crypto3::zk::snark::plonk_constraint_system<BlueprintFieldType, ArithmetizationParams>> |
| 234 | + &assignment, |
| 235 | + const typename plonk_bls12_g2_point_addition<BlueprintFieldType, ArithmetizationParams>::input_type |
| 236 | + &instance_input) { |
| 237 | + |
| 238 | + const std::size_t WA = component.witness_amount(); |
| 239 | + |
| 240 | + using var = typename plonk_bls12_g2_point_addition<BlueprintFieldType, ArithmetizationParams>::var; |
| 241 | + using constraint_type = crypto3::zk::snark::plonk_constraint<BlueprintFieldType>; |
| 242 | + |
| 243 | + // Fp2 field over constraints: |
| 244 | + using fp2_constraint = detail::abstract_fp2_element<constraint_type>; |
| 245 | + |
| 246 | + constraint_type cnstr_zero = constraint_type(), |
| 247 | + cnstr_one = cnstr_zero + 1; |
| 248 | + |
| 249 | + fp2_constraint one = {cnstr_one,cnstr_zero}, |
| 250 | + xP = {var(component.W(0), 0, true),var(component.W(1), 0, true)}, |
| 251 | + yP = {var(component.W(2), 0, true),var(component.W(3), 0, true)}, |
| 252 | + xQ = {var(component.W(4), 0, true),var(component.W(5), 0, true)}, |
| 253 | + yQ = {var(component.W(6), 0, true),var(component.W(7), 0, true)}, |
| 254 | + zP = {var(component.W(8), 0, true),var(component.W(9), 0, true)}, |
| 255 | + zQ = {var(component.W(10), 0, true),var(component.W(11), 0, true)}, |
| 256 | + zPQ = {var(component.W(12 % WA), (WA < 24), true),var(component.W(13 % WA), (WA < 24), true)}, |
| 257 | + wPQ = {var(component.W(14 % WA), (WA < 24), true),var(component.W(15 % WA), (WA < 24), true)}, |
| 258 | + la = {var(component.W(16 % WA), (WA < 24), true),var(component.W(17 % WA), (WA < 24), true)}, |
| 259 | + xR = {var(component.W(20 % WA), (WA < 24), true),var(component.W(21 % WA), (WA < 24), true)}, |
| 260 | + yR = {var(component.W(22 % WA), (WA < 24), true),var(component.W(23 % WA), (WA < 24), true)}; |
| 261 | + fp2_constraint C; |
| 262 | + |
| 263 | + std::vector<constraint_type> Cs = {}; |
| 264 | + |
| 265 | + // yP(1 - yP zP) = 0 (1) |
| 266 | + C = yP * (one - yP * zP); |
| 267 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 268 | + |
| 269 | + // yQ(1 - yQ zQ) = 0 (2) |
| 270 | + C = yQ * (one - yQ * zQ); |
| 271 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 272 | + |
| 273 | + // (xR - xQ)(1 - yP zP) = 0 (3) |
| 274 | + C = (xR - xQ) * (one - yP * zP); |
| 275 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 276 | + |
| 277 | + // (yR - yQ)(1 - yP zP) = 0 (4) |
| 278 | + C = (yR - yQ)*(one - yP * zP); |
| 279 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 280 | + |
| 281 | + // (xR - xP)(1 - yQ zQ) = 0 (5) |
| 282 | + C = (xR - xP)*(one - yQ*zQ); |
| 283 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 284 | + |
| 285 | + // (yR - yP)(1 - yQ zQ) = 0 (6) |
| 286 | + C = (yR - yP)*(one - yQ*zQ); |
| 287 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 288 | + |
| 289 | + // (xP - xQ)(1 - (xP-xQ) zPQ) = 0 (7) |
| 290 | + C = (xP - xQ)*(one - (xP - xQ)*zPQ); |
| 291 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 292 | + |
| 293 | + // zPQ (1 - (xP - xQ) zPQ) = 0 (8) |
| 294 | + C = zPQ * (one - (xP - xQ) * zPQ); |
| 295 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 296 | + |
| 297 | + // (yP + yQ)(1 - (yP + yQ) wPQ) = 0 (9) |
| 298 | + C = (yP + yQ)*(one - (yP + yQ)*wPQ); |
| 299 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 300 | + |
| 301 | + // wPQ (1 - (yP + yQ) wPQ) = 0 (10) |
| 302 | + C = wPQ * (one - (yP + yQ)*wPQ); |
| 303 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 304 | + |
| 305 | + // yP(1 - (xP - xQ) zPQ) yQ(1 - (yP + yQ) wPQ) xR = 0 (11) |
| 306 | + C = yP * (one - (xP-xQ)*zPQ) * yQ * (one - (yP + yQ)* wPQ) * xR; |
| 307 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 308 | + |
| 309 | + // yP(1 - (xP - xQ) zPQ) yQ(1 - (yP + yQ) wPQ) yR = 0 (12) |
| 310 | + C = yP * (one - (xP-xQ)*zPQ) * yQ * (one - (yP + yQ)* wPQ) * yR; |
| 311 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 312 | + |
| 313 | + // yP yQ (zPQ + wPQ (1 - (xP - xQ) zPQ)) (xR - la^2 + xP + xQ) = 0 (13) |
| 314 | + C = yP * yQ * (zPQ + wPQ * (one - (xP - xQ)*zPQ)) * (xR - la*la + xP + xQ); |
| 315 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 316 | + |
| 317 | + // yP yQ (zPQ + wPQ (1 - (xP - xQ) zPQ)) (yR + yP + la(xR - xP)) = 0 (14) |
| 318 | + C = yP * yQ * (zPQ + wPQ * (one - (xP - xQ)*zPQ)) * (yR + yP + la*(xR - xP)); |
| 319 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 320 | + |
| 321 | + // yQ ( 2yP zPQ ( (xP - xQ)la - (yP - yQ) ) + (1 - (xP - xQ)zPQ) wPQ (2yP la - 3xP^2)) = 0 (15) |
| 322 | + C = yQ * (2*yP * zPQ * ((xP - xQ)*la - (yP - yQ)) + (one - (xP - xQ)*zPQ) * wPQ *(2*yP*la - 3*xP*xP)); |
| 323 | + Cs.push_back(C[0]); Cs.push_back(C[1]); |
| 324 | + |
| 325 | + return bp.add_gate(Cs); |
| 326 | + } |
| 327 | + |
| 328 | + template<typename BlueprintFieldType, typename ArithmetizationParams> |
| 329 | + void generate_copy_constraints( |
| 330 | + const plonk_bls12_g2_point_addition<BlueprintFieldType, ArithmetizationParams> &component, |
| 331 | + circuit<crypto3::zk::snark::plonk_constraint_system<BlueprintFieldType, ArithmetizationParams>> &bp, |
| 332 | + assignment<crypto3::zk::snark::plonk_constraint_system<BlueprintFieldType, ArithmetizationParams>> |
| 333 | + &assignment, |
| 334 | + const typename plonk_bls12_g2_point_addition<BlueprintFieldType, ArithmetizationParams>::input_type &instance_input, |
| 335 | + const std::size_t start_row_index) { |
| 336 | + |
| 337 | + using var = typename plonk_bls12_g2_point_addition<BlueprintFieldType, ArithmetizationParams>::var; |
| 338 | + |
| 339 | + const std::size_t WA = component.witness_amount(); |
| 340 | + |
| 341 | + for(std::size_t i = 0; i < 4; i++) { |
| 342 | + bp.add_copy_constraint({var(component.W(i), start_row_index, false), instance_input.P[i]}); |
| 343 | + } |
| 344 | + } |
| 345 | + |
| 346 | + template<typename BlueprintFieldType, typename ArithmetizationParams> |
| 347 | + typename plonk_bls12_g2_point_addition<BlueprintFieldType, ArithmetizationParams>::result_type generate_circuit( |
| 348 | + const plonk_bls12_g2_point_addition<BlueprintFieldType, ArithmetizationParams> &component, |
| 349 | + circuit<crypto3::zk::snark::plonk_constraint_system<BlueprintFieldType, ArithmetizationParams>> &bp, |
| 350 | + assignment<crypto3::zk::snark::plonk_constraint_system<BlueprintFieldType, ArithmetizationParams>> |
| 351 | + &assignment, |
| 352 | + const typename plonk_bls12_g2_point_addition<BlueprintFieldType, ArithmetizationParams>::input_type &instance_input, |
| 353 | + const std::size_t start_row_index) { |
| 354 | + |
| 355 | + std::size_t selector_index = generate_gates(component, bp, assignment, instance_input); |
| 356 | + |
| 357 | + assignment.enable_selector(selector_index, start_row_index); |
| 358 | + |
| 359 | + generate_copy_constraints(component, bp, assignment, instance_input, start_row_index); |
| 360 | + |
| 361 | + return typename plonk_bls12_g2_point_addition<BlueprintFieldType, ArithmetizationParams>::result_type( |
| 362 | + component, start_row_index); |
| 363 | + } |
| 364 | + |
| 365 | + } // namespace components |
| 366 | + } // namespace blueprint |
| 367 | +} // namespace nil |
| 368 | + |
| 369 | +#endif // CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_BLS12_G2_POINT_ADDITION_HPP |
0 commit comments