diff --git a/bandersnatch/CMakeLists.txt b/bandersnatch/CMakeLists.txt index 2c8e3dd..90cedbc 100644 --- a/bandersnatch/CMakeLists.txt +++ b/bandersnatch/CMakeLists.txt @@ -6,7 +6,7 @@ file(GLOB_RECURSE SRCS bandersnatch/*.cpp) file(GLOB_RECURSE HEADERS bandersnatch/*.h) add_library(bandersnatch ${SRCS} ${HEADERS}) -target_link_directories(bandersnatch PUBLIC bandersnatch) +target_include_directories(bandersnatch PUBLIC .) target_link_libraries(bandersnatch PUBLIC blst) if (TESTS) diff --git a/bandersnatch/bandersnatch/Element.cpp b/bandersnatch/bandersnatch/Element.cpp index 518c16f..5280b5c 100644 --- a/bandersnatch/bandersnatch/Element.cpp +++ b/bandersnatch/bandersnatch/Element.cpp @@ -50,7 +50,7 @@ Element& Element::mult(const Fr& fr) return *this; } -Element Element::msm(Element::ElementListPtr points, Fr::FrListPtr scalars) +Element Element::msm(const ElementListPtr& points, const Fr::FrListPtr& scalars) { if (points->size() != scalars->size()) { throw std::runtime_error("points and scalars have different sizes, " + @@ -63,29 +63,21 @@ Element Element::msm(Element::ElementListPtr points, Fr::FrListPtr scalars) // By now we use Pippenger's algorithm to accelerate MSM (Multi-Scalar Multiplication). // It is implemented in blst lib. auto sz = blst_p1s_mult_pippenger_scratch_sizeof(points->size()); - std::unique_ptr scratch{new limb_t[sz/sizeof(limb_t)]}; - - auto* affinePoints = new blst_p1_affine[n]; - auto* baseScalars = new byte* [n]; + limb_t scratch[sz/sizeof(limb_t)]; + blst_p1_affine affinePoints[n]; + blst_scalar baseScalars[n]; for (auto i = 0; i < n; ++i) { blst_p1_to_affine(&affinePoints[i], &points->at(i).m_point); - - blst_scalar tmp; - blst_scalar_from_fr(&tmp, &scalars->at(i).m_val); - baseScalars[i] = tmp.b; + blst_scalar_from_fr(&baseScalars[i], &scalars->at(i).m_val); } - Element ret; - blst_p1s_mult_pippenger(&ret.m_point, &affinePoints, n, baseScalars, 255, scratch.get()); + const blst_p1_affine* pointsArg[2] = {affinePoints, nullptr}; + const byte* scalarsArg[2] = {reinterpret_cast(baseScalars), nullptr}; - for (size_t i = 0; i < n; ++i) - { - delete[] baseScalars[i]; - } - delete[] affinePoints; - delete[] baseScalars; + Element ret; + blst_p1s_mult_pippenger(&ret.m_point, pointsArg, n, scalarsArg, 255, scratch); return ret; } @@ -100,6 +92,14 @@ bool Element::operator!=(const Element& other) const return !(*this == other); } +Element Element::zero() +{ + // Identity/infinity of G1. + Element ret; + memset(&ret.m_point, 0, sizeof(ret.m_point)); + return ret; +} + Element Element::add(const Element& a, const Element& b) { Element ret; diff --git a/bandersnatch/bandersnatch/Element.h b/bandersnatch/bandersnatch/Element.h index 3b13bfc..da6ab0a 100644 --- a/bandersnatch/bandersnatch/Element.h +++ b/bandersnatch/bandersnatch/Element.h @@ -26,10 +26,11 @@ class Element bool operator==(const Element& other) const; bool operator!=(const Element& other) const; + static Element zero(); static Element add(const Element& a, const Element& b); static Element dbl(const Element& a); static Element mult(const Fr& fr, const Element& a); - static Element msm(Element::ElementListPtr points, Fr::FrListPtr scalars); + static Element msm(const Element::ElementListPtr& points, const Fr::FrListPtr& scalars); static Element generator(); diff --git a/bandersnatch/bandersnatch/Fr.cpp b/bandersnatch/bandersnatch/Fr.cpp index 089a0cf..a0254e0 100644 --- a/bandersnatch/bandersnatch/Fr.cpp +++ b/bandersnatch/bandersnatch/Fr.cpp @@ -73,7 +73,7 @@ Fr Fr::random() Fr Fr::fromUint64(uint64_t v) { uint64_t a[4] = {v}; - return {a}; + return Fr(a); } uint64_t Fr::toUint64() const diff --git a/bandersnatch/bandersnatch/Fr.h b/bandersnatch/bandersnatch/Fr.h index 4fd274c..6b60a00 100644 --- a/bandersnatch/bandersnatch/Fr.h +++ b/bandersnatch/bandersnatch/Fr.h @@ -19,7 +19,7 @@ class Fr Fr& operator=(const Fr& other); // deserialize - Fr(const uint64_t a[4]); + explicit Fr(const uint64_t a[4]); Fr(const byte* msg, size_t nbits); static Fr zero(); diff --git a/bandersnatch/test/unittests/ElementTest.cpp b/bandersnatch/test/unittests/ElementTest.cpp index 6b6adae..f00fcc5 100644 --- a/bandersnatch/test/unittests/ElementTest.cpp +++ b/bandersnatch/test/unittests/ElementTest.cpp @@ -71,6 +71,27 @@ BOOST_AUTO_TEST_CASE(testMult) BOOST_ASSERT(g2 == exp); } +BOOST_AUTO_TEST_CASE(testMsm) +{ + auto scalars = std::make_shared>(256); + auto points = std::make_shared>(256); + auto exp = bandersnatch::Element::zero(); + for (size_t i = 0; i < 256; ++i) + { + auto randomFr = bandersnatch::Fr::random(); + auto randomPoint = bandersnatch::Element::generator().mult(randomFr); + + // naive sum of multiple multiplication + exp.add(bandersnatch::Element::mult(randomFr, randomPoint)); + + scalars->at(i) = randomFr; + points->at(i) = randomPoint; + } + + auto res = bandersnatch::Element::msm(points, scalars); + BOOST_ASSERT(res == exp); +} + BOOST_AUTO_TEST_CASE(testEqual) { uint8_t raw[96] = { diff --git a/common/common/Common.h b/common/common/Common.h index 8890505..2689e15 100644 --- a/common/common/Common.h +++ b/common/common/Common.h @@ -3,8 +3,15 @@ // #pragma once #include +#include +#include namespace verkle::common { constexpr size_t vectorLength = 256; + + using byte = uint8_t; + using bytes = std::vector; + using bytesPtr = std::shared_ptr>; + } \ No newline at end of file diff --git a/ipa/CMakeLists.txt b/ipa/CMakeLists.txt index 6dd23f9..cf6b35e 100644 --- a/ipa/CMakeLists.txt +++ b/ipa/CMakeLists.txt @@ -5,7 +5,7 @@ file(GLOB_RECURSE HEADERS ipa/*.h) add_library(ipa ${SRCS} ${HEADERS}) add_dependencies(ipa bandersnatch utilities common) -target_include_directories(ipa PUBLIC ../bandersnatch ipa) +target_include_directories(ipa PUBLIC .) target_link_libraries(ipa PUBLIC bandersnatch utilities common) if (TESTS) diff --git a/ipa/ipa/IPAProof.cpp b/ipa/ipa/IPAProof.cpp index 7819179..d162db0 100644 --- a/ipa/ipa/IPAProof.cpp +++ b/ipa/ipa/IPAProof.cpp @@ -4,8 +4,8 @@ using namespace verkle::ipa; IPAProof IPAProof::create( - Transcript::Ptr transcript, - IPAConfig::Ptr config, + const Transcript::Ptr& transcript, + const IPAConfig::Ptr& config, Element const& commitment, Fr::FrListPtr& a, Fr const& evalPoint @@ -46,14 +46,14 @@ IPAProof IPAProof::create( auto C_L_1 = commit(G_L, a_R); auto C_L = commit( - std::make_shared>(std::initializer_list{C_L_1, q}), - std::make_shared>(std::initializer_list{Fr::one(), z_L}) + std::make_shared>(std::initializer_list{C_L_1, q}), + std::make_shared>(std::initializer_list{Fr::one(), z_L}) ); auto C_R_1 = commit(G_R, a_L); auto C_R = commit( - std::make_shared>(std::initializer_list{C_R_1, q}), - std::make_shared>(std::initializer_list{Fr::one(), z_R}) + std::make_shared>(std::initializer_list{C_R_1, q}), + std::make_shared>(std::initializer_list{Fr::one(), z_R}) ); L->at(i) = C_L; @@ -82,8 +82,8 @@ IPAProof IPAProof::create( } bool IPAProof::check ( - Transcript::Ptr transcript, - IPAConfig::Ptr config, + const Transcript::Ptr& transcript, + const IPAConfig::Ptr& config, Element& commitment, Fr const& evalPoint, Fr const& result @@ -104,10 +104,72 @@ bool IPAProof::check ( auto w = transcript->generateChallenge(SeperateLabel::LABEL_RESCALING); + // Rescaling of q. auto q = config->m_Q.mult(w); commitment.add(q.mult(result)); - auto + auto challenges = generateChallenges(transcript); + auto invChallenges = std::make_shared>(challenges->size()); + for (size_t i = 0; i < challenges->size(); ++i) + { + invChallenges->at(i) = challenges->at(i).inv(); + } + + // Compute expected commitment + auto elements = std::make_shared>(3); + auto frs = std::make_shared>(3); + for (size_t i = 0; i < challenges->size(); ++i) + { + auto x = challenges->at(i); + auto L = m_left->at(i); + auto R = m_right->at(i); + + elements->clear(); + elements->insert(elements->end(), {commitment, L, R}); + + frs->clear(); + frs->insert(frs->end(), {Fr::one(), x, invChallenges->at(i)}); + } + + auto g = config->m_srs; + + // We compute the folding-scalars for g and b. + auto foldingScalars = std::make_shared>(g->size()); + for (size_t i = 0; i < foldingScalars->size(); ++i) + { + auto scalar = Fr::one(); + + for (size_t challengeIdx = 0; challengeIdx < challenges->size(); ++challengeIdx) + { + if ((i & (1<<(7-challengeIdx))) > 0) + { + scalar *= invChallenges->at(challengeIdx); + } + } + foldingScalars->at(i) = scalar; + } + + auto g0 = Element::msm(g, foldingScalars); + auto b0 = innerProduct(b, foldingScalars); + + auto part1 = g0.mult(m_a); + auto part2 = q.mult(b0*m_a); + auto expected = part1.add(part2); + + return expected == commitment; +} + + +Fr::FrListPtr IPAProof::generateChallenges(Transcript::Ptr const& transcript) const +{ + auto out = std::make_shared>(m_left->size()); + for (size_t i = 0; i < m_left->size(); ++i) + { + transcript->appendPoint(m_left->at(i), SeperateLabel::LABEL_LEFT); + transcript->appendPoint(m_right->at(i), SeperateLabel::LABEL_RIGHT); + out->at(i) = transcript->generateChallenge(SeperateLabel::LABEL_X); + } + return out; } \ No newline at end of file diff --git a/ipa/ipa/IPAProof.h b/ipa/ipa/IPAProof.h index bb032d4..775450c 100644 --- a/ipa/ipa/IPAProof.h +++ b/ipa/ipa/IPAProof.h @@ -9,25 +9,29 @@ using verkle::bandersnatch::Element; namespace verkle::ipa { -struct IPAProof +class IPAProof { - Element::ElementListPtr m_left; - Element::ElementListPtr m_right; - Fr m_a; - +public: static IPAProof create( - Transcript::Ptr transcript, - IPAConfig::Ptr config, + const Transcript::Ptr& transcript, + const IPAConfig::Ptr& config, Element const& commitment, Fr::FrListPtr& a, Fr const& evalPoint ); bool check( - Transcript::Ptr transcript, - IPAConfig::Ptr config, + const Transcript::Ptr& transcript, + const IPAConfig::Ptr& config, Element& commitment, Fr const& evalPoint, Fr const& result ) const; + +private: + Element::ElementListPtr m_left; + Element::ElementListPtr m_right; + Fr m_a; + + Fr::FrListPtr generateChallenges(Transcript::Ptr const& transcript) const; }; } \ No newline at end of file diff --git a/ipa/ipa/IPAUtility.cpp b/ipa/ipa/IPAUtility.cpp index 3d053bd..21f1efd 100644 --- a/ipa/ipa/IPAUtility.cpp +++ b/ipa/ipa/IPAUtility.cpp @@ -1,79 +1,92 @@ #include "IPAUtility.h" -using namespace verkle::ipa; - -Fr innerProduct(Fr::FrListPtr const& a, Fr::FrListPtr const& b) +namespace verkle::ipa { - if (a->size() != b->size()) { - throw std::runtime_error("a and b are different sizes, " + - std::to_string(a->size()) + " != " + std::to_string(b->size())); - } + Fr::FrListPtr powers(Fr const& x, size_t degree) + { + auto res = std::make_shared>(degree); + res->at(0) = Fr::one(); - auto ret = Fr::zero(); - for (size_t i = 0; i < a->size(); ++i) { - ret += a->at(i) * b->at(i); + for (size_t i = 1; i < degree; ++i) + { + res->at(i) = res->at(i-1) * x; + } + return res; } - return ret; -} - -template -void splitSlice(T a, T& out1, T& out2) -{ - if (a->size()%2 != 0) + Fr innerProduct(Fr::FrListPtr const& a, Fr::FrListPtr const& b) { - throw std::runtime_error("scalars or elements should have even length"); + if (a->size() != b->size()) { + throw std::runtime_error("a and b are different sizes, " + + std::to_string(a->size()) + " != " + std::to_string(b->size())); + } + + auto ret = Fr::zero(); + for (size_t i = 0; i < a->size(); ++i) { + ret += a->at(i) * b->at(i); + } + + return ret; } - auto mid = a->size() / 2; + template + void split(T a, T& out1, T& out2) + { + if (a->size()%2 != 0) + { + throw std::runtime_error("scalars or elements should have even length"); + } - std::vector first(mid); - std::vector second(a->size()-mid); + auto mid = a->size() / 2; - std::move(a->begin(), a->begin()+mid, first.begin()); - std::move(a->begin()+mid, a->end(), second.begin()); + std::vector first(mid); + std::vector second(a->size()-mid); - out1 = std::make_shared(first); - out2 = std::make_shared(second); -} + std::move(a->begin(), a->begin()+mid, first.begin()); + std::move(a->begin()+mid, a->end(), second.begin()); -Element commit(Element::ElementListPtr const& groupElements, Fr::FrListPtr const& polynomial) -{ - if (groupElements->size() != polynomial->size()) { - throw std::runtime_error("group elements and polynomial are different sizes, " + - std::to_string(groupElements->size()) + " != " + std::to_string(polynomial->size())); + out1 = std::make_shared(first); + out2 = std::make_shared(second); } - return Element::msm(groupElements, polynomial); -} + Element commit(Element::ElementListPtr const& groupElements, Fr::FrListPtr const& polynomial) + { + if (groupElements->size() != polynomial->size()) { + throw std::runtime_error("group elements and polynomial are different sizes, " + + std::to_string(groupElements->size()) + " != " + std::to_string(polynomial->size())); + } -Fr::FrListPtr foldScalars(Fr::FrListPtr const& a, Fr::FrListPtr const& b, Fr const& x) -{ - if (a->size() != b->size()) { - throw std::runtime_error("a and b are different sizes, " + - std::to_string(a->size()) + " != " + std::to_string(b->size())); + return Element::msm(groupElements, polynomial); } - auto ret = std::make_shared>(a->size()); - for (size_t i = 0; i < a->size(); ++i) + + Fr::FrListPtr foldScalars(Fr::FrListPtr const& a, Fr::FrListPtr const& b, Fr const& x) { - ret->at(i) = a->at(i) + b->at(i) * x; + if (a->size() != b->size()) { + throw std::runtime_error("a and b are different sizes, " + + std::to_string(a->size()) + " != " + std::to_string(b->size())); + } + auto ret = std::make_shared>(a->size()); + for (size_t i = 0; i < a->size(); ++i) + { + ret->at(i) = a->at(i) + b->at(i) * x; + } + return ret; } - return ret; -} -Element::ElementListPtr foldPoints( - Element::ElementListPtr const& a, - Element::ElementListPtr const& b, - Fr const& x) -{ - if (a->size() != b->size()) { - throw std::runtime_error("a and b are different sizes, " + - std::to_string(a->size()) + " != " + std::to_string(b->size())); - } - auto ret = std::make_shared>(a->size()); - for (size_t i = 0; i < a->size(); ++i) + Element::ElementListPtr foldPoints( + Element::ElementListPtr const& a, + Element::ElementListPtr const& b, + Fr const& x) { - ret->at(i) = a->at(i).add(b->at(i).mult(x)); + if (a->size() != b->size()) { + throw std::runtime_error("a and b are different sizes, " + + std::to_string(a->size()) + " != " + std::to_string(b->size())); + } + auto ret = std::make_shared>(a->size()); + for (size_t i = 0; i < a->size(); ++i) + { + ret->at(i) = a->at(i).add(b->at(i).mult(x)); + } + return ret; } - return ret; } diff --git a/ipa/ipa/IPAUtility.h b/ipa/ipa/IPAUtility.h index 1c507e5..0ac5273 100644 --- a/ipa/ipa/IPAUtility.h +++ b/ipa/ipa/IPAUtility.h @@ -15,12 +15,14 @@ namespace verkle::ipa { a->end() } -> std::random_access_iterator; }; + Fr::FrListPtr powers(Fr const& x, size_t degree); + Fr innerProduct(Fr::FrListPtr const& a, Fr::FrListPtr const& b); template void split(T a, T& out1, T& out2); - Element commit(Element::ElementListPtr groupElements, Fr::FrListPtr polynomial); + Element commit(Element::ElementListPtr const& groupElements, Fr::FrListPtr const& polynomial); Fr::FrListPtr foldScalars(Fr::FrListPtr const& a, Fr::FrListPtr const& b, Fr const& x); diff --git a/ipa/ipa/PrecomputedFrs.cpp b/ipa/ipa/PrecomputedFrs.cpp index b8982a4..cd42991 100644 --- a/ipa/ipa/PrecomputedFrs.cpp +++ b/ipa/ipa/PrecomputedFrs.cpp @@ -64,12 +64,16 @@ Fr PrecomputedFrs::computeBarycentricWeightForElement(uint64_t element) continue; } - auto fr_i = Fr::fromUint64(i); - total *= domainEle - fr_i; + total *= domainEle - Fr::fromUint64(i); } return total; +} +Fr PrecomputedFrs::getInversedBarycentricWeight(size_t index) const +{ + auto const mid = m_barycentricWeights->size() / 2; + return m_barycentricWeights->at(index+mid); } // ComputeBarycentricCoefficients, computes the coefficients `bary_coeffs` diff --git a/ipa/ipa/PrecomputedFrs.h b/ipa/ipa/PrecomputedFrs.h index 5a003b6..b17807d 100644 --- a/ipa/ipa/PrecomputedFrs.h +++ b/ipa/ipa/PrecomputedFrs.h @@ -18,6 +18,7 @@ namespace verkle::ipa PrecomputedFrs(); [[nodiscard]] Fr::FrListPtr computeBarycentricCoefficients(const Fr& point) const; + [[nodiscard]] Fr getInversedBarycentricWeight(size_t index) const; static Fr computeBarycentricWeightForElement(uint64_t element); diff --git a/ipa/ipa/Transcript.cpp b/ipa/ipa/Transcript.cpp index ee3bdd1..89ec748 100644 --- a/ipa/ipa/Transcript.cpp +++ b/ipa/ipa/Transcript.cpp @@ -60,15 +60,3 @@ verkle::bandersnatch::Fr Transcript::generateChallenge(SeperateLabel label) return ret; } - -verkle::bandersnatch::Fr::FrListPtr Transcript::generateChallengeByProof(IPAProof const& proof) -{ - auto out = std::make_shared>(proof.m_left->size()); - for (size_t i = 0; i < proof.m_left->size(); ++i) - { - appendPoint(proof.m_left->at(i), SeperateLabel::LABEL_LEFT); - appendPoint(proof.m_right->at(i), SeperateLabel::LABEL_RIGHT); - out->at(i) = generateChallenge(SeperateLabel::LABEL_X); - } - return out; -} \ No newline at end of file diff --git a/ipa/ipa/Transcript.h b/ipa/ipa/Transcript.h index c1ae0e5..bef5a24 100644 --- a/ipa/ipa/Transcript.h +++ b/ipa/ipa/Transcript.h @@ -3,11 +3,8 @@ #include "bandersnatch/Element.h" #include "verkleutils/Hash.h" #include -#include #include -#include "IPAProof.h" - namespace verkle::ipa { enum class SeperateLabel @@ -25,21 +22,21 @@ enum class SeperateLabel // The transcript is for challenge scalars generation. class Transcript { -private: - std::stringstream m_buffer; - utils::Hash m_state; - static const std::unordered_map labelValues; - static const char* getLabelValue(const SeperateLabel& label); - public: using Ptr = std::shared_ptr; + Transcript(SeperateLabel label); + void appendLabel(SeperateLabel label); void appendScalar(const bandersnatch::Fr& scalar, SeperateLabel label); void appendPoint(const bandersnatch::Element& point, SeperateLabel label); - bandersnatch::Fr generateChallenge(SeperateLabel label); - bandersnatch::Fr::FrListPtr generateChallengeByProof(IPAProof const& proof); + +private: + std::stringstream m_buffer; + utils::Hash m_state; + static const std::unordered_map labelValues; + static const char* getLabelValue(const SeperateLabel& label); }; inline const std::unordered_map Transcript::labelValues = { diff --git a/ipa/test/CMakeLists.txt b/ipa/test/CMakeLists.txt index 548508b..09f8829 100644 --- a/ipa/test/CMakeLists.txt +++ b/ipa/test/CMakeLists.txt @@ -1,9 +1,10 @@ +file(GLOB_RECURSE TEST_HEADERS "*.h") file(GLOB_RECURSE TEST_SRCS "*.cpp") -add_executable(ipa-test ${TEST_SRCS}) -target_include_directories(ipa-test PRIVATE . ..) +add_executable(ipa-test ${TEST_HEADERS} ${TEST_SRCS}) +target_include_directories(ipa-test PRIVATE .) find_package(boost_unit_test_framework CONFIG REQUIRED) -target_link_libraries(ipa-test PRIVATE utilities ipa Boost::unit_test_framework) +target_link_libraries(ipa-test PRIVATE ipa Boost::unit_test_framework) add_test(NAME test-bandersnatch WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} COMMAND ipa-test) \ No newline at end of file diff --git a/ipa/test/PrecomputedFrsTest.cpp b/ipa/test/PrecomputedFrsTest.cpp new file mode 100644 index 0000000..94a007f --- /dev/null +++ b/ipa/test/PrecomputedFrsTest.cpp @@ -0,0 +1,62 @@ +// +// Created by Zhengxuan Guo on 2024/8/29. +// +#include "Utility.h" +#include "testutils/TestPromptFixture.h" +#include + +#include "ipa/IPAUtility.h" +#include "ipa/PrecomputedFrs.h" + +namespace verkle::ipa::test +{ + BOOST_FIXTURE_TEST_SUITE(PrecomputedFrsTest, verkle::test::TestPromptFixture) + + BOOST_AUTO_TEST_CASE(TestInterpolate) + { + auto a = FrPoint(Fr::zero(), Fr::zero()); + auto b = FrPoint(Fr::one(), Fr::one()); + auto points = FrPoints(2); + points.m_inner->at(0) = a; + points.m_inner->at(1) = b; + + auto poly = points.interpolate(); + + auto randomFr = Fr::random(); + auto res = evalPoly(poly, randomFr); + + BOOST_ASSERT(res == randomFr); + } + + BOOST_AUTO_TEST_CASE(TestComputeBarycentricCoefficients) + { + auto outsidePoint = Fr::fromUint64(3400); + auto lagrangeFrs = testPoly256(std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); + + auto precomputed = PrecomputedFrs(); + + auto barCoeffs = precomputed.computeBarycentricCoefficients(outsidePoint); + auto got = innerProduct(lagrangeFrs, barCoeffs); + + auto exp = evalOutsideDomain(precomputed, lagrangeFrs, outsidePoint); + + auto points = FrPoints(256); + for (size_t k = 0; k < 256; k++) + { + points.m_inner->at(k) = FrPoint(Fr::fromUint64(k), lagrangeFrs->at(k)); + } + auto polyCoeff = points.interpolate(); + auto exp2 = evalPoly(polyCoeff, outsidePoint); + + if (exp2 != exp) + { + BOOST_FAIL("problem with barycentric weights"); + } + + if (exp2 != got) { + BOOST_FAIL("problem with inner product"); + } + } + + BOOST_AUTO_TEST_SUITE_END() +} diff --git a/ipa/test/Utility.cpp b/ipa/test/Utility.cpp new file mode 100644 index 0000000..78cc754 --- /dev/null +++ b/ipa/test/Utility.cpp @@ -0,0 +1,143 @@ +// +// Created by Zhengxuan Guo on 2024/8/29. +// +#include "Utility.h" +#include "ipa/IPAUtility.h" +#include + +namespace verkle::ipa::test +{ + Fr::FrListPtr testPoly256(std::vector const& polynomial) + { + auto n = polynomial.size(); + + if (n > 256) + { + BOOST_ERROR("polynomial cannot exceed 256 coefficients"); + } + + auto frs = std::make_shared>(256); + for (size_t i = 0; i < n; ++i) + { + frs->at(i) = Fr::fromUint64(polynomial[i]); + } + + for (size_t i = n; i < 256; ++i) + { + frs->at(i) = Fr::zero(); + } + + return frs; + } + + Fr evalOutsideDomain(PrecomputedFrs const& precomputed, Fr::FrListPtr f, Fr const& point) + { + auto pointsMinusDomain = std::vector(verkle::ipa::domainSize); + for (size_t i = 0; i < verkle::ipa::domainSize; ++i) + { + auto fr_i = Fr::fromUint64(i); + pointsMinusDomain[i] = (point - fr_i).inv(); + } + + auto summand = Fr::zero(); + for (size_t i = 0; i < pointsMinusDomain.size(); ++i) + { + auto weight = precomputed.getInversedBarycentricWeight(i); + summand += weight * f->at(i) * pointsMinusDomain[i]; + } + + auto a_z = Fr::one(); + for (size_t i = 0; i < verkle::ipa::domainSize; ++i) + { + a_z *= point - Fr::fromUint64(i); + } + a_z *= summand; + + return a_z; + } + + Fr evalPoly(const Fr::FrListPtr& poly, const Fr& evalPoint) + { + auto powers = verkle::ipa::powers(evalPoint, poly->size()); + auto total = Fr::zero(); + for (size_t i = 0; i < poly->size(); ++i) + { + total += powers->at(i) * poly->at(i); + } + return total; + } + + FrPoints::FrPoints(size_t size) : m_inner(std::make_shared>(size)) {} + + Fr::FrListPtr FrPoints::interpolate() const + { + auto one = Fr::one(); + auto zero = Fr::zero(); + + auto degreePlusOne = m_inner->size(); + if (degreePlusOne < 2) + { + BOOST_ERROR("should interpolate for degree >= 1"); + } + auto coeffs = std::make_shared>(degreePlusOne); + + for (size_t k = 0; k < m_inner->size(); k++) + { + auto [x_k, y_k] = m_inner->at(k); + auto contribution = std::vector(degreePlusOne); + auto denominator = Fr::one(); + auto contributionDegree = 0; + + for (size_t j = 0; j < m_inner->size(); j++) + { + auto x_j = m_inner->at(j).first; + + if (j == k) + { + continue; + } + + denominator *= x_k - x_j; + + if (contributionDegree == 0) + { + contributionDegree = 1; + contribution.at(0) -= x_j; + contribution.at(1) += one; + } else + { + auto mul_by_minus_x_j = std::vector(contribution.size()); + for (size_t i = 0; i < contribution.size(); ++i) + { + mul_by_minus_x_j[i] = zero - contribution[i] * x_j; + } + + contribution.insert(contribution.begin(), zero); + contribution.resize(degreePlusOne); + + if (degreePlusOne != mul_by_minus_x_j.size()) + { + BOOST_ERROR("malformed mul_by_minus_x_j"); + } + + for (size_t i = 0; i < contribution.size(); ++i) + { + contribution[i] += mul_by_minus_x_j[i]; + } + } + } + + denominator = denominator.inv(); + if (denominator == zero) + { + BOOST_ERROR("denominator should not be zero"); + } + for (size_t i = 0; i < contribution.size(); ++i) + { + coeffs->at(i) += contribution[i] * denominator * y_k; + } + } + + return coeffs; + } +} \ No newline at end of file diff --git a/ipa/test/Utility.h b/ipa/test/Utility.h new file mode 100644 index 0000000..8ec18fa --- /dev/null +++ b/ipa/test/Utility.h @@ -0,0 +1,24 @@ +// +// Created by Zhengxuan Guo on 2024/8/29. +// +#pragma once +#include "ipa/PrecomputedFrs.h" +#include "bandersnatch/Fr.h" + +using verkle::bandersnatch::Fr; + +namespace verkle::ipa::test +{ + Fr::FrListPtr testPoly256(std::vector const& polynomial); + Fr evalOutsideDomain(PrecomputedFrs const& precomputed, Fr::FrListPtr f, Fr const& point); + Fr evalPoly(Fr::FrListPtr const& poly, Fr const& evalPoint); + + using FrPoint = std::pair; + struct FrPoints + { + explicit FrPoints(size_t size); + + std::shared_ptr> m_inner; + [[nodiscard]] Fr::FrListPtr interpolate() const; + }; +} \ No newline at end of file