Skip to content

Commit

Permalink
Merge pull request #1904 from AntelopeIO/more_bls_benchmark
Browse files Browse the repository at this point in the history
BLS: add benchmarking for Affine form host functions
  • Loading branch information
linh2931 authored Nov 17, 2023
2 parents d9e59b8 + 6a9a8b1 commit cc9bba8
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 53 deletions.
2 changes: 1 addition & 1 deletion benchmark/benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ std::map<std::string, std::function<void()>> features {
};

// values to control cout format
constexpr auto name_width = 28;
constexpr auto name_width = 40;
constexpr auto runs_width = 5;
constexpr auto time_width = 12;
constexpr auto ns_width = 2;
Expand Down
182 changes: 130 additions & 52 deletions benchmark/bls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,32 @@ std::array<uint64_t, 4> random_scalar()
};
}

// utilility to create a random fp
fp random_fe()
{
std::random_device rd;
std::mt19937_64 gen(rd());
std::uniform_int_distribution<uint64_t> dis;

return fp({
dis(gen) % 0xb9feffffffffaaab,
dis(gen) % 0x1eabfffeb153ffff,
dis(gen) % 0x6730d2a0f6b0f624,
dis(gen) % 0x64774b84f38512bf,
dis(gen) % 0x4b1ba7b6434bacd7,
dis(gen) % 0x1a0111ea397fe69a
});
}

// utilility to create a random fp2
fp2 random_fe2()
{
return fp2({
random_fe(),
random_fe()
});
}

// utilility to create a random g1
bls12_381::g1 random_g1()
{
Expand All @@ -125,34 +151,30 @@ bls12_381::g2 random_g2()
void benchmark_bls_g1_add() {
// prepare g1 operand in Jacobian LE format
g1 p = random_g1();
std::vector<char> buf(96);
p.toAffineBytesLE(std::span<uint8_t, 96>((uint8_t*)buf.data(), 96), true);
eosio::chain::span<const char> op1(buf.data(), buf.size());
std::array<char, 96> op;
p.toAffineBytesLE(std::span<uint8_t, 96>((uint8_t*)op.data(), 96), false);

// prepare result operand
std::vector<char> result_buf(96);
eosio::chain::span<char> result(result_buf.data(), result_buf.size());
std::array<char, 96> result;

// set up bls_g1_add to be benchmarked
interface_in_benchmark interface;
auto g1_add_func = [&]() {
interface.interface->bls_g1_add(op1, op1, result);
auto benchmarked_func = [&]() {
interface.interface->bls_g1_add(op, op, result);
};

benchmarking("bls_g1_add", g1_add_func);
benchmarking("bls_g1_add", benchmarked_func);
}

// bls_g2_add benchmarking
void benchmark_bls_g2_add() {
// prepare g2 operand in Jacobian LE format
g2 p = random_g2();
std::vector<char> buf(192);
p.toAffineBytesLE(std::span<uint8_t, 192>((uint8_t*)buf.data(), 192), true);
eosio::chain::span<const char> op(buf.data(), buf.size());
std::array<char, 192> op;
p.toAffineBytesLE(std::span<uint8_t, 192>((uint8_t*)op.data(), 192), false);

// prepare result operand
std::vector<char> result_buf(192);
eosio::chain::span<char> result(result_buf.data(), result_buf.size());
std::array<char, 192> result;

// set up bls_g2_add to be benchmarked
interface_in_benchmark interface;
Expand All @@ -164,12 +186,12 @@ void benchmark_bls_g2_add() {
}

// bls_g1_weighted_sum benchmarking utility
void benchmark_bls_g1_weighted_sum(std::string test_name, uint32_t num_points) {
void benchmark_bls_g1_weighted_sum_impl(const std::string& test_name, uint32_t num_points) {
// prepare g1 points operand
std::vector<char> g1_buf(96*num_points);
for (auto i=0u; i < num_points; ++i) {
g1 p = random_g1();
p.toAffineBytesLE(std::span<uint8_t, 96>((uint8_t*)g1_buf.data() + i * 96, 96), true);
p.toAffineBytesLE(std::span<uint8_t, 96>((uint8_t*)g1_buf.data() + i * 96, 96), false);
}
chain::span<const char> g1_points(g1_buf.data(), g1_buf.size());

Expand All @@ -182,8 +204,7 @@ void benchmark_bls_g1_weighted_sum(std::string test_name, uint32_t num_points) {
chain::span<const char> scalars(scalars_buf.data(), scalars_buf.size());

// prepare result operand
std::vector<char> result_buf(96);
eosio::chain::span<char> result(result_buf.data(), result_buf.size());
std::array<char, 96> result;

// set up bls_g1_weighted_sum to be benchmarked
interface_in_benchmark interface;
Expand All @@ -196,21 +217,26 @@ void benchmark_bls_g1_weighted_sum(std::string test_name, uint32_t num_points) {

// bls_g1_weighted_sum benchmarking with 1 input point
void benchmark_bls_g1_weighted_sum_one_point() {
benchmark_bls_g1_weighted_sum("bls_g1_weighted_sum 1 point", 1);
benchmark_bls_g1_weighted_sum_impl("bls_g1_weighted_sum 1 point", 1);
}

// bls_g1_weighted_sum benchmarking with 3 input points
void benchmark_bls_g1_weighted_sum_three_point() {
benchmark_bls_g1_weighted_sum("bls_g1_weighted_sum 3 points", 3);
benchmark_bls_g1_weighted_sum_impl("bls_g1_weighted_sum 3 points", 3);
}

// bls_g1_weighted_sum benchmarking with 5 input points
void benchmark_bls_g1_weighted_sum_five_point() {
benchmark_bls_g1_weighted_sum_impl("bls_g1_weighted_sum 5 points", 5);
}

// bls_g2_weighted_sum benchmarking utility
void benchmark_bls_g2_weighted_sum(std::string test_name, uint32_t num_points) {
void benchmark_bls_g2_weighted_sum_impl(const std::string& test_name, uint32_t num_points) {
// prepare g2 points operand
std::vector<char> g2_buf(192*num_points);
for (auto i=0u; i < num_points; ++i) {
g2 p = random_g2();
p.toAffineBytesLE(std::span<uint8_t, 192>((uint8_t*)g2_buf.data() + i * 192, 192), true);
p.toAffineBytesLE(std::span<uint8_t, 192>((uint8_t*)g2_buf.data() + i * 192, 192), false);
}
eosio::chain::span<const char> g2_points(g2_buf.data(), g2_buf.size());

Expand All @@ -223,12 +249,11 @@ void benchmark_bls_g2_weighted_sum(std::string test_name, uint32_t num_points) {
eosio::chain::span<const char> scalars(scalars_buf.data(), scalars_buf.size());

// prepare result operand
std::vector<char> result_buf(192);
eosio::chain::span<char> result(result_buf.data(), result_buf.size());
std::array<char, 192> result;

// set up bls_g2_weighted_sum to be benchmarked
interface_in_benchmark interface;
auto benchmarked_func = [&]() {
auto benchmarked_func = [&]() {
interface.interface->bls_g2_weighted_sum(g2_points, scalars, num_points, result);
};

Expand All @@ -237,40 +262,43 @@ void benchmark_bls_g2_weighted_sum(std::string test_name, uint32_t num_points) {

// bls_g2_weighted_sum benchmarking with 1 input point
void benchmark_bls_g2_weighted_sum_one_point() {
benchmark_bls_g2_weighted_sum("bls_g2_weighted_sum 1 point", 1);
benchmark_bls_g2_weighted_sum_impl("bls_g2_weighted_sum 1 point", 1);
}

// bls_g2_weighted_sum benchmarking with 3 input points
void benchmark_bls_g2_weighted_sum_three_point() {
benchmark_bls_g2_weighted_sum("bls_g2_weighted_sum 3 points", 3);
benchmark_bls_g2_weighted_sum_impl("bls_g2_weighted_sum 3 points", 3);
}

// bls_g2_weighted_sum benchmarking with 5 input points
void benchmark_bls_g2_weighted_sum_five_point() {
benchmark_bls_g2_weighted_sum_impl("bls_g2_weighted_sum 5 points", 5);
}

// bls_pairing benchmarking utility
void benchmark_bls_pairing(std::string test_name, uint32_t num_pairs) {
void benchmark_bls_pairing_impl(const std::string& test_name, uint32_t num_pairs) {
// prepare g1 operand
std::vector<char> g1_buf(96*num_pairs);
//g1_buf.reserve(96*num_pairs);
for (auto i=0u; i < num_pairs; ++i) {
g1 p = random_g1();
p.toAffineBytesLE(std::span<uint8_t, 96>((uint8_t*)g1_buf.data() + i * 96, 96), true);
p.toAffineBytesLE(std::span<uint8_t, 96>((uint8_t*)g1_buf.data() + i * 96, 96), false);
}
eosio::chain::span<const char> g1_points(g1_buf.data(), g1_buf.size());

// prepare g2 operand
std::vector<char> g2_buf(192*num_pairs);
for (auto i=0u; i < num_pairs; ++i) {
g2 p2 = random_g2();
p2.toAffineBytesLE(std::span<uint8_t, (192)>((uint8_t*)g2_buf.data() + i * 192, (192)), true);
p2.toAffineBytesLE(std::span<uint8_t, (192)>((uint8_t*)g2_buf.data() + i * 192, (192)), false);
}
eosio::chain::span<const char> g2_points(g2_buf.data(), g2_buf.size());

// prepare result operand
std::vector<char> result_buf(576);
eosio::chain::span<char> result(result_buf.data(), result_buf.size());
std::array<char, 576> result;

// set up bls_pairing to be benchmarked
interface_in_benchmark interface;
auto benchmarked_func = [&]() {
auto benchmarked_func = [&]() {
interface.interface->bls_pairing(g1_points, g2_points, num_pairs, result);
};

Expand All @@ -279,27 +307,27 @@ void benchmark_bls_pairing(std::string test_name, uint32_t num_pairs) {

// bls_pairing benchmarking with 1 input pair
void benchmark_bls_pairing_one_pair() {
benchmark_bls_pairing("bls_pairing 1 pair", 1);
benchmark_bls_pairing_impl("bls_pairing 1 pair", 1);
}

// bls_pairing benchmarking with 3 input pairs
void benchmark_bls_pairing_three_pair() {
benchmark_bls_pairing("bls_pairing 3 pairs", 3);
benchmark_bls_pairing_impl("bls_pairing 3 pairs", 3);
}

// bls_g1_map benchmarking
void benchmark_bls_g1_map() {
// prepare e operand. Must be fp LE.
std::vector<uint8_t> e_buf = {0xc9, 0x3f,0x81,0x7b, 0x15, 0x9b, 0xdf, 0x84, 0x04, 0xdc, 0x37, 0x85, 0x14, 0xf8, 0x45, 0x19, 0x2b, 0xba, 0xe4, 0xfa, 0xac, 0x7f, 0x4a, 0x56, 0x89, 0x24, 0xf2, 0xd9, 0x72, 0x51, 0x25, 0x00, 0x04, 0x89, 0x40, 0x8f, 0xd7, 0x96, 0x46, 0x1c, 0x28, 0x89, 0x00, 0xad, 0xd0, 0x0d, 0x46, 0x18};
eosio::chain::span<const char> e((char*)e_buf.data(), e_buf.size());
std::array<char, 48> e;
fp a = random_fe();
a.toBytesLE(std::span<uint8_t, 48>((uint8_t*)e.data(), 48), false);

// prepare result operand
std::vector<char> result_buf(96);
eosio::chain::span<char> result(result_buf.data(), result_buf.size());
std::array<char, 96> result;

// set up bls_g1_map to be benchmarked
interface_in_benchmark interface;
auto benchmarked_func = [&]() {
auto benchmarked_func = [&]() {
interface.interface->bls_g1_map(e, result);
};

Expand All @@ -308,17 +336,16 @@ void benchmark_bls_g1_map() {

// bls_g2_map benchmarking
void benchmark_bls_g2_map() {
// prepare e operand. Must be fp2 LE.
std::vector<uint8_t> e_buf = {0xd4, 0xf2, 0xcf, 0xec, 0x99, 0x38, 0x78, 0x09, 0x57, 0x4f, 0xcc, 0x2d, 0xba, 0x10, 0x56, 0x03, 0xd9, 0x50, 0xd4, 0x90, 0xe2, 0xbe, 0xbe, 0x0c, 0x21, 0x2c, 0x05, 0xe1, 0x6b, 0x78, 0x47, 0x45, 0xef, 0x4f, 0xe8, 0xe7, 0x0b, 0x55, 0x4d, 0x0a, 0x52, 0xfe, 0x0b, 0xed, 0x5e, 0xa6, 0x69, 0x0a, 0xde, 0x23, 0x48, 0xeb, 0x89, 0x72, 0xa9, 0x67, 0x40, 0xa4, 0x30, 0xdf, 0x16, 0x2d, 0x92, 0x0e, 0x17, 0x5f, 0x59, 0x23, 0xa7, 0x6d, 0x18, 0x65, 0x0e, 0xa2, 0x4a, 0x8e, 0xc0, 0x6d, 0x41, 0x4c, 0x6d, 0x1d, 0x21, 0x8d, 0x67, 0x3d, 0xac, 0x36, 0x19, 0xa1, 0xa5, 0xc1, 0x42, 0x78, 0x57, 0x08};
eosio::chain::span<const char> e((char*)e_buf.data(), e_buf.size());
std::array<char, 96> e;
fp2 a = random_fe2();
a.toBytesLE(std::span<uint8_t, 96>((uint8_t*)e.data(), 96), false);

// prepare result operand
std::vector<char> result_buf(192);
eosio::chain::span<char> result(result_buf.data(), result_buf.size());
std::array<char, 192> result;

// set up bls_g2_map to be benchmarked
interface_in_benchmark interface;
auto benchmarked_func = [&]() {
auto benchmarked_func = [&]() {
interface.interface->bls_g2_map(e, result);
};

Expand All @@ -328,27 +355,74 @@ void benchmark_bls_g2_map() {
// bls_fp_mod benchmarking
void benchmark_bls_fp_mod() {
// prepare scalar operand
std::vector<char> scalar_buf(64);
std::array<char, 64> scalar;
// random_scalar returns 32 bytes. need to call it twice
for (auto i=0u; i < 2; ++i) {
std::array<uint64_t, 4> s = random_scalar();
scalar::toBytesLE(s, std::span<uint8_t, 32>((uint8_t*)scalar_buf.data() + i*32, 32));
scalar::toBytesLE(s, std::span<uint8_t, 32>((uint8_t*)scalar.data() + i*32, 32));
}
chain::span<const char> scalar(scalar_buf.data(), scalar_buf.size());

// prepare result operand
std::vector<char> result_buf(48);
eosio::chain::span<char> result(result_buf.data(), result_buf.size());
std::array<char, 48> result;

// set up bls_fp_mod to be benchmarked
interface_in_benchmark interface;
auto benchmarked_func = [&]() {
auto benchmarked_func = [&]() {
interface.interface->bls_fp_mod(scalar, result);
};

benchmarking("bls_fp_mod", benchmarked_func);
}

void benchmark_bls_fp_mul() {
// prepare op1
std::array<char, 48> op1;
fp a = random_fe();
a.toBytesLE(std::span<uint8_t, 48>((uint8_t*)op1.data(), 48), false);

// prepare op2
std::array<char, 48> op2;
fp b = random_fe();
b.toBytesLE(std::span<uint8_t, 48>((uint8_t*)op2.data(), 48), false);

// prepare result operand
std::array<char, 48> result;

// set up bls_fp_mul to be benchmarked
interface_in_benchmark interface;
auto benchmarked_func = [&]() {
interface.interface->bls_fp_mul(op1, op2, result);
};

benchmarking("bls_fp_mul", benchmarked_func);
}

void benchmark_bls_fp_exp() {
// prepare base
std::array<char, 48> base;
fp a = random_fe();
a.toBytesLE(std::span<uint8_t, 48>((uint8_t*)base.data(), 48), false);

// prepare exp operand
std::array<char, 64> exp;
// random_scalar returns 32 bytes. need to call it twice
for (auto i=0u; i < 2; ++i) {
std::array<uint64_t, 4> s = random_scalar();
scalar::toBytesLE(s, std::span<uint8_t, 32>((uint8_t*)exp.data() + i*32, 32));
}

// prepare result operand
std::array<char, 48> result;

// set up bls_fp_exp to be benchmarked
interface_in_benchmark interface;
auto benchmarked_func = [&]() {
interface.interface->bls_fp_exp(base, exp, result);
};

benchmarking("bls_fp_exp", benchmarked_func);
}

// register benchmarking functions
void bls_benchmarking() {
benchmark_bls_g1_add();
Expand All @@ -357,10 +431,14 @@ void bls_benchmarking() {
benchmark_bls_pairing_three_pair();
benchmark_bls_g1_weighted_sum_one_point();
benchmark_bls_g1_weighted_sum_three_point();
benchmark_bls_g1_weighted_sum_five_point();
benchmark_bls_g2_weighted_sum_one_point();
benchmark_bls_g2_weighted_sum_three_point();
benchmark_bls_g2_weighted_sum_five_point();
benchmark_bls_g1_map();
benchmark_bls_g2_map();
benchmark_bls_fp_mod();
benchmark_bls_fp_mul();
benchmark_bls_fp_exp();
}
} // namespace benchmark

0 comments on commit cc9bba8

Please sign in to comment.