diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e0311b..6734824 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,4 +10,5 @@ include(ProjectBLST) add_subdirectory(utilities) -add_subdirectory(bandersnatch) \ No newline at end of file +add_subdirectory(bandersnatch) +add_subdirectory(ipa) \ No newline at end of file diff --git a/bandersnatch/CMakeLists.txt b/bandersnatch/CMakeLists.txt index f3ba8d1..2c8e3dd 100644 --- a/bandersnatch/CMakeLists.txt +++ b/bandersnatch/CMakeLists.txt @@ -6,6 +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_link_libraries(bandersnatch PUBLIC blst) if (TESTS) diff --git a/bandersnatch/test/unittests/ElementTest.cpp b/bandersnatch/test/unittests/ElementTest.cpp index c6f0259..168d0cb 100644 --- a/bandersnatch/test/unittests/ElementTest.cpp +++ b/bandersnatch/test/unittests/ElementTest.cpp @@ -1,9 +1,9 @@ // // Created by Zhengxuan Guo on 2024/8/15. // -#include "bandersnatch/Element.h" -#include "testutils/TestPromptFixture.h" #include "Constants.h" +#include +#include #include namespace verkle::test diff --git a/bandersnatch/test/unittests/FrTest.cpp b/bandersnatch/test/unittests/FrTest.cpp index 95df24b..48812ff 100644 --- a/bandersnatch/test/unittests/FrTest.cpp +++ b/bandersnatch/test/unittests/FrTest.cpp @@ -1,9 +1,9 @@ // // Created by Zhengxuan Guo on 2024/8/15. // -#include "bandersnatch/Fr.h" -#include "testutils/TestPromptFixture.h" #include "Constants.h" +#include +#include #include namespace verkle::test diff --git a/ipa/CMakelists.txt b/ipa/CMakelists.txt new file mode 100644 index 0000000..7441597 --- /dev/null +++ b/ipa/CMakelists.txt @@ -0,0 +1,15 @@ +project(ipa) + +file(GLOB_RECURSE SRCS ipa/*.cpp) +file(GLOB_RECURSE HEADERS ipa/*.h) + +add_library(ipa ${SRCS} ${HEADERS}) +add_dependencies(ipa bandersnatch utilities) +target_include_directories(ipa PUBLIC ../bandersnatch ipa) +target_link_libraries(ipa PUBLIC bandersnatch utilities) + +if (TESTS) + enable_testing() + set(CTEST_OUTPUT_ON_FAILURE TRUE) + add_subdirectory(test) +endif() \ No newline at end of file diff --git a/ipa/ipa/IPAConfig.h b/ipa/ipa/IPAConfig.h new file mode 100644 index 0000000..e58ea09 --- /dev/null +++ b/ipa/ipa/IPAConfig.h @@ -0,0 +1,17 @@ +#pragma once +#include "bandersnatch/Fr.h" +#include "bandersnatch/Element.h" + + +namespace verkle::ipa +{ +class IPAConfig +{ +public: + bandersnatch::Element commitToPoly(const std::vector& scalars); +private: + std::vector m_srs; + bandersnatch::Element q; + uint32_t rounds; +}; +} \ No newline at end of file diff --git a/ipa/ipa/Transcript.cpp b/ipa/ipa/Transcript.cpp new file mode 100644 index 0000000..4a82235 --- /dev/null +++ b/ipa/ipa/Transcript.cpp @@ -0,0 +1,63 @@ +#include "Transcript.h" + +using namespace verkle::ipa; + +Transcript::Transcript(SeperateLabel label) +{ + auto lv = getLabelValue(label); + m_state.update(lv, strlen(lv)); +} + +const char* Transcript::getLabelValue(const SeperateLabel& label) +{ + return labelValues.at(label); +} + +void Transcript::appendLabel(SeperateLabel label) +{ + m_buffer << getLabelValue(label); +} + +void Transcript::appendScalar(const bandersnatch::Fr& scalar, SeperateLabel label) +{ + uint64_t out[4]; + scalar.serialize(out); + appendLabel(label); + for (size_t i = 0; i < 4; ++i) + { + m_buffer << out[i]; + } +} + +void Transcript::appendPoint(const bandersnatch::Element& point, SeperateLabel label) +{ + byte out[96]; + point.serialize(out); + appendLabel(label); + for (size_t i = 0; i < 96; ++i) + { + m_buffer << out[i]; + } +} + +verkle::bandersnatch::Fr Transcript::generateChallenge(SeperateLabel label) +{ + // fetch buffer and reset it + appendLabel(label); + auto str = m_buffer.str(); + auto combined = str.c_str(); + m_buffer.str(""); + m_buffer.clear(); + + // use buffer hash to generate a challenge + unsigned char hash[32]; + m_state.update(combined, strlen(combined)); + m_state.finalize(hash); + bandersnatch::Fr ret(hash, sizeof(hash)); + + // add the new challenge to the state + // which "summarises" the previous state before we cleared it + appendScalar(ret, label); + + return ret; +} \ No newline at end of file diff --git a/ipa/ipa/Transcript.h b/ipa/ipa/Transcript.h new file mode 100644 index 0000000..cda3550 --- /dev/null +++ b/ipa/ipa/Transcript.h @@ -0,0 +1,52 @@ +#pragma once +#include "bandersnatch/Fr.h" +#include "bandersnatch/Element.h" +#include "verkleutils/Hash.h" +#include +#include +#include + +namespace verkle::ipa +{ +enum SeperateLabel +{ + LABEL_IPA, + LABEL_COMMITMENT, + LABEL_INPUT_POINT, + LABEL_OUTPPUT_POINT, + LABEL_RESCALING, + LABEL_LEFT, + LABEL_RIGHT, + LABEL_X, +}; + +// 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: + 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); +}; + +inline const std::unordered_map Transcript::labelValues = { + {LABEL_IPA, "ipa"}, + {LABEL_COMMITMENT, "commitment"}, + {LABEL_INPUT_POINT, "input point"}, + {LABEL_OUTPPUT_POINT, "output point"}, + {LABEL_RESCALING, "rescaling"}, + {LABEL_LEFT, "left"}, + {LABEL_RIGHT, "right"}, + {LABEL_X, "x"} +}; + +} \ No newline at end of file diff --git a/ipa/test/CMakelists.txt b/ipa/test/CMakelists.txt new file mode 100644 index 0000000..548508b --- /dev/null +++ b/ipa/test/CMakelists.txt @@ -0,0 +1,9 @@ +file(GLOB_RECURSE TEST_SRCS "*.cpp") + +add_executable(ipa-test ${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) +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/TranscriptTest.cpp b/ipa/test/TranscriptTest.cpp new file mode 100644 index 0000000..f131dc6 --- /dev/null +++ b/ipa/test/TranscriptTest.cpp @@ -0,0 +1,115 @@ +// +// Created by Zhengxuan Guo on 2024/8/15. +// +#include "ipa/Transcript.h" +#include "testutils/TestPromptFixture.h" +#include + +namespace verkle::test +{ +BOOST_FIXTURE_TEST_SUITE(TransCriptTest, TestPromptFixture) + +BOOST_AUTO_TEST_CASE(testCallChallengeScalarTwice) +{ + ipa::Transcript tr(ipa::LABEL_IPA); + auto challenge_1 = tr.generateChallenge(ipa::LABEL_X); + auto challenge_2 = tr.generateChallenge(ipa::LABEL_X); + BOOST_ASSERT(challenge_1 != challenge_2); +} + +BOOST_AUTO_TEST_CASE(testChallengeScalar) +{ + ipa::Transcript tr(ipa::LABEL_IPA); + auto challenge = tr.generateChallenge(ipa::LABEL_X); + uint64_t out[4]; + challenge.serialize(out); + + uint64_t raw[4] = { + 0xe9f26c96d15bb807, + 0x6ad84e7137609152, + 0xe193b5e1ce7d01c4, + 0x27625b6a622c0518, + }; + bandersnatch::Fr exp(raw); + BOOST_ASSERT(challenge == exp); +} + +BOOST_AUTO_TEST_CASE(testAppendScalar) +{ + uint64_t raw1[4] = { + 0xe9f26c96d15bb807, + 0x6ad84e7137609152, + 0xe193b5e1ce7d01c4, + 0x27625b6a622c0518, + }; + bandersnatch::Fr base(raw1); + ipa::Transcript tr(ipa::LABEL_LEFT); + + // append scalar twice + tr.appendScalar(base, ipa::LABEL_RESCALING); + tr.appendScalar(base, ipa::LABEL_RESCALING); + + auto challenge = tr.generateChallenge(ipa::LABEL_X); + uint64_t out[4]; + challenge.serialize(out); + + uint64_t raw2[4] = { + 0xe9f26c96d15bb807, + 0x6ad84e7137609152, + 0xe193b5e1ce7d01c4, + 0x27625b6a622c0518, + }; + bandersnatch::Fr exp(raw2); + BOOST_ASSERT(challenge == exp); +} + +BOOST_AUTO_TEST_CASE(testAppendPoint) +{ + auto g = bandersnatch::Element::generator(); + ipa::Transcript tr(ipa::LABEL_LEFT); + + // append point twice + tr.appendPoint(g, ipa::LABEL_INPUT_POINT); + tr.appendPoint(g, ipa::LABEL_OUTPPUT_POINT); + + auto challenge = tr.generateChallenge(ipa::LABEL_X); + uint64_t out[4]; + challenge.serialize(out); + + uint64_t raw2[4] = { + 0xe9f26c96d15bb807, + 0x6ad84e7137609152, + 0xe193b5e1ce7d01c4, + 0x27625b6a622c0518, + }; + bandersnatch::Fr exp(raw2); + BOOST_ASSERT(challenge == exp); +} + +BOOST_AUTO_TEST_CASE(testAppendLabel) +{ + auto g = bandersnatch::Element::generator(); + ipa::Transcript tr(ipa::LABEL_LEFT); + + // append point and some labels + tr.appendPoint(g, ipa::LABEL_INPUT_POINT); + tr.appendLabel(ipa::LABEL_COMMITMENT); + tr.appendPoint(g, ipa::LABEL_OUTPPUT_POINT); + tr.appendLabel(ipa::LABEL_RIGHT); + + auto challenge = tr.generateChallenge(ipa::LABEL_X); + uint64_t out[4]; + challenge.serialize(out); + + uint64_t raw2[4] = { + 0xe9f26c96d15bb807, + 0x6ad84e7137609152, + 0xe193b5e1ce7d01c4, + 0x27625b6a622c0518, + }; + bandersnatch::Fr exp(raw2); + BOOST_ASSERT(challenge == exp); +} + +BOOST_AUTO_TEST_SUITE_END() +} \ No newline at end of file diff --git a/ipa/test/main.cpp b/ipa/test/main.cpp new file mode 100644 index 0000000..178413e --- /dev/null +++ b/ipa/test/main.cpp @@ -0,0 +1,5 @@ +#define BOOST_TEST_MODULE VERKLE_Tests +#define BOOST_TEST_MAIN + +#include +#include \ No newline at end of file diff --git a/utilities/CMakeLists.txt b/utilities/CMakeLists.txt index f98be3c..afadd42 100644 --- a/utilities/CMakeLists.txt +++ b/utilities/CMakeLists.txt @@ -1,7 +1,12 @@ project(utilities) +find_package(OpenSSL CONFIG REQUIRED) find_package(boost_unit_test_framework CONFIG REQUIRED) find_package(boost_filesystem CONFIG REQUIRED) -add_library(utilities INTERFACE) -target_include_directories(utilities INTERFACE .) \ No newline at end of file +file(GLOB_RECURSE SRCS *.cpp) +file(GLOB_RECURSE HEADERS *.h) + +add_library(utilities ${SRCS} ${HEADERS}) +target_include_directories(utilities PUBLIC .) +target_link_libraries(utilities PUBLIC OpenSSL::Crypto) \ No newline at end of file diff --git a/utilities/verkleutils/Hash.cpp b/utilities/verkleutils/Hash.cpp new file mode 100644 index 0000000..db6d7bb --- /dev/null +++ b/utilities/verkleutils/Hash.cpp @@ -0,0 +1,24 @@ +#include "Hash.h" + +using namespace verkle::utils; + +Hash::Hash() : m_ctx(EVP_MD_CTX_new()) +{ + EVP_DigestInit_ex(m_ctx, EVP_sha256(), NULL); +} + +Hash::~Hash() +{ + EVP_MD_CTX_free(m_ctx); +} + +void Hash::update(const void* data, size_t len) +{ + EVP_DigestUpdate(m_ctx, data, len); +} + +void Hash::finalize(unsigned char out[32]) +{ + unsigned int _len; + EVP_DigestFinal_ex(m_ctx, out, &_len); +} \ No newline at end of file diff --git a/utilities/verkleutils/Hash.h b/utilities/verkleutils/Hash.h new file mode 100644 index 0000000..ce69640 --- /dev/null +++ b/utilities/verkleutils/Hash.h @@ -0,0 +1,16 @@ +#pragma once +#include + +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]); +}; +} \ No newline at end of file diff --git a/vcpkg.json b/vcpkg.json index c76fc33..8b3b453 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -3,6 +3,7 @@ "version": "1.0", "dependencies": [ "boost-test", - "boost-filesystem" + "boost-filesystem", + "openssl" ] }