-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
41ab935
commit 1363a34
Showing
7 changed files
with
2,586 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
675 changes: 675 additions & 0 deletions
675
crypto3/libs/blueprint/include/nil/blueprint/bbf/components/pubkey/ecdsa/ecdsa_recovery.hpp
Large diffs are not rendered by default.
Oops, something went wrong.
1,401 changes: 1,401 additions & 0 deletions
1,401
crypto3/libs/blueprint/include/nil/blueprint/bbf/components/pubkey/ecdsa/old_ecdsa.hpp
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
241 changes: 241 additions & 0 deletions
241
crypto3/libs/blueprint/test/bbf/pubkey/ecdsa/ecdsa_recovery.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
//---------------------------------------------------------------------------// | ||
// Copyright (c) 2024 Alexey Yashunsky <[email protected]> | ||
// Copyright (c) 2025 Antoine Cyr <[email protected]> | ||
// | ||
// 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_ecdsa_recovery_test | ||
|
||
#include <boost/test/unit_test.hpp> | ||
#include <nil/blueprint/bbf/circuit_builder.hpp> | ||
#include <nil/blueprint/bbf/components/pubkey/ecdsa/ecdsa_recovery.hpp> | ||
#include <nil/crypto3/algebra/curves/pallas.hpp> | ||
#include <nil/crypto3/algebra/curves/vesta.hpp> | ||
#include <nil/crypto3/random/algebraic_engine.hpp> | ||
|
||
using namespace nil; | ||
using namespace nil::blueprint; | ||
|
||
template<typename FieldType, typename CurveType, std::size_t num_chunks, | ||
std::size_t bit_size_chunk> | ||
void test_ecdsa_recovery( | ||
typename CurveType::scalar_field_type::value_type z, | ||
typename CurveType::scalar_field_type::value_type r, | ||
typename CurveType::scalar_field_type::value_type s, | ||
typename CurveType::scalar_field_type::value_type v, | ||
typename CurveType::template g1_type<nil::crypto3::algebra::curves::coordinates::affine>::value_type QA) { | ||
|
||
using foreign_basic_integral_type = typename CurveType::scalar_field_type::integral_type; | ||
typedef nil::crypto3::multiprecision::big_uint<2 * | ||
CurveType::scalar_field_type::modulus_bits> | ||
foreign_integral_type; | ||
using TYPE = typename FieldType::value_type; | ||
using integral_type = typename FieldType::integral_type; | ||
|
||
using BaseField = typename CurveType::base_field_type; | ||
|
||
std::vector<TYPE> public_input; | ||
|
||
foreign_integral_type B = foreign_integral_type(1) << bit_size_chunk, | ||
zf = foreign_integral_type(foreign_basic_integral_type(z.data)), | ||
rf = foreign_integral_type(foreign_basic_integral_type(r.data)), | ||
sf = foreign_integral_type(foreign_basic_integral_type(s.data)), | ||
vf = foreign_integral_type(foreign_basic_integral_type(v.data)); | ||
|
||
auto chunks_to_public_input = [&public_input, &B](foreign_integral_type &t) { | ||
for(std::size_t i = 0; i < num_chunks; i++) { | ||
public_input.push_back(TYPE(t % B)); | ||
t /= B; | ||
} | ||
}; | ||
chunks_to_public_input(zf); | ||
chunks_to_public_input(rf); | ||
chunks_to_public_input(sf); | ||
public_input.push_back(TYPE(vf)); | ||
|
||
auto assign_and_check = [&](auto& B, auto& raw_input) { | ||
raw_input.z = | ||
std::vector<TYPE>(public_input.begin(), public_input.begin() + num_chunks); | ||
raw_input.r = std::vector<TYPE>(public_input.begin() + num_chunks, | ||
public_input.begin() + 2 * num_chunks); | ||
raw_input.s = std::vector<TYPE>(public_input.begin() + 2 * num_chunks, | ||
public_input.begin() + 3 * num_chunks); | ||
raw_input.v = 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); | ||
foreign_integral_type xQA = 0, yQA = 0, pow = 1; | ||
for (std::size_t i = 0; i < num_chunks; i++) { | ||
xQA += foreign_integral_type(integral_type(A.xQA[i].data)) * pow; | ||
yQA += foreign_integral_type(integral_type(A.yQA[i].data)) * pow; | ||
pow <<= bit_size_chunk; | ||
} | ||
//ifdef BLUEPRINT_PLONK_PROFILING_ENABLED | ||
std::cout << "expected: " << QA.X.data << " " << QA.Y.data << "\n"; | ||
std::cout << "real : " << xQA << " " << yQA << "\n\n"; | ||
//#endif | ||
assert(xQA == QA.X.data); | ||
assert(yQA == QA.Y.data); | ||
}; | ||
|
||
if constexpr (std::is_same_v<BaseField, | ||
crypto3::algebra::curves::pallas::base_field_type>) { | ||
typename bbf::components::pallas_ecdsa_recovery< | ||
FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; | ||
|
||
auto B = | ||
bbf::circuit_builder<FieldType, bbf::components::pallas_ecdsa_recovery, | ||
std::size_t, std::size_t>(num_chunks, bit_size_chunk); | ||
|
||
assign_and_check(B, raw_input); | ||
} else if constexpr (std::is_same_v< | ||
BaseField, | ||
crypto3::algebra::curves::vesta::base_field_type>) { | ||
typename bbf::components::vesta_ecdsa_recovery< | ||
FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; | ||
auto B = | ||
bbf::circuit_builder<FieldType, bbf::components::vesta_ecdsa_recovery, | ||
std::size_t, std::size_t>(num_chunks, bit_size_chunk); | ||
|
||
assign_and_check(B, raw_input); | ||
} | ||
} | ||
|
||
|
||
template<typename FieldType, typename CurveType, std::size_t num_chunks, std::size_t bit_size_chunk, std::size_t RandomTestAmount> void multi_test_recovery() { | ||
nil::crypto3::random::algebraic_engine<typename CurveType::scalar_field_type> generate_random_scalar; | ||
|
||
boost::random::mt19937 seed_seq; | ||
generate_random_scalar.seed(seed_seq); | ||
|
||
using ec_point_value_type = typename CurveType::template g1_type<nil::crypto3::algebra::curves::coordinates::affine>::value_type; | ||
using scalar_value_type = typename CurveType::scalar_field_type::value_type; | ||
using scalar_integral_type = typename CurveType::scalar_field_type::integral_type; | ||
using base_integral_type = typename CurveType::base_field_type::integral_type; | ||
|
||
scalar_value_type d, z, k, r, s, v; | ||
scalar_integral_type n = CurveType::scalar_field_type::modulus, | ||
m = (n-1)/2 + 1; | ||
ec_point_value_type G = ec_point_value_type::one(), | ||
QA, R; | ||
|
||
|
||
for (std::size_t i = 0; i < RandomTestAmount; i++) { | ||
d = generate_random_scalar(); // private key | ||
QA = G*d; // public key | ||
|
||
z = generate_random_scalar(); // instead of taking part of the hash we just generate a random number | ||
|
||
do { | ||
k = generate_random_scalar(); // this random generation is part of the signature procedure | ||
R = G*k; | ||
v = scalar_value_type(scalar_integral_type(R.Y.data) % 2); | ||
r = base_integral_type(R.X.data); | ||
s = k.inversed() * (z + r*d); | ||
} while(r.is_zero() || s.is_zero() || (scalar_integral_type(r.data) >= n) || (scalar_integral_type(s.data) >= m)); | ||
|
||
std::cout << "Random test # " << (i+1) << std::endl; | ||
test_ecdsa_recovery<FieldType,CurveType,num_chunks,bit_size_chunk>(z,r,s,v,QA); | ||
} | ||
} | ||
|
||
template<typename FieldType, typename CurveType, std::size_t num_chunks, std::size_t bit_size_chunk, std::size_t RandomTestAmount> void multi_test_recovery_invalid() { | ||
nil::crypto3::random::algebraic_engine<typename CurveType::scalar_field_type> generate_random_scalar; | ||
|
||
boost::random::mt19937 seed_seq; | ||
generate_random_scalar.seed(seed_seq); | ||
|
||
using ec_point_value_type = typename CurveType::template g1_type<nil::crypto3::algebra::curves::coordinates::affine>::value_type; | ||
using scalar_value_type = typename CurveType::scalar_field_type::value_type; | ||
using scalar_integral_type = typename CurveType::scalar_field_type::integral_type; | ||
using base_value_type = typename CurveType::base_field_type::value_type; | ||
using base_integral_type = typename CurveType::base_field_type::integral_type; | ||
|
||
scalar_value_type d, z, k, r, s, v; | ||
scalar_integral_type n = CurveType::scalar_field_type::modulus, | ||
m = (n-1)/2 + 1; | ||
ec_point_value_type G = ec_point_value_type::one(), | ||
QA, R; | ||
base_value_type a = CurveType::template g1_type<nil::crypto3::algebra::curves::coordinates::affine>::params_type::b; | ||
|
||
for (std::size_t i = 0; i < RandomTestAmount; i++) { | ||
std::cout << "Random test # " << (i+1) << std::endl; | ||
d = generate_random_scalar(); // private key | ||
QA = G*d; // public key | ||
|
||
z = generate_random_scalar(); // instead of taking part of the hash we just generate a random number | ||
|
||
std::cout << "Invalid with s > n/2" << std::endl; | ||
do { | ||
k = generate_random_scalar(); // this random generation is part of the signature procedure | ||
R = G*k; | ||
v = scalar_value_type(scalar_integral_type(R.Y.data) % 2); | ||
r = base_integral_type(R.X.data); | ||
s = k.inversed() * (z + r*d); | ||
} while(r.is_zero() || s.is_zero() || (scalar_integral_type(r.data) >= n) || (scalar_integral_type(s.data) < m)); | ||
test_ecdsa_recovery<FieldType,CurveType,num_chunks,bit_size_chunk>(z,r,s,v,QA); | ||
|
||
std::cout << "Invalid off elliptic curve" << std::endl; | ||
do { | ||
k = generate_random_scalar(); // this random generation is part of the signature procedure | ||
R = G*k; | ||
v = scalar_value_type(scalar_integral_type(R.Y.data) % 2); | ||
r = base_integral_type(R.X.data); | ||
s = k.inversed() * (z + r*d); | ||
} while(r.is_zero() || s.is_zero() || (scalar_integral_type(r.data) >= n) || (scalar_integral_type(s.data) >= m)); | ||
|
||
base_value_type x1 = base_integral_type(r.data); | ||
while((x1*x1*x1 + a).is_square()) { | ||
x1 = x1 + 1; | ||
} | ||
|
||
test_ecdsa_recovery<FieldType,CurveType,num_chunks,bit_size_chunk>( | ||
z,scalar_value_type(base_integral_type(x1.data)),s,v,QA); | ||
} | ||
} | ||
|
||
constexpr static const std::size_t random_tests_amount = 1; | ||
|
||
BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) | ||
|
||
BOOST_AUTO_TEST_CASE(blueprint_plonk_pubkey_non_native_ecdsa_vesta) { | ||
using vesta = typename crypto3::algebra::curves::vesta; | ||
using pallas_base_field = typename crypto3::algebra::curves::pallas::base_field_type; | ||
|
||
// <base_field_type,curve_type, num_chunks, bit_size_chunk, random_tests_amount> | ||
multi_test_recovery<pallas_base_field,vesta, 3, 96, random_tests_amount>(); | ||
multi_test_recovery_invalid<pallas_base_field,vesta, 3, 96, random_tests_amount>(); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(blueprint_plonk_pubkey_non_native_ecdsa_pallas) { | ||
using pallas = typename crypto3::algebra::curves::pallas; | ||
using vesta_field_type = typename crypto3::algebra::curves::vesta::base_field_type; | ||
|
||
// <base_field_type,curve_type, num_chunks, bit_size_chunk, random_tests_amount> | ||
multi_test_recovery<vesta_field_type,pallas, 3, 96, random_tests_amount>(); | ||
multi_test_recovery_invalid<vesta_field_type,pallas, 3, 96, random_tests_amount>(); | ||
} | ||
|
||
BOOST_AUTO_TEST_SUITE_END() |
Oops, something went wrong.