diff --git a/bandersnatch/bandersnatch/Element.cpp b/bandersnatch/bandersnatch/Element.cpp index 5280b5c..e445d3f 100644 --- a/bandersnatch/bandersnatch/Element.cpp +++ b/bandersnatch/bandersnatch/Element.cpp @@ -22,14 +22,26 @@ Element& Element::operator=(const Element& other) Element::Element(const byte* in, size_t len) { if (len == 0 || len != (in[0]&0x80 ? 48 : 96)) + { throw BLST_BAD_ENCODING; + } + blst_p1_affine a; BLST_ERROR err = blst_p1_deserialize(&a, in); + if (err != BLST_SUCCESS) + { throw err; + } + blst_p1_from_affine(&m_point, &a); } +bool Element::isInG1() const +{ + return blst_p1_on_curve(&m_point) && blst_p1_in_g1(&m_point); +} + Element& Element::add(const Element& other) { blst_p1_add_or_double(&m_point, &m_point, &other.m_point); diff --git a/bandersnatch/bandersnatch/Element.h b/bandersnatch/bandersnatch/Element.h index da6ab0a..c2ed80e 100644 --- a/bandersnatch/bandersnatch/Element.h +++ b/bandersnatch/bandersnatch/Element.h @@ -8,6 +8,7 @@ namespace verkle::bandersnatch { class Fr; +class PrecomputedElements; class Element { @@ -15,7 +16,11 @@ class Element using ElementListPtr = std::shared_ptr>; Element(); + + // deserialize Element(const Element& other); + [[nodiscard]] bool isInG1() const; + Element& operator=(const Element& other); Element(const byte *in, size_t len); @@ -39,5 +44,6 @@ class Element private: blst_p1 m_point; + friend class PrecomputedElements; }; } \ No newline at end of file diff --git a/bandersnatch/bandersnatch/Fr.cpp b/bandersnatch/bandersnatch/Fr.cpp index a0254e0..8ee1fd5 100644 --- a/bandersnatch/bandersnatch/Fr.cpp +++ b/bandersnatch/bandersnatch/Fr.cpp @@ -88,7 +88,9 @@ int Fr::cmp(const Fr& other) const if (m_val.l[i] > other.m_val.l[i]) { return 1; - } else if (m_val.l[i] < other.m_val.l[i]) + } + + if (m_val.l[i] < other.m_val.l[i]) { return -1; } diff --git a/bandersnatch/bandersnatch/Fr.h b/bandersnatch/bandersnatch/Fr.h index 6b60a00..dcece98 100644 --- a/bandersnatch/bandersnatch/Fr.h +++ b/bandersnatch/bandersnatch/Fr.h @@ -3,11 +3,13 @@ // #pragma once #include +#include #include namespace verkle::bandersnatch { class Element; +class PrecomputedElements; class Fr { @@ -49,5 +51,6 @@ class Fr private: blst_fr m_val{}; friend class Element; + friend class PrecomputedElements; }; } \ No newline at end of file diff --git a/bandersnatch/bandersnatch/PrecomputedElements.cpp b/bandersnatch/bandersnatch/PrecomputedElements.cpp new file mode 100644 index 0000000..e74602a --- /dev/null +++ b/bandersnatch/bandersnatch/PrecomputedElements.cpp @@ -0,0 +1,42 @@ +// +// Created by Zhengxuan Guo on 2024/8/30. +// +#include "PrecomputedElements.h" + +using namespace verkle::bandersnatch; + +PrecomputedElements::PrecomputedElements(Element::ElementListPtr const& points, size_t window) + : m_window(window), + m_numPoints(points->size()), + m_table(std::make_shared([window, this]() { + auto const bits = blst_p1s_mult_wbits_precompute_sizeof(window, m_numPoints); + return bits / sizeof(blst_p1_affine); + }())) +{ + blst_p1_affine affinePoints[m_numPoints]; + for (size_t i = 0; i < m_numPoints; ++i) + { + blst_p1_to_affine(&affinePoints[i], &points->at(i).m_point); + } + + const blst_p1_affine* pointsArg[2] = {affinePoints, nullptr}; + blst_p1s_mult_wbits_precompute(m_table.get(), m_window, pointsArg, m_numPoints); +} + +Element PrecomputedElements::msm(Fr::FrListPtr const& scalars) const +{ + size_t sz = blst_p1s_mult_wbits_scratch_sizeof(m_numPoints); + limb_t scratch[sz/sizeof(limb_t)]; + + blst_scalar baseScalars[m_numPoints]; + for (size_t i = 0; i < m_numPoints; ++i) + { + blst_scalar_from_fr(&baseScalars[i], &scalars->at(i).m_val); + } + + Element ret; + const byte* scalarsArg[2] = {reinterpret_cast(baseScalars), nullptr}; + blst_p1s_mult_wbits(&ret.m_point, m_table.get(), m_window, m_numPoints, scalarsArg, 255, scratch); + + return ret; +} \ No newline at end of file diff --git a/bandersnatch/bandersnatch/PrecomputedElements.h b/bandersnatch/bandersnatch/PrecomputedElements.h new file mode 100644 index 0000000..477f980 --- /dev/null +++ b/bandersnatch/bandersnatch/PrecomputedElements.h @@ -0,0 +1,21 @@ +// +// Created by Zhengxuan Guo on 2024/8/30. +// +#pragma once +#include "Element.h" +#include "Fr.h" + +namespace verkle::bandersnatch +{ + class PrecomputedElements { + public: + using Ptr = std::shared_ptr; + explicit PrecomputedElements(Element::ElementListPtr const& points, size_t window); + [[nodiscard]] Element msm(Fr::FrListPtr const& scalars) const; + + private: + size_t m_window; + size_t m_numPoints; + std::shared_ptr m_table; + }; +} diff --git a/bandersnatch/test/unittests/Common.h b/bandersnatch/test/unittests/Common.h index 33a6784..b30446f 100644 --- a/bandersnatch/test/unittests/Common.h +++ b/bandersnatch/test/unittests/Common.h @@ -2,9 +2,9 @@ #include "bandersnatch/Fr.h" #include "bandersnatch/Element.h" -namespace verkle::test +namespace verkle::ipa::test { -static inline const bandersnatch::Fr& FixedFr1() +static const bandersnatch::Fr& FixedFr1() { static uint64_t raw[4] = { 0xe5d76b4ca918a221, @@ -16,7 +16,7 @@ static inline const bandersnatch::Fr& FixedFr1() return fr1; } -static inline const bandersnatch::Fr& FixedFr2() +static const bandersnatch::Fr& FixedFr2() { static uint64_t raw[4] = { 0xd894647091277b9c, @@ -28,7 +28,7 @@ static inline const bandersnatch::Fr& FixedFr2() return fr2; } -static inline const bandersnatch::Element& FixedGenerator() +static const bandersnatch::Element& FixedGenerator() { static auto g = bandersnatch::Element::generator(); return g; diff --git a/bandersnatch/test/unittests/ElementTest.cpp b/bandersnatch/test/unittests/ElementTest.cpp index f00fcc5..a71d1fa 100644 --- a/bandersnatch/test/unittests/ElementTest.cpp +++ b/bandersnatch/test/unittests/ElementTest.cpp @@ -6,9 +6,15 @@ #include #include -namespace verkle::test +namespace verkle::ipa::test { -BOOST_FIXTURE_TEST_SUITE(ElementTest, TestPromptFixture) +BOOST_FIXTURE_TEST_SUITE(ElementTest, verkle::test::TestPromptFixture) + +BOOST_AUTO_TEST_CASE(testInG1) +{ + auto g = bandersnatch::Element::generator(); + BOOST_ASSERT(g.isInG1()); +} BOOST_AUTO_TEST_CASE(testAdd) { diff --git a/bandersnatch/test/unittests/FrTest.cpp b/bandersnatch/test/unittests/FrTest.cpp index ed3014d..0c0a1da 100644 --- a/bandersnatch/test/unittests/FrTest.cpp +++ b/bandersnatch/test/unittests/FrTest.cpp @@ -8,9 +8,9 @@ #include #include -namespace verkle::test +namespace verkle::ipa::test { -BOOST_FIXTURE_TEST_SUITE(FrTest, TestPromptFixture) +BOOST_FIXTURE_TEST_SUITE(FrTest, verkle::test::TestPromptFixture) BOOST_AUTO_TEST_CASE(testFromBytes) { diff --git a/bandersnatch/test/unittests/PrecomputedElementsTest.cpp b/bandersnatch/test/unittests/PrecomputedElementsTest.cpp new file mode 100644 index 0000000..3390ded --- /dev/null +++ b/bandersnatch/test/unittests/PrecomputedElementsTest.cpp @@ -0,0 +1,42 @@ +// +// Created by Zhengxuan Guo on 2024/8/30. +// +#include +#include + +#include "bandersnatch/Fr.h" +#include "bandersnatch/Element.h" +#include "bandersnatch/PrecomputedElements.h" + +using verkle::bandersnatch::Fr; +using verkle::bandersnatch::Element; +using verkle::bandersnatch::PrecomputedElements; + +namespace verkle::ipa::test +{ + BOOST_FIXTURE_TEST_SUITE(ElementTest, verkle::test::TestPromptFixture) + + BOOST_AUTO_TEST_CASE(testPrecomputedMSM) + { + auto scalars = std::make_shared>(256); + auto points = std::make_shared>(256); + auto exp = Element::zero(); + for (size_t i = 0; i < 256; ++i) + { + auto randomFr = bandersnatch::Fr::random(); + auto randomPoint = Element::generator().mult(randomFr); + + // naive sum of multiple multiplication + exp.add(Element::mult(randomFr, randomPoint)); + + scalars->at(i) = randomFr; + points->at(i) = randomPoint; + } + + auto const precomputed = PrecomputedElements(points, 8); + auto const res = precomputed.msm(scalars); + BOOST_ASSERT(res == exp); + } + + BOOST_AUTO_TEST_SUITE_END() +} \ No newline at end of file diff --git a/cmake/ProjectBLST.cmake b/cmake/ProjectBLST.cmake index f2cf910..fb505ad 100644 --- a/cmake/ProjectBLST.cmake +++ b/cmake/ProjectBLST.cmake @@ -8,17 +8,25 @@ if (NOT BASH_COMMAND) message(FATAL_ERROR "bash not found") endif () +set(BLST_INSTALL_COMMAND + sh -c + "cp /bindings/blst.h /include/ && + cp /bindings/blst.hpp /include/ && + cp /bindings/blst_aux.h /include/ && + cp /libblst.a /lib/" +) + ExternalProject_Add(blst_project PREFIX ${CMAKE_SOURCE_DIR}/deps GIT_REPOSITORY https://github.com/supranational/blst.git - GIT_TAG 3dd0f804b1819e5d03fb22ca2e6fac105932043a + GIT_TAG 52cc60d78591a56abb2f3d0bd1cdafc6ba242997 GIT_SHALLOW 0 CMAKE_ARGS -DCMAKE_INSTALL_PREFIX= BUILD_IN_SOURCE 1 CONFIGURE_COMMAND "" BUILD_COMMAND ${BLST_BUILD_COMMAND} - INSTALL_COMMAND sh -c "cp /bindings/blst.h /include/ && cp /bindings/blst_aux.h /include/ && cp /libblst.a /lib/" + INSTALL_COMMAND ${BLST_INSTALL_COMMAND} LOG_BUILD true LOG_INSTALL true LOG_CONFIGURE true diff --git a/ipa/ipa/IPAConfig.cpp b/ipa/ipa/IPAConfig.cpp index c7ec8eb..b8c644f 100644 --- a/ipa/ipa/IPAConfig.cpp +++ b/ipa/ipa/IPAConfig.cpp @@ -1,12 +1,32 @@ #include "IPAConfig.h" +#include "IPAUtility.h" +#include "PrecomputedMSM.h" using namespace verkle::ipa; +IPAConfig::IPAConfig(): + m_srs(generateRandomPoints(common::vectorLength)), + m_Q(Element::generator()), + m_precomputed_msm(std::make_shared(PrecomputedMSM(m_srs))), + m_precomputed_weights(std::make_shared(PrecomputedWeights())), + m_rounds(computeNumRounds(common::vectorLength)) {} + +IPAConfig const& IPAConfig::getConfig() +{ + static auto config = IPAConfig(); + return config; +} + +Element IPAConfig::commit(const Fr::FrListPtr& scalars) const +{ + return m_precomputed_msm->msm(scalars); +} + Fr::FrListPtr IPAConfig::computeBVector(Fr const& evalPoint) const { if (evalPoint.cmp(maxEvalPoinInsideDomain) > 0) { - return m_precomputed_weights.computeBarycentricCoefficients(evalPoint); + return m_precomputed_weights->computeBarycentricCoefficients(evalPoint); } // We build b = [0, 0, 0, ... , 1, .., 0] where the 1 element is at the index of the evaluation point. diff --git a/ipa/ipa/IPAConfig.h b/ipa/ipa/IPAConfig.h index 1b19f08..e8f7cba 100644 --- a/ipa/ipa/IPAConfig.h +++ b/ipa/ipa/IPAConfig.h @@ -1,5 +1,6 @@ #pragma once -#include "PrecomputedFrs.h" +#include "PrecomputedMSM.h" +#include "PrecomputedWeights.h" #include "bandersnatch/Fr.h" #include "bandersnatch/Element.h" @@ -13,16 +14,23 @@ struct IPAConfig using Ptr = std::shared_ptr; Element::ElementListPtr m_srs; Element m_Q; - PrecomputedFrs m_precomputed_weights; - uint32_t rounds; + PrecomputedMSM::Ptr m_precomputed_msm; + PrecomputedWeights::Ptr m_precomputed_weights; + uint32_t m_rounds{}; - // TODO: precomputed points for acceleration + IPAConfig(IPAConfig const&) = delete; + void operator=(IPAConfig const&) = delete; - Element commitToPoly(const Fr::FrListPtr& scalars); + static IPAConfig const& getConfig(); - Fr::FrListPtr computeBVector(Fr const& evalPoint) const; + [[nodiscard]] Element commit(const Fr::FrListPtr& scalars) const; + + [[nodiscard]] Fr::FrListPtr computeBVector(Fr const& evalPoint) const; static const Fr maxEvalPoinInsideDomain; + +private: + IPAConfig(); }; inline const Fr IPAConfig::maxEvalPoinInsideDomain = Fr::fromUint64(255); diff --git a/ipa/ipa/IPAProof.cpp b/ipa/ipa/IPAProof.cpp index d162db0..2eb2494 100644 --- a/ipa/ipa/IPAProof.cpp +++ b/ipa/ipa/IPAProof.cpp @@ -5,7 +5,7 @@ using namespace verkle::ipa; IPAProof IPAProof::create( const Transcript::Ptr& transcript, - const IPAConfig::Ptr& config, + const IPAConfig& config, Element const& commitment, Fr::FrListPtr& a, Fr const& evalPoint @@ -13,7 +13,7 @@ IPAProof IPAProof::create( { transcript->appendLabel(SeperateLabel::LABEL_IPA); - auto b = config->computeBVector(evalPoint); + auto b = config.computeBVector(evalPoint); auto innerProd = innerProduct(a, b); transcript->appendPoint(commitment, SeperateLabel::LABEL_COMMITMENT); @@ -21,11 +21,11 @@ IPAProof IPAProof::create( transcript->appendScalar(innerProd, SeperateLabel::LABEL_OUTPUT_POINT); auto w = transcript->generateChallenge(SeperateLabel::LABEL_RESCALING); - auto q = config->m_Q.mult(w); + auto q = Element::mult(w, config.m_Q); - auto rounds = config->rounds; + auto rounds = config.m_rounds; - auto currentBasis = config->m_srs; + auto currentBasis = config.m_srs; auto L = std::make_shared>(rounds); auto R = std::make_shared>(rounds); @@ -83,20 +83,20 @@ IPAProof IPAProof::create( bool IPAProof::check ( const Transcript::Ptr& transcript, - const IPAConfig::Ptr& config, + const IPAConfig& config, Element& commitment, Fr const& evalPoint, Fr const& result ) const { - if (m_left->size() != m_right->size() || m_left->size() != config->rounds) + if (m_left->size() != m_right->size() || m_left->size() != config.m_rounds) { return false; } transcript->appendLabel(SeperateLabel::LABEL_IPA); - auto b = config->computeBVector(evalPoint); + auto b = config.computeBVector(evalPoint); transcript->appendPoint(commitment, SeperateLabel::LABEL_COMMITMENT); transcript->appendScalar(evalPoint, SeperateLabel::LABEL_INPUT_POINT); @@ -105,7 +105,7 @@ bool IPAProof::check ( auto w = transcript->generateChallenge(SeperateLabel::LABEL_RESCALING); // Rescaling of q. - auto q = config->m_Q.mult(w); + auto q = Element::mult(w, config.m_Q); commitment.add(q.mult(result)); @@ -132,7 +132,7 @@ bool IPAProof::check ( frs->insert(frs->end(), {Fr::one(), x, invChallenges->at(i)}); } - auto g = config->m_srs; + auto g = config.m_srs; // We compute the folding-scalars for g and b. auto foldingScalars = std::make_shared>(g->size()); diff --git a/ipa/ipa/IPAProof.h b/ipa/ipa/IPAProof.h index 775450c..4975795 100644 --- a/ipa/ipa/IPAProof.h +++ b/ipa/ipa/IPAProof.h @@ -14,14 +14,14 @@ class IPAProof public: static IPAProof create( const Transcript::Ptr& transcript, - const IPAConfig::Ptr& config, + const IPAConfig& config, Element const& commitment, Fr::FrListPtr& a, Fr const& evalPoint ); bool check( const Transcript::Ptr& transcript, - const IPAConfig::Ptr& config, + const IPAConfig& config, Element& commitment, Fr const& evalPoint, Fr const& result @@ -32,6 +32,6 @@ class IPAProof Element::ElementListPtr m_right; Fr m_a; - Fr::FrListPtr generateChallenges(Transcript::Ptr const& transcript) const; + [[nodiscard]] 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 21f1efd..f336a0c 100644 --- a/ipa/ipa/IPAUtility.cpp +++ b/ipa/ipa/IPAUtility.cpp @@ -29,26 +29,6 @@ namespace verkle::ipa return ret; } - 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"); - } - - auto mid = a->size() / 2; - - std::vector first(mid); - std::vector second(a->size()-mid); - - std::move(a->begin(), a->begin()+mid, first.begin()); - std::move(a->begin()+mid, a->end(), second.begin()); - - out1 = std::make_shared(first); - out2 = std::make_shared(second); - } - Element commit(Element::ElementListPtr const& groupElements, Fr::FrListPtr const& polynomial) { if (groupElements->size() != polynomial->size()) { @@ -89,4 +69,32 @@ namespace verkle::ipa } return ret; } + + Element::ElementListPtr generateRandomPoints(size_t numPoints) + { + auto const g = Element::generator(); + auto ret = std::make_shared>(numPoints); + for (size_t i = 0; i < numPoints; ++i) + { + auto randomFr = Fr::random(); + ret->at(i) = Element::mult(randomFr, g); + } + return ret; + } + + size_t computeNumRounds(size_t vectorSize) + { + if (vectorSize == 0) + { + throw std::runtime_error("zero is not a valid input"); + } + + if ((vectorSize & (vectorSize - 1)) == 0) + { + throw std::runtime_error("non power of 2 numbers are not valid inputs"); + } + + size_t ret = std::floor(std::log2(static_cast(vectorSize))); + return ret; + } } diff --git a/ipa/ipa/IPAUtility.h b/ipa/ipa/IPAUtility.h index 0ac5273..a7ad233 100644 --- a/ipa/ipa/IPAUtility.h +++ b/ipa/ipa/IPAUtility.h @@ -19,9 +19,6 @@ namespace verkle::ipa Fr innerProduct(Fr::FrListPtr const& a, Fr::FrListPtr const& b); - template - void split(T a, T& out1, T& out2); - Element commit(Element::ElementListPtr const& groupElements, Fr::FrListPtr const& polynomial); Fr::FrListPtr foldScalars(Fr::FrListPtr const& a, Fr::FrListPtr const& b, Fr const& x); @@ -30,4 +27,34 @@ namespace verkle::ipa Element::ElementListPtr const& a, Element::ElementListPtr const& b, Fr const& x); + + Element::ElementListPtr generateRandomPoints(size_t numPoints); + + size_t computeNumRounds(size_t vectorSize); + + size_t constexpr window16vs8IndexLimit = 5; + size_t constexpr supportedMSMLength = 256; + + template + void split(T a, T& out1, T& out2) + { + using InnerType = typename T::element_type; + + if (a->size()%2 != 0) + { + throw std::runtime_error("scalars or elements should have even length"); + } + + auto mid = a->size() / 2; + + InnerType first(mid); + InnerType second(a->size() - mid); + + std::move(a->begin(), a->begin() + mid, first.begin()); + std::move(a->begin() + mid, a->end(), second.begin()); + + out1 = std::make_shared(std::move(first)); + out2 = std::make_shared(std::move(second)); + } + } \ No newline at end of file diff --git a/ipa/ipa/PrecomputedMSM.cpp b/ipa/ipa/PrecomputedMSM.cpp new file mode 100644 index 0000000..8b80cb1 --- /dev/null +++ b/ipa/ipa/PrecomputedMSM.cpp @@ -0,0 +1,37 @@ +// +// Created by Zhengxuan Guo on 2024/8/30. +// + +#include "PrecomputedMSM.h" +#include "IPAUtility.h" + +using namespace verkle::ipa; + +PrecomputedMSM::PrecomputedMSM(Element::ElementListPtr const& points) +{ + if (points->size() != supportedMSMLength) + { + throw std::runtime_error("the number of points must be " + std::to_string(supportedMSMLength)); + } + + auto first = std::make_shared>(points->begin(), points->begin()+window16vs8IndexLimit); + auto second = std::make_shared>(points->begin()+window16vs8IndexLimit, points->end()); + m_heavy = std::make_shared(first, 14); + m_light = std::make_shared(second, 8); +} + +Element PrecomputedMSM::msm(Fr::FrListPtr const& scalars) +{ + if (scalars->size() != supportedMSMLength) + { + throw std::runtime_error("the number of points must be " + std::to_string(supportedMSMLength)); + } + + auto firstFrs = std::make_shared>(scalars->begin(), scalars->begin()+window16vs8IndexLimit); + auto secondFrs = std::make_shared>(scalars->begin()+window16vs8IndexLimit, scalars->end()); + + auto heavyRes = m_heavy->msm(firstFrs); + auto lightRes = m_light->msm(firstFrs); + + return Element::add(heavyRes, lightRes); +} \ No newline at end of file diff --git a/ipa/ipa/PrecomputedMSM.h b/ipa/ipa/PrecomputedMSM.h new file mode 100644 index 0000000..f8e1eae --- /dev/null +++ b/ipa/ipa/PrecomputedMSM.h @@ -0,0 +1,33 @@ +// +// Created by Zhengxuan Guo on 2024/8/30. +// +#pragma once + +#include "bandersnatch/Element.h" +#include "bandersnatch/Fr.h" +#include "bandersnatch/PrecomputedElements.h" + +using verkle::bandersnatch::PrecomputedElements; +using verkle::bandersnatch::Element; +using verkle::bandersnatch::Fr; + +namespace verkle::ipa +{ + // MSMPrecomp is an engine to calculate 256-MSM on a fixed basis using precomputed tables. + // This precomputed tables design are biased to support an efficient MSM for Verkle Trees. + // + // Their design involves 16-bit windows for the first window16vs8IndexLimit points, and 8-bit + // windows for the rest. The motivation for this is that the first points are used to calculate + // tree keys, which clients heavily rely on compared to "longer" MSMs. This provides a significant + // boost to tree-key generation without exploding table sizes. + class PrecomputedMSM { + public: + using Ptr = std::shared_ptr; + explicit PrecomputedMSM(Element::ElementListPtr const& points); + Element msm(Fr::FrListPtr const& scalars); + + private: + PrecomputedElements::Ptr m_heavy; + PrecomputedElements::Ptr m_light; + }; +} diff --git a/ipa/ipa/PrecomputedFrs.cpp b/ipa/ipa/PrecomputedWeights.cpp similarity index 90% rename from ipa/ipa/PrecomputedFrs.cpp rename to ipa/ipa/PrecomputedWeights.cpp index cd42991..86409fd 100644 --- a/ipa/ipa/PrecomputedFrs.cpp +++ b/ipa/ipa/PrecomputedWeights.cpp @@ -2,7 +2,7 @@ // Created by Zhengxuan Guo on 2024/8/28. // -#include "PrecomputedFrs.h" +#include "PrecomputedWeights.h" using namespace verkle::ipa; @@ -10,7 +10,7 @@ using namespace verkle::ipa; // This is how we will store the A'(x_i) and 1/A'(x_i) // This midpoint variable is used to compute the offset that we need // to place 1/A'(x_i) -PrecomputedFrs::PrecomputedFrs() +PrecomputedWeights::PrecomputedWeights() { auto mid = domainSize; @@ -46,7 +46,7 @@ PrecomputedFrs::PrecomputedFrs() // computes A'(x_j) where x_j must be an element in the domain // This is computed as the product of x_j - x_i where x_i is an element in the domain // and x_i is not equal to x_j -Fr PrecomputedFrs::computeBarycentricWeightForElement(uint64_t element) +Fr PrecomputedWeights::computeBarycentricWeightForElement(uint64_t element) { if (element > domainSize) { @@ -70,7 +70,7 @@ Fr PrecomputedFrs::computeBarycentricWeightForElement(uint64_t element) return total; } -Fr PrecomputedFrs::getInversedBarycentricWeight(size_t index) const +Fr PrecomputedWeights::getInversedBarycentricWeight(size_t index) const { auto const mid = m_barycentricWeights->size() / 2; return m_barycentricWeights->at(index+mid); @@ -81,7 +81,7 @@ Fr PrecomputedFrs::getInversedBarycentricWeight(size_t index) const // basis, the inner product of `p` and `bary_coeffs` is equal to p(z) // Note that `z` should not be in the domain. // This can also be seen as the lagrange coefficients L_i(point) -Fr::FrListPtr PrecomputedFrs::computeBarycentricCoefficients(const Fr& point) const +Fr::FrListPtr PrecomputedWeights::computeBarycentricCoefficients(const Fr& point) const { auto lagrangeEvals = std::make_shared>(domainSize); for (auto i = 0; i < domainSize; ++i) diff --git a/ipa/ipa/PrecomputedFrs.h b/ipa/ipa/PrecomputedWeights.h similarity index 87% rename from ipa/ipa/PrecomputedFrs.h rename to ipa/ipa/PrecomputedWeights.h index b17807d..1bb0ad6 100644 --- a/ipa/ipa/PrecomputedFrs.h +++ b/ipa/ipa/PrecomputedWeights.h @@ -13,9 +13,10 @@ namespace verkle::ipa // PrecomputedWeights contains precomputed coefficients for efficient // usage of the Barycentric formula. - class PrecomputedFrs { + class PrecomputedWeights { public: - PrecomputedFrs(); + using Ptr = std::shared_ptr; + PrecomputedWeights(); [[nodiscard]] Fr::FrListPtr computeBarycentricCoefficients(const Fr& point) const; [[nodiscard]] Fr getInversedBarycentricWeight(size_t index) const; diff --git a/ipa/test/IPAProofTest.cpp b/ipa/test/IPAProofTest.cpp new file mode 100644 index 0000000..40f68d9 --- /dev/null +++ b/ipa/test/IPAProofTest.cpp @@ -0,0 +1,45 @@ +// +// Created by Zhengxuan Guo on 2024/8/30. +// +#include "testutils/TestPromptFixture.h" +#include + +#include "Utility.h" +#include "bandersnatch/Fr.h" +#include "ipa/Transcript.h" +#include "ipa/IPAProof.h" +#include "ipa/IPAUtility.h" + +namespace verkle::ipa::test +{ + BOOST_FIXTURE_TEST_SUITE(PrecomputedFrsTest, verkle::test::TestPromptFixture) + + BOOST_AUTO_TEST_CASE(TestIPAProofCreateVerify) + { + // Shared view + auto point = bandersnatch::Fr::fromUint64(123456789); + + // Prover view + auto poly = testPoly256(std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}); + auto& config = IPAConfig::getConfig(); + auto proverCommitment = config.commit(poly); + auto proverTranscript = std::make_shared(SeperateLabel::LABEL_IPA); + auto proof = IPAProof::create(proverTranscript, config, proverCommitment, poly, point); + + auto lagrangeCoeffs = config.m_precomputed_weights->computeBarycentricCoefficients(point); + auto innerProd = innerProduct(poly, lagrangeCoeffs); + + // Verifier view + auto verifierCommitment = proverCommitment; + auto verifierTranscript = std::make_shared(SeperateLabel::LABEL_IPA); + + BOOST_ASSERT(proof.check(verifierTranscript, config, verifierCommitment, point, innerProd)); + } + + BOOST_AUTO_TEST_CASE(TestIPAProofSerializtion) + { + // TODO + } + + BOOST_AUTO_TEST_SUITE_END() +} diff --git a/ipa/test/PrecomputedFrsTest.cpp b/ipa/test/PrecomputedFrsTest.cpp index 94a007f..dd9f58f 100644 --- a/ipa/test/PrecomputedFrsTest.cpp +++ b/ipa/test/PrecomputedFrsTest.cpp @@ -6,7 +6,7 @@ #include #include "ipa/IPAUtility.h" -#include "ipa/PrecomputedFrs.h" +#include "ipa/PrecomputedWeights.h" namespace verkle::ipa::test { @@ -33,7 +33,7 @@ namespace verkle::ipa::test auto outsidePoint = Fr::fromUint64(3400); auto lagrangeFrs = testPoly256(std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); - auto precomputed = PrecomputedFrs(); + auto precomputed = PrecomputedWeights(); auto barCoeffs = precomputed.computeBarycentricCoefficients(outsidePoint); auto got = innerProduct(lagrangeFrs, barCoeffs); diff --git a/ipa/test/Utility.cpp b/ipa/test/Utility.cpp index 78cc754..da05c9d 100644 --- a/ipa/test/Utility.cpp +++ b/ipa/test/Utility.cpp @@ -30,7 +30,7 @@ namespace verkle::ipa::test return frs; } - Fr evalOutsideDomain(PrecomputedFrs const& precomputed, Fr::FrListPtr f, Fr const& point) + Fr evalOutsideDomain(PrecomputedWeights 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) diff --git a/ipa/test/Utility.h b/ipa/test/Utility.h index 8ec18fa..fd6ab0f 100644 --- a/ipa/test/Utility.h +++ b/ipa/test/Utility.h @@ -2,15 +2,16 @@ // Created by Zhengxuan Guo on 2024/8/29. // #pragma once -#include "ipa/PrecomputedFrs.h" #include "bandersnatch/Fr.h" +#include "ipa/PrecomputedWeights.h" +#include "ipa/IPAConfig.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 evalOutsideDomain(PrecomputedWeights const& precomputed, Fr::FrListPtr f, Fr const& point); Fr evalPoly(Fr::FrListPtr const& poly, Fr const& evalPoint); using FrPoint = std::pair; diff --git a/utilities/verkleutils/Hash.h b/utilities/verkleutils/Hash.h index ce69640..433033a 100644 --- a/utilities/verkleutils/Hash.h +++ b/utilities/verkleutils/Hash.h @@ -5,12 +5,13 @@ namespace verkle::utils { class Hash { -private: - EVP_MD_CTX* m_ctx; public: Hash(); ~Hash(); void update(const void* data, size_t len); void finalize(unsigned char out[32]); + +private: + EVP_MD_CTX* m_ctx; }; } \ No newline at end of file