// Copyright (c) 2021 Zano Project (https://zano.org/) // Copyright (c) 2021 sowle (val@zano.org, crypto.sowle@gmail.com) // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #pragma once // calc weighted inner pruduct of av and bv w.r.t. Vandermonde vector (y, y^2, y^3, ..., y^n) // = (<> -- standard inner product, o - componen-wise) // s.a. BP+ paper, pages 3-4 bool wip_vandermonde(const scalar_vec_t& av, const scalar_vec_t& bv, const scalar_t& y, scalar_t& result) { result = 0; size_t n = av.size(); if (n != bv.size()) return false; scalar_t y_powered = 1; for (size_t i = 0; i < n; ++i) { y_powered *= y; result.assign_muladd(av[i] * bv[i], y_powered, result); // result.a += av[i] * bv[i] * y_powered; } return true; } static_assert(constexpr_floor_log2(0) == 0, ""); static_assert(constexpr_floor_log2(1) == 0, ""); static_assert(constexpr_floor_log2(2) == 1, ""); static_assert(constexpr_floor_log2(3) == 1, ""); static_assert(constexpr_floor_log2(4) == 2, ""); static_assert(constexpr_floor_log2(5) == 2, ""); static_assert(constexpr_floor_log2(64) == 6, ""); static_assert(constexpr_floor_log2(100) == 6, ""); static_assert(constexpr_floor_log2(100000000) == 26, ""); static_assert(constexpr_floor_log2(0x7fffffffffffffff) == 62, ""); static_assert(constexpr_floor_log2(SIZE_MAX) == 63, ""); static_assert(constexpr_ceil_log2(0) == 0, ""); static_assert(constexpr_ceil_log2(1) == 0, ""); static_assert(constexpr_ceil_log2(2) == 1, ""); static_assert(constexpr_ceil_log2(3) == 2, ""); static_assert(constexpr_ceil_log2(4) == 2, ""); static_assert(constexpr_ceil_log2(5) == 3, ""); static_assert(constexpr_ceil_log2(64) == 6, ""); static_assert(constexpr_ceil_log2(100) == 7, ""); static_assert(constexpr_ceil_log2(100000000) == 27, ""); static_assert(constexpr_ceil_log2(0x7fffffffffffffff) == 63, ""); static_assert(constexpr_ceil_log2(SIZE_MAX) == 64, ""); TEST(bpp, basics) { /* srand(0); for (size_t i = 0; i < 10; ++i) std::cout << scalar_t::random().to_string_as_secret_key() << ENDL; */ point_t H = hash_helper_t::hp(c_point_G); ASSERT_EQ(H, c_point_H); std::string h2_hash_str("h2_generator"); point_t H2 = hash_helper_t::hp(h2_hash_str.c_str(), h2_hash_str.size()); ASSERT_EQ(H2, c_point_H2); LOG_PRINT_L0("c_point_0 = " << c_point_0 << " = { " << c_point_0.to_hex_comma_separated_uint64_str() << " }"); LOG_PRINT_L0("Zano G = " << c_point_G << " = { " << c_point_G.to_hex_comma_separated_bytes_str() << " }"); LOG_PRINT_L0("Zano H = " << H << " = { " << H.to_hex_comma_separated_uint64_str() << " }"); LOG_PRINT_L0("Zano H2 = " << H2 << " = { " << H2.to_hex_comma_separated_uint64_str() << " }"); auto foo = [&](scalar_t v){ scalar_vec_t values = { v }; scalar_vec_t masks = { scalar_t::random() }; bpp_signature bpp_sig; std::vector commitments_1div8; uint8_t err = 0; bool r = bpp_gen>(values, masks, bpp_sig, commitments_1div8, &err); if (!r) { LOG_PRINT_L0("bpp_gen err = " << (uint16_t)err); return false; } std::vector sigs; sigs.emplace_back(bpp_sig, commitments_1div8); r = bpp_verify>(sigs, &err); if (!r) { LOG_PRINT_L0("bpp_verify err = " << (uint16_t)err); return false; } return true; }; ASSERT_TRUE(foo(scalar_t(0))); ASSERT_TRUE(foo(scalar_t(1))); ASSERT_TRUE(foo(scalar_t(5))); ASSERT_TRUE(foo(scalar_t(UINT64_MAX))); ASSERT_FALSE(foo(scalar_t(UINT64_MAX, 1, 0, 0))); ASSERT_FALSE(foo(scalar_t(0, 1, 0, 0))); ASSERT_FALSE(foo(scalar_t(0, 0, 1, 0))); ASSERT_FALSE(foo(scalar_t(0, 0, 0, 1))); ASSERT_FALSE(foo(c_scalar_Lm1)); ASSERT_FALSE(foo(c_scalar_L)); ASSERT_FALSE(foo(c_scalar_256m1)); return true; } TEST(bpp, two) { std::vector signatures_vector; signatures_vector.reserve(10); std::vector> commitments_vector; commitments_vector.reserve(10); std::vector sigs; uint8_t err = 0; bool r = false; { signatures_vector.resize(signatures_vector.size() + 1); bpp_signature &bpp_sig = signatures_vector.back(); commitments_vector.resize(commitments_vector.size() + 1); std::vector& commitments = commitments_vector.back(); scalar_vec_t values = { 5 }; scalar_vec_t masks = { scalar_t(77 + 256 * 77) }; r = bpp_gen>(values, masks, bpp_sig, commitments, &err); ASSERT_TRUE(r); sigs.emplace_back(bpp_sig, commitments); } { signatures_vector.resize(signatures_vector.size() + 1); bpp_signature &bpp_sig = signatures_vector.back(); commitments_vector.resize(commitments_vector.size() + 1); std::vector& commitments = commitments_vector.back(); scalar_vec_t values = { 5, 700, 8 }; scalar_vec_t masks = { scalar_t(77 + 256 * 77), scalar_t(255), scalar_t(17) }; r = bpp_gen>(values, masks, bpp_sig, commitments, &err); ASSERT_TRUE(r); sigs.emplace_back(bpp_sig, commitments); } r = bpp_verify>(sigs, &err); ASSERT_TRUE(r); return true; } TEST(bpp, power_256) { // make sure the BPP implementation supports values up to 2^256 (Zarcanum needs 2^170 since b_a < z * 2^64, where z = 2^106, s.a. Zarcanum preprint, page 21) std::vector signatures_vector; signatures_vector.reserve(10); std::vector> commitments_vector; commitments_vector.reserve(10); std::vector sig_commit_refs; uint8_t err = 0; bool r = false; { signatures_vector.resize(signatures_vector.size() + 1); bpp_signature &bpp_sig = signatures_vector.back(); commitments_vector.resize(commitments_vector.size() + 1); std::vector& commitments = commitments_vector.back(); scalar_vec_t values = { 5 }; scalar_vec_t masks = { scalar_t(77 + 256 * 77) }; r = bpp_gen>(values, masks, bpp_sig, commitments, &err); ASSERT_TRUE(r); sig_commit_refs.emplace_back(bpp_sig, commitments); } { signatures_vector.resize(signatures_vector.size() + 1); bpp_signature &bpp_sig = signatures_vector.back(); commitments_vector.resize(commitments_vector.size() + 1); std::vector& commitments = commitments_vector.back(); scalar_vec_t values = { 5, 700, 8 }; scalar_vec_t masks = { scalar_t(77 + 256 * 77), scalar_t(255), scalar_t(17) }; r = bpp_gen>(values, masks, bpp_sig, commitments, &err); ASSERT_TRUE(r); sig_commit_refs.emplace_back(bpp_sig, commitments); } r = bpp_verify>(sig_commit_refs, &err); ASSERT_TRUE(r); return true; } // // tests for Bulletproofs+ Extended (with double-blinded commitments) // TEST(bppe, basics) { /* srand(0); for (size_t i = 0; i < 10; ++i) std::cout << scalar_t::random().to_string_as_secret_key() << ENDL; */ scalar_vec_t values = { 5 }; scalar_vec_t masks = { 0 }; scalar_vec_t masks_2 = { 0 }; bppe_signature bppe_sig; std::vector commitments; uint8_t err = 0; bool r = bppe_gen>(values, masks, masks_2, bppe_sig, commitments, &err); ASSERT_TRUE(r); return true; } TEST(bppe, two) { std::vector signatures_vector; signatures_vector.reserve(10); std::vector> commitments_vector; commitments_vector.reserve(10); std::vector sigs; uint8_t err = 0; bool r = false; { signatures_vector.resize(signatures_vector.size() + 1); bppe_signature &bppe_sig = signatures_vector.back(); commitments_vector.resize(commitments_vector.size() + 1); std::vector& commitments = commitments_vector.back(); scalar_vec_t values = { 5 }; scalar_vec_t masks = { scalar_t(77 + 256 * 77) }; scalar_vec_t masks2 = { scalar_t(88 + 256 * 88) }; r = bppe_gen>(values, masks, masks2, bppe_sig, commitments, &err); ASSERT_TRUE(r); sigs.emplace_back(bppe_sig, commitments); } { signatures_vector.resize(signatures_vector.size() + 1); bppe_signature &bppe_sig = signatures_vector.back(); commitments_vector.resize(commitments_vector.size() + 1); std::vector& commitments = commitments_vector.back(); scalar_vec_t values = { 5, 700, 8 }; scalar_vec_t masks = { scalar_t(77 + 256 * 77), scalar_t(255), scalar_t(17) }; scalar_vec_t masks2 = { scalar_t(88 + 256 * 88), scalar_t(1), scalar_t(19) }; r = bppe_gen>(values, masks, masks2, bppe_sig, commitments, &err); ASSERT_TRUE(r); sigs.emplace_back(bppe_sig, commitments); } r = bppe_verify>(sigs, &err); ASSERT_TRUE(r); return true; } TEST(bppe, power_128) { std::vector signatures_vector; signatures_vector.reserve(200); std::vector> commitments_vector; commitments_vector.reserve(200); std::vector sigs; uint8_t err = 0; bool r = false; auto gen_rp_for_vec = [&](const scalar_vec_t& values) { signatures_vector.resize(signatures_vector.size() + 1); bppe_signature &bppe_sig = signatures_vector.back(); commitments_vector.resize(commitments_vector.size() + 1); std::vector& commitments = commitments_vector.back(); scalar_vec_t masks, masks2; for(auto& el: values) { masks.emplace_back(scalar_t::random()); masks2.emplace_back(scalar_t::random()); } r = bppe_gen>(values, masks, masks2, bppe_sig, commitments, &err); ASSERT_TRUE(r); sigs.emplace_back(bppe_sig, commitments); return true; }; auto gen_rp_for_value = [&](const scalar_t& v) { return gen_rp_for_vec(scalar_vec_t{ v }); }; const scalar_t s_128_max = scalar_t(UINT64_MAX, UINT64_MAX, 0, 0); LOG_PRINT_L0("1"); ASSERT_TRUE(gen_rp_for_value(s_128_max)); ASSERT_TRUE(bppe_verify>(sigs, &err)); signatures_vector.clear(), commitments_vector.clear(), sigs.clear(); LOG_PRINT_L0("2"); ASSERT_TRUE(gen_rp_for_value(scalar_t(crypto::rand(), crypto::rand(), 0, 0))); ASSERT_TRUE(bppe_verify>(sigs, &err)); signatures_vector.clear(), commitments_vector.clear(), sigs.clear(); LOG_PRINT_L0("3"); ASSERT_TRUE(gen_rp_for_value(scalar_t(0, 0, 1, 0))); ASSERT_FALSE(bppe_verify>(sigs, &err)); signatures_vector.clear(), commitments_vector.clear(), sigs.clear(); LOG_PRINT_L0("4"); ASSERT_TRUE(gen_rp_for_value(scalar_t(0, 0, crypto::rand(), 0))); ASSERT_FALSE(bppe_verify>(sigs, &err)); signatures_vector.clear(), commitments_vector.clear(), sigs.clear(); LOG_PRINT_L0("5"); ASSERT_TRUE(gen_rp_for_value(scalar_t(0, 0, 0, crypto::rand()))); ASSERT_FALSE(bppe_verify>(sigs, &err)); signatures_vector.clear(), commitments_vector.clear(), sigs.clear(); LOG_PRINT_L0("6"); ASSERT_TRUE(gen_rp_for_value(scalar_t(0, 0, 0, UINT64_MAX))); ASSERT_FALSE(bppe_verify>(sigs, &err)); signatures_vector.clear(), commitments_vector.clear(), sigs.clear(); LOG_PRINT_L0("7"); ASSERT_TRUE(gen_rp_for_vec(scalar_vec_t{s_128_max, s_128_max, s_128_max, s_128_max})); LOG_PRINT_L0("simple generated"); ASSERT_TRUE(bppe_verify>(sigs, &err)); LOG_PRINT_L0("simple verified"); for(size_t i = 0; i < 16; ++i) { LOG_PRINT_L0(" #" << i << " simple generated"); scalar_vec_t vec; for(size_t j = 0, n = crypto::rand() % 4 + 1; j < n; ++j) vec.emplace_back(scalar_t(crypto::rand(), crypto::rand(), 0, 0)); ASSERT_TRUE(gen_rp_for_vec(vec)); } LOG_PRINT_L0("verification started"); ASSERT_TRUE(bppe_verify>(sigs, &err)); signatures_vector.clear(), commitments_vector.clear(), sigs.clear(); LOG_PRINT_L0("verification finished" << ENDL); LOG_PRINT_L0("8"); ASSERT_TRUE(gen_rp_for_value(s_128_max)); ASSERT_TRUE(gen_rp_for_value(scalar_t(0, 0, 0, UINT64_MAX))); ASSERT_TRUE(gen_rp_for_value(s_128_max)); ASSERT_FALSE(bppe_verify>(sigs, &err)); signatures_vector.clear(), commitments_vector.clear(), sigs.clear(); return true; }