-
Notifications
You must be signed in to change notification settings - Fork 266
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
# Description Basic structure for a new stdlib Transcript corresponding to the new native transcript used by the Honk proving systems. Implements all functions required with the CAVEAT that no constraints are imposed for hashing in `get_challenge`. May be useful to do this properly at some point but avoiding it for now since it was non-trivial and the hash will change anyway. # Checklist: - [ ] I have reviewed my diff in github, line by line. - [ ] Every change is related to the PR description. - [ ] I have [linked](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) this pull request to the issue(s) that it resolves. - [ ] There are no unexpected formatting changes, superfluous debug logs, or commented-out code. - [ ] The branch has been merged or rebased against the head of its merge target. - [ ] I'm happy for the PR to be merged at the reviewer's next convenience.
- Loading branch information
1 parent
624ffaf
commit 2f66de1
Showing
4 changed files
with
358 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
...uits/cpp/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/trancript.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
#pragma once | ||
|
||
#include "barretenberg/ecc/curves/bn254/fq.hpp" | ||
#include "barretenberg/ecc/curves/bn254/fr.hpp" | ||
#include "barretenberg/ecc/curves/bn254/g1.hpp" | ||
#include "barretenberg/honk/sumcheck/polynomials/univariate.hpp" | ||
#include "barretenberg/honk/transcript/transcript.hpp" | ||
|
||
#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" | ||
#include "barretenberg/stdlib/primitives/biggroup/biggroup.hpp" | ||
#include "barretenberg/stdlib/primitives/field/field.hpp" | ||
#include "barretenberg/stdlib/utility/utility.hpp" | ||
|
||
//TODO(luke): this namespace will be sensible once stdlib is moved out of the plonk namespace | ||
namespace proof_system::plonk::stdlib::recursion::honk { | ||
template <typename Builder> class Transcript { | ||
public: | ||
using field_pt = field_t<Builder>; | ||
using FF = barretenberg::fr; | ||
using VerifierTranscript = proof_system::honk::VerifierTranscript<FF>; | ||
using StdlibTypes = utility::StdlibTypesUtility<Builder>; | ||
|
||
static constexpr size_t HASH_OUTPUT_SIZE = VerifierTranscript::HASH_OUTPUT_SIZE; | ||
|
||
VerifierTranscript native_transcript; | ||
Builder* builder; | ||
|
||
Transcript(Builder* builder, auto proof_data) | ||
: native_transcript(proof_data) | ||
, builder(builder){}; | ||
|
||
/** | ||
* @brief Get the underlying native transcript manifest (primarily for debugging) | ||
* | ||
*/ | ||
auto get_manifest() const { return native_transcript.get_manifest(); }; | ||
|
||
/** | ||
* @brief Compute the challenges (more than 1) indicated by labels | ||
* | ||
* @tparam Strings | ||
* @param labels Names of the challenges to be computed | ||
* @return std::array<FF, sizeof...(Strings)> Array of challenges | ||
*/ | ||
template <typename... Strings> std::array<field_pt, sizeof...(Strings)> get_challenges(const Strings&... labels) | ||
{ | ||
// Compute the indicated challenges from the native transcript | ||
constexpr size_t num_challenges = sizeof...(Strings); | ||
std::array<FF, num_challenges> native_challenges{}; | ||
native_challenges = native_transcript.get_challenges(labels...); | ||
|
||
/* | ||
* TODO(#1351): Do stdlib hashing here. E.g., for the current pedersen/blake setup, we could write data into a | ||
* byte_array as it is received from prover, then compress via pedersen and apply blake3s. Not doing this now | ||
* since it's a pain and we'll be revamping our hashing anyway. For now, simply convert the native hashes to | ||
* stdlib types without adding any hashing constraints. | ||
*/ | ||
std::array<field_pt, num_challenges> challenges; | ||
for (size_t i = 0; i < num_challenges; ++i) { | ||
challenges[i] = native_challenges[i]; | ||
} | ||
|
||
return challenges; | ||
} | ||
|
||
/** | ||
* @brief Compute the single challenge indicated by the input label | ||
* | ||
* @param label Name of challenge | ||
* @return field_pt Challenge | ||
*/ | ||
field_pt get_challenge(const std::string& label) | ||
{ | ||
// Compute the indicated challenge from the native transcript | ||
auto native_challenge = native_transcript.get_challenge(label); | ||
|
||
// TODO(1351): Stdlib hashing here... | ||
|
||
return field_pt(native_challenge); | ||
} | ||
|
||
/** | ||
* @brief Extract a native element from the transcript and return a corresponding stdlib type | ||
* | ||
* @tparam T Type of the native element to be extracted | ||
* @param label Name of the element | ||
* @return The corresponding element of appropriate stdlib type | ||
*/ | ||
template <class T> auto receive_from_prover(const std::string& label) | ||
{ | ||
// Extract the native element from the native transcript | ||
T element = native_transcript.template receive_from_prover<T>(label); | ||
|
||
// Return the corresponding stdlib type | ||
return StdlibTypes::from_witness(builder, element); | ||
} | ||
}; | ||
} // namespace proof_system::plonk::stdlib::recursion::honk |
159 changes: 159 additions & 0 deletions
159
...pp/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
#include <gtest/gtest.h> | ||
|
||
#include "barretenberg/ecc/curves/bn254/fr.hpp" | ||
#include "barretenberg/ecc/curves/bn254/g1.hpp" | ||
#include "barretenberg/honk/sumcheck/polynomials/univariate.hpp" | ||
#include "barretenberg/honk/transcript/transcript.hpp" | ||
#include "barretenberg/stdlib/recursion/honk/transcript/trancript.hpp" | ||
|
||
namespace proof_system::plonk::stdlib::recursion::honk { | ||
|
||
using Builder = UltraCircuitBuilder; | ||
|
||
using FF = barretenberg::fr; | ||
using Commitment = barretenberg::g1::affine_element; | ||
using Point = barretenberg::g1::element; | ||
constexpr size_t LENGTH = 8; // arbitrary | ||
using Univariate = proof_system::honk::sumcheck::Univariate<FF, LENGTH>; | ||
using ProverTranscript = ::proof_system::honk::ProverTranscript<FF>; | ||
using VerifierTranscript = ::proof_system::honk::VerifierTranscript<FF>; | ||
|
||
/** | ||
* @brief Create some mock data and then add it to the transcript in various mock rounds | ||
* | ||
* @param prover_transcript | ||
* @return auto proof_data | ||
*/ | ||
auto generate_mock_proof_data(auto prover_transcript) | ||
{ | ||
uint32_t data = 25; | ||
auto scalar = FF::random_element(); | ||
auto commitment = Commitment::one(); | ||
|
||
std::array<FF, LENGTH> evaluations; | ||
for (auto& eval : evaluations) { | ||
eval = FF::random_element(); | ||
} | ||
auto univariate = Univariate(evaluations); | ||
|
||
// round 0 | ||
prover_transcript.send_to_verifier("data", data); | ||
prover_transcript.get_challenge("alpha"); | ||
|
||
// round 1 | ||
prover_transcript.send_to_verifier("scalar", scalar); | ||
prover_transcript.send_to_verifier("commitment", commitment); | ||
prover_transcript.get_challenges("beta, gamma"); | ||
|
||
// round 2 | ||
prover_transcript.send_to_verifier("univariate", univariate); | ||
prover_transcript.get_challenges("gamma", "delta"); | ||
|
||
return prover_transcript.proof_data; | ||
} | ||
|
||
/** | ||
* @brief Perform series of verifier transcript operations | ||
* @details Operations are designed to correspond to those performed by a prover transcript from which the verifier | ||
* transcript was initialized. | ||
* | ||
* @param transcript Either a native or stdlib verifier transcript | ||
*/ | ||
void perform_mock_verifier_transcript_operations(auto transcript) | ||
{ | ||
// round 0 | ||
transcript.template receive_from_prover<uint32_t>("data"); | ||
transcript.get_challenge("alpha"); | ||
|
||
// round 1 | ||
transcript.template receive_from_prover<FF>("scalar"); | ||
transcript.template receive_from_prover<Commitment>("commitment"); | ||
transcript.get_challenges("beta, gamma"); | ||
|
||
// round 2 | ||
transcript.template receive_from_prover<Univariate>("univariate"); | ||
transcript.get_challenges("gamma", "delta"); | ||
} | ||
|
||
/** | ||
* @brief Test basic transcript functionality and check circuit | ||
* @details Implicitly ensures stdlib interface is identical to native | ||
* @todo(luke): Underlying circuit is nearly trivial until transcript implements hashing constraints | ||
*/ | ||
TEST(stdlib_honk_transcript, basic_transcript_operations) | ||
{ | ||
Builder builder; | ||
|
||
// Instantiate a Prover Transcript and use it to generate some mock proof data | ||
ProverTranscript prover_transcript; | ||
auto proof_data = generate_mock_proof_data(prover_transcript); | ||
|
||
// Instantiate a (native) Verifier Transcript with the proof data and perform some mock transcript operations | ||
VerifierTranscript native_transcript(proof_data); | ||
perform_mock_verifier_transcript_operations(native_transcript); | ||
|
||
// Confirm that Prover and Verifier transcripts have generated the same manifest via the operations performed | ||
EXPECT_EQ(prover_transcript.get_manifest(), native_transcript.get_manifest()); | ||
|
||
// Instantiate a stdlib Transcript and perform the same operations | ||
Transcript<Builder> transcript{ &builder, proof_data }; | ||
perform_mock_verifier_transcript_operations(transcript); | ||
|
||
// Confirm that the native and stdlib transcripts have generated the same manifest | ||
EXPECT_EQ(transcript.get_manifest(), native_transcript.get_manifest()); | ||
|
||
// TODO(luke): This doesn't check much of anything until hashing is constrained in the stdlib transcript | ||
EXPECT_TRUE(builder.check_circuit()); | ||
} | ||
|
||
/** | ||
* @brief Check that native and stdlib verifier transcript functions produce equivalent outputs | ||
* | ||
*/ | ||
TEST(stdlib_honk_transcript, return_values) | ||
{ | ||
Builder builder; | ||
|
||
// Define some mock data for a mock proof | ||
auto scalar = FF::random_element(); | ||
auto commitment = Commitment::one() * FF::random_element(); | ||
|
||
const size_t LENGTH = 10; // arbitrary | ||
std::array<FF, LENGTH> evaluations; | ||
for (auto& eval : evaluations) { | ||
eval = FF::random_element(); | ||
} | ||
|
||
// Construct a mock proof via the prover transcript | ||
ProverTranscript prover_transcript; | ||
prover_transcript.send_to_verifier("scalar", scalar); | ||
prover_transcript.send_to_verifier("commitment", commitment); | ||
prover_transcript.send_to_verifier("evaluations", evaluations); | ||
prover_transcript.get_challenges("alpha, beta"); | ||
auto proof_data = prover_transcript.proof_data; | ||
|
||
// Perform the corresponding operations with the native verifier transcript | ||
VerifierTranscript native_transcript(proof_data); | ||
auto native_scalar = native_transcript.template receive_from_prover<FF>("scalar"); | ||
auto native_commitment = native_transcript.template receive_from_prover<Commitment>("commitment"); | ||
auto native_evaluations = native_transcript.template receive_from_prover<std::array<FF, LENGTH>>("evaluations"); | ||
auto [native_alpha, native_beta] = native_transcript.get_challenges("alpha", "beta"); | ||
|
||
// Perform the corresponding operations with the stdlib verifier transcript | ||
Transcript<Builder> stdlib_transcript{ &builder, proof_data }; | ||
auto stdlib_scalar = stdlib_transcript.template receive_from_prover<FF>("scalar"); | ||
auto stdlib_commitment = stdlib_transcript.template receive_from_prover<Commitment>("commitment"); | ||
auto stdlib_evaluations = stdlib_transcript.template receive_from_prover<std::array<FF, LENGTH>>("evaluations"); | ||
auto [stdlib_alpha, stdlib_beta] = stdlib_transcript.get_challenges("alpha", "beta"); | ||
|
||
// Confirm that return values are equivalent | ||
EXPECT_EQ(native_scalar, stdlib_scalar.get_value()); | ||
EXPECT_EQ(native_commitment, stdlib_commitment.get_value()); | ||
for (size_t i = 0; i < LENGTH; ++i) { | ||
EXPECT_EQ(native_evaluations[i], stdlib_evaluations[i].get_value()); | ||
} | ||
EXPECT_EQ(native_alpha, stdlib_alpha.get_value()); | ||
EXPECT_EQ(native_beta, stdlib_beta.get_value()); | ||
} | ||
|
||
} // namespace proof_system::plonk::stdlib::recursion::honk |
99 changes: 99 additions & 0 deletions
99
circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/utility/utility.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
#pragma once | ||
|
||
#include "barretenberg/ecc/curves/bn254/fq.hpp" | ||
#include "barretenberg/ecc/curves/bn254/fr.hpp" | ||
#include "barretenberg/ecc/curves/bn254/g1.hpp" | ||
#include "barretenberg/honk/sumcheck/polynomials/univariate.hpp" | ||
#include "barretenberg/honk/transcript/transcript.hpp" | ||
|
||
#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" | ||
#include "barretenberg/stdlib/primitives/biggroup/biggroup.hpp" | ||
#include "barretenberg/stdlib/primitives/field/field.hpp" | ||
|
||
namespace proof_system::plonk::stdlib::recursion::utility { | ||
|
||
/** | ||
* @brief Utility class for converting native types to corresponding stdlib types | ||
* | ||
* @details Used to facilitate conversion of various native types (uint32_t, field, group, Univarite, etc.) to | ||
* corresponding stdlib types. Useful for example for obtaining stdlib types in the recursive trancript from native | ||
* types upon deserialization from the native transcript. | ||
* | ||
* @todo Eliminate the need for these somehow? | ||
* @tparam Builder | ||
*/ | ||
template <typename Builder> class StdlibTypesUtility { | ||
using field_ct = field_t<Builder>; | ||
using witness_ct = witness_t<Builder>; | ||
using fq_ct = bigfield<Builder, barretenberg::Bn254FqParams>; | ||
using element_ct = element<Builder, fq_ct, field_ct, barretenberg::g1>; | ||
using FF = barretenberg::fr; | ||
using Commitment = barretenberg::g1::affine_element; | ||
template <size_t LENGTH> using Univariate = proof_system::honk::sumcheck::Univariate<FF, LENGTH>; | ||
|
||
public: | ||
/** | ||
* @brief Construct stdlib field from uint32_t | ||
* | ||
* @param element | ||
* @return field_ct | ||
*/ | ||
static field_ct from_witness(Builder* builder, uint32_t native_element) | ||
{ | ||
return field_ct::from_witness(builder, native_element); | ||
} | ||
|
||
/** | ||
* @brief Construct stdlib field from native field type | ||
* | ||
* @param native_element | ||
* @return field_ct | ||
*/ | ||
static field_ct from_witness(Builder* builder, FF native_element) | ||
{ | ||
return field_ct::from_witness(builder, native_element); | ||
} | ||
|
||
/** | ||
* @brief Construct stdlib group from native affine group element type | ||
* | ||
* @param native_element | ||
* @return field_ct | ||
*/ | ||
static element_ct from_witness(Builder* builder, Commitment native_element) | ||
{ | ||
return element_ct::from_witness(builder, native_element); | ||
} | ||
|
||
/** | ||
* @brief Construct field_t array from native field array | ||
* @param native_element Array of FF | ||
* @return std::array<field_ct, LENGTH> | ||
*/ | ||
template <size_t LENGTH> | ||
static std::array<field_ct, LENGTH> from_witness(Builder* builder, std::array<FF, LENGTH> native_element) | ||
{ | ||
std::array<field_ct, LENGTH> element; | ||
for (size_t i = 0; i < LENGTH; ++i) { | ||
element[i] = field_ct::from_witness(builder, native_element[i]); | ||
} | ||
return element; | ||
} | ||
|
||
/** | ||
* @brief Construct field_t array from native Univariate type | ||
* TODO(luke): do we need a stdlib Univariate or is std::array<field_t> good enough? | ||
* @param native_element | ||
* @return std::array<field_ct, LENGTH> | ||
*/ | ||
template <size_t LENGTH> | ||
static std::array<field_ct, LENGTH> from_witness(Builder* builder, Univariate<LENGTH> native_element) | ||
{ | ||
std::array<field_ct, LENGTH> element; | ||
for (size_t i = 0; i < LENGTH; ++i) { | ||
element[i] = field_ct::from_witness(builder, native_element.value_at(i)); | ||
} | ||
return element; | ||
} | ||
}; | ||
} // namespace proof_system::plonk::stdlib::recursion::utility |