Skip to content

Commit

Permalink
refac: refactor transcript and organize commitment schemes
Browse files Browse the repository at this point in the history
This commit solves 2 problems.

1. `Transcript` was only able to handle field or curve point.
   Since proof and hash algorithm can take arbitrary types, this limitation is
   overcame.

2. The interfaces of `VectorCommitmentScheme` and
   `UnivariatePolynomialCommitmentScheme` are organized.

   When committing, the cases are divided into 3 cases.

   - non interactive: e.g, SHPlonk
   - non interactive with random: e.g, Pedersen and MerkleTree
   - interactive: e.g, FRI

  When opening, the cases are divided into 2 cases.

  - non interactive: e.g, MerkleTree
  - interactive: e.g, SHPlonk and FRI
  • Loading branch information
chokobole committed Jan 8, 2024
1 parent 9d68ea7 commit 377692a
Show file tree
Hide file tree
Showing 33 changed files with 645 additions and 597 deletions.
52 changes: 29 additions & 23 deletions tachyon/crypto/commitments/fri/fri.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@

namespace tachyon::crypto {

template <typename F, size_t MaxDegree>
class FRI final
: public UnivariatePolynomialCommitmentScheme<FRI<F, MaxDegree>> {
template <typename F, size_t MaxDegree, typename TranscriptReader,
typename TranscriptWriter>
class FRI final : public UnivariatePolynomialCommitmentScheme<
FRI<F, MaxDegree, TranscriptReader, TranscriptWriter>> {
public:
using Base = UnivariatePolynomialCommitmentScheme<FRI<F, MaxDegree>>;
using Base = UnivariatePolynomialCommitmentScheme<
FRI<F, MaxDegree, TranscriptReader, TranscriptWriter>>;
using Poly = typename Base::Poly;
using Evals = typename Base::Evals;
using Domain = typename Base::Domain;
Expand All @@ -45,14 +47,14 @@ class FRI final
// UnivariatePolynomialCommitmentScheme methods
size_t N() const { return domain_->size(); }

[[nodiscard]] bool Commit(const Poly& poly, Transcript<F>* transcript) const {
[[nodiscard]] bool Commit(const Poly& poly, TranscriptWriter* writer,
std::vector<F>* roots) const {
size_t num_layers = domain_->log_size_of_group();
TranscriptWriter<F>* writer = transcript->ToWriter();
BinaryMerkleTree<F, F, MaxDegree + 1> tree(storage_->GetLayer(0), hasher_);
Evals evals = domain_->FFT(poly);
F root;
if (!tree.Commit(evals.evaluations(), &root)) return false;
if (!writer->WriteToProof(root)) return false;
roots->resize(num_layers + 1);
if (!tree.Commit(evals.evaluations(), &(*roots)[0])) return false;
if (!writer->WriteToProof((*roots)[0])) return false;
const Poly* cur_poly = &poly;

F beta;
Expand All @@ -66,17 +68,17 @@ class FRI final
BinaryMerkleTree<F, F, MaxDegree + 1> tree(storage_->GetLayer(i),
hasher_);
evals = sub_domains_[i - 1]->FFT(folded_poly);
if (!tree.Commit(evals.evaluations(), &root)) return false;
if (!writer->WriteToProof(root)) return false;
if (!tree.Commit(evals.evaluations(), &(*roots)[i])) return false;
if (!writer->WriteToProof((*roots)[i])) return false;
cur_poly = &folded_poly;
}
}

beta = writer->SqueezeChallenge();
folded_poly = cur_poly->template Fold<false>(beta);
const F* constant = folded_poly[0];
root = constant ? *constant : F::Zero();
return writer->WriteToProof(root);
(*roots)[num_layers] = constant ? *constant : F::Zero();
return writer->WriteToProof((*roots)[num_layers]);
}

[[nodiscard]] bool DoCreateOpeningProof(size_t index,
Expand Down Expand Up @@ -110,10 +112,9 @@ class FRI final
return true;
}

[[nodiscard]] bool DoVerifyOpeningProof(Transcript<F>& transcript,
[[nodiscard]] bool DoVerifyOpeningProof(TranscriptReader& reader,
size_t index,
const FRIProof<F>& proof) const {
TranscriptReader<F>* reader = transcript.ToReader();
size_t domain_size = domain_->size();
size_t num_layers = domain_->log_size_of_group();
F root;
Expand All @@ -126,7 +127,7 @@ class FRI final
BinaryMerkleTreeStorage<F>* layer = storage_->GetLayer(i);
BinaryMerkleTree<F, F, MaxDegree + 1> tree(layer, hasher_);

if (!reader->ReadFromProof(&root)) return false;
if (!reader.ReadFromProof(&root)) return false;
if (!tree.VerifyOpeningProof(root, proof.evaluations[i], proof.paths[i]))
return false;

Expand Down Expand Up @@ -175,7 +176,7 @@ class FRI final
evaluation_sym = proof.evaluations_sym[i];
x = sub_domains_[i - 1]->GetElement(leaf_index);
}
beta = reader->SqueezeChallenge();
beta = reader.SqueezeChallenge();
beta *= x.Inverse();
domain_size = domain_size >> 1;
}
Expand All @@ -185,7 +186,7 @@ class FRI final
evaluation += evaluation_sym;
evaluation *= two_inv;

if (!reader->ReadFromProof(&root)) return false;
if (!reader.ReadFromProof(&root)) return false;
if (root != evaluation) {
LOG(ERROR) << "Root doesn't match with expected evaluation";
return false;
Expand All @@ -200,19 +201,24 @@ class FRI final
mutable FRIStorage<F>* storage_ = nullptr;
// not owned
BinaryMerkleHasher<F, F>* hasher_ = nullptr;
// not owned
Transcript<F>* transcript_ = nullptr;
std::vector<std::unique_ptr<Domain>> sub_domains_;
};

template <typename F, size_t MaxDegree>
struct VectorCommitmentSchemeTraits<FRI<F, MaxDegree>> {
template <typename F, size_t MaxDegree, typename _TranscriptReader,
typename _TranscriptWriter>
struct VectorCommitmentSchemeTraits<
FRI<F, MaxDegree, _TranscriptReader, _TranscriptWriter>> {
public:
constexpr static size_t kMaxSize = MaxDegree + 1;
constexpr static bool kIsTransparent = true;
constexpr static bool kIsCommitInteractive = true;
constexpr static bool kIsOpenInteractive = false;

using Field = F;
using Commitment = Transcript<F>;
using Commitment = std::vector<F>;
using TranscriptReader = _TranscriptReader;
using TranscriptWriter = _TranscriptWriter;
using Proof = FRIProof<F>;
};

} // namespace tachyon::crypto
Expand Down
26 changes: 18 additions & 8 deletions tachyon/crypto/commitments/fri/fri_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ class SimpleHasher

class SimpleFRIStorage : public FRIStorage<math::Goldilocks> {
public:
const std::vector<SimpleBinaryMerkleTreeStorage<math::Goldilocks>>& layers()
const {
return layers_;
using Layer = SimpleBinaryMerkleTreeStorage<math::Goldilocks>;

const std::vector<Layer>& layers() const { return layers_; }

std::vector<math::Goldilocks> GetRoots() const {
return base::Map(layers_,
[](const Layer& layer) { return layer.GetRoot(); });
}

// FRIStorage<math::Goldilocks> methods
Expand All @@ -54,11 +58,14 @@ class FRITest : public testing::Test {
constexpr static size_t N = size_t{1} << K;
constexpr static size_t kMaxDegree = N - 1;

using PCS = FRI<math::Goldilocks, kMaxDegree>;
using PCS = FRI<math::Goldilocks, kMaxDegree,
SimpleTranscriptReader<math::Goldilocks>,
SimpleTranscriptWriter<math::Goldilocks>>;
using F = PCS::Field;
using Poly = PCS::Poly;
using Commitment = PCS::Commitment;
using Domain = PCS::Domain;
using TranscriptReader = PCS::TranscriptReader;
using TranscriptWriter = PCS::TranscriptWriter;

static void SetUpTestSuite() { math::Goldilocks::Init(); }

Expand All @@ -79,14 +86,17 @@ class FRITest : public testing::Test {
TEST_F(FRITest, CommitAndVerify) {
Poly poly = Poly::Random(kMaxDegree);
base::Uint8VectorBuffer write_buffer;
SimpleTranscriptWriter<F> writer(std::move(write_buffer));
ASSERT_TRUE(pcs_.Commit(poly, &writer));
TranscriptWriter writer(std::move(write_buffer));
std::vector<F> roots;
ASSERT_TRUE(pcs_.Commit(poly, &writer, &roots));
roots.pop_back();
EXPECT_EQ(roots, storage_.GetRoots());

size_t index = base::Uniform(base::Range<size_t>::Until(kMaxDegree + 1));
FRIProof<math::Goldilocks> proof;
ASSERT_TRUE(pcs_.CreateOpeningProof(index, &proof));

SimpleTranscriptReader<F> reader(std::move(writer).TakeBuffer());
TranscriptReader reader(std::move(writer).TakeBuffer());
reader.buffer().set_buffer_offset(0);
ASSERT_TRUE(pcs_.VerifyOpeningProof(reader, index, proof));
}
Expand Down
61 changes: 34 additions & 27 deletions tachyon/crypto/commitments/kzg/shplonk.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,24 @@ namespace tachyon {
namespace zk {

template <typename Curve, size_t MaxDegree, size_t MaxExtensionDegree,
typename _Commitment = typename math::Pippenger<
typename Curve::G1Curve::AffinePoint>::Bucket>
typename Commitment, typename TranscriptReader,
typename TranscriptWriter>
class SHPlonkExtension;

} // namespace zk

namespace crypto {

template <typename Curve, size_t MaxDegree,
typename Commitment = typename math::Pippenger<
typename Curve::G1Curve::AffinePoint>::Bucket>
class SHPlonk final : public UnivariatePolynomialCommitmentScheme<
SHPlonk<Curve, MaxDegree, Commitment>>,
public KZGFamily<typename Curve::G1Curve::AffinePoint,
MaxDegree, Commitment> {
template <typename Curve, size_t MaxDegree, typename Commitment,
typename TranscriptReader, typename TranscriptWriter>
class SHPlonk final
: public UnivariatePolynomialCommitmentScheme<SHPlonk<
Curve, MaxDegree, Commitment, TranscriptReader, TranscriptWriter>>,
public KZGFamily<typename Curve::G1Curve::AffinePoint, MaxDegree,
Commitment> {
public:
using Base = UnivariatePolynomialCommitmentScheme<
SHPlonk<Curve, MaxDegree, Commitment>>;
using Base = UnivariatePolynomialCommitmentScheme<SHPlonk<
Curve, MaxDegree, Commitment, TranscriptReader, TranscriptWriter>>;
using G1Point = typename Curve::G1Curve::AffinePoint;
using G2Point = typename Curve::G2Curve::AffinePoint;
using Fp12 = typename Curve::Fp12;
Expand All @@ -51,20 +51,20 @@ class SHPlonk final : public UnivariatePolynomialCommitmentScheme<
: KZGFamily<G1Point, MaxDegree, Commitment>(std::move(kzg)) {}

private:
friend class VectorCommitmentScheme<SHPlonk<Curve, MaxDegree, Commitment>>;
friend class UnivariatePolynomialCommitmentScheme<
SHPlonk<Curve, MaxDegree, Commitment>>;
template <typename, size_t, size_t, typename>
friend class VectorCommitmentScheme<SHPlonk<
Curve, MaxDegree, Commitment, TranscriptReader, TranscriptWriter>>;
friend class UnivariatePolynomialCommitmentScheme<SHPlonk<
Curve, MaxDegree, Commitment, TranscriptReader, TranscriptWriter>>;
template <typename, size_t, size_t, typename, typename, typename>
friend class zk::SHPlonkExtension;

// Set 𝜏G₂
void SetTauG2(const G2Point& tau_g2) { tau_g2_ = tau_g2; }

// UnivariatePolynomialCommitmentScheme methods
template <typename Container>
[[nodiscard]] bool DoCreateOpeningProof(
const Container& poly_openings,
TranscriptWriter<Commitment>* writer) const {
[[nodiscard]] bool DoCreateOpeningProof(const Container& poly_openings,
TranscriptWriter* writer) const {
PolynomialOpeningGrouper<Poly> grouper;
grouper.GroupByPolyOracleAndPoints(poly_openings);

Expand Down Expand Up @@ -196,20 +196,19 @@ class SHPlonk final : public UnivariatePolynomialCommitmentScheme<

template <typename Container>
[[nodiscard]] bool DoVerifyOpeningProof(
const Container& poly_openings,
TranscriptReader<Commitment>* reader) const {
TranscriptReader& reader, const Container& poly_openings) const {
using G1JacobianPoint = math::JacobianPoint<typename G1Point::Curve>;

Field y = reader->SqueezeChallenge();
Field v = reader->SqueezeChallenge();
Field y = reader.SqueezeChallenge();
Field v = reader.SqueezeChallenge();

Commitment h;
if (!reader->ReadFromProof(&h)) return false;
if (!reader.ReadFromProof(&h)) return false;

Field u = reader->SqueezeChallenge();
Field u = reader.SqueezeChallenge();

Commitment q;
if (!reader->ReadFromProof(&q)) return false;
if (!reader.ReadFromProof(&q)) return false;

PolynomialOpeningGrouper<Poly, Commitment> grouper;
grouper.GroupByPolyOracleAndPoints(poly_openings);
Expand Down Expand Up @@ -350,15 +349,23 @@ class SHPlonk final : public UnivariatePolynomialCommitmentScheme<
G2Point tau_g2_;
};

template <typename Curve, size_t MaxDegree, typename _Commitment>
struct VectorCommitmentSchemeTraits<SHPlonk<Curve, MaxDegree, _Commitment>> {
template <typename Curve, size_t MaxDegree, typename _Commitment,
typename _TranscriptReader, typename _TranscriptWriter>
struct VectorCommitmentSchemeTraits<SHPlonk<
Curve, MaxDegree, _Commitment, _TranscriptReader, _TranscriptWriter>> {
public:
constexpr static size_t kMaxSize = MaxDegree + 1;
constexpr static bool kIsTransparent = false;
constexpr static bool kIsCommitInteractive = false;
constexpr static bool kIsOpenInteractive = true;

using G1Point = typename Curve::G1Curve::AffinePoint;
using Field = typename G1Point::ScalarField;
using Commitment = _Commitment;
using TranscriptReader = _TranscriptReader;
using TranscriptWriter = _TranscriptWriter;
// not used since all of the proof needed is recorded in transcript.
using Proof = void*;
};

} // namespace crypto
Expand Down
20 changes: 11 additions & 9 deletions tachyon/crypto/commitments/kzg/shplonk_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ class SHPlonkTest : public testing::Test {
constexpr static size_t kMaxDegree = N - 1;

using PCS =
SHPlonk<math::bn254::BN254Curve, kMaxDegree, math::bn254::G1AffinePoint>;
SHPlonk<math::bn254::BN254Curve, kMaxDegree, math::bn254::G1AffinePoint,
SimpleTranscriptReader<math::bn254::G1AffinePoint>,
SimpleTranscriptWriter<math::bn254::G1AffinePoint>>;
using F = PCS::Field;
using Poly = PCS::Poly;
using Commitment = PCS::Commitment;
using Point = Poly::Point;
using TranscriptReader = PCS::TranscriptReader;
using TranscriptWriter = PCS::TranscriptWriter;
using PolyRef = base::DeepRef<const Poly>;
using PointRef = base::DeepRef<const Point>;
using CommitmentRef = base::DeepRef<const Commitment>;
Expand All @@ -36,8 +40,6 @@ class SHPlonkTest : public testing::Test {
math::bn254::G2Curve::Init();
}

SHPlonkTest() : writer_(base::Uint8VectorBuffer()) {}

void SetUp() override {
KZG<math::bn254::G1AffinePoint, kMaxDegree, math::bn254::G1AffinePoint> kzg;
pcs_ = PCS(std::move(kzg));
Expand Down Expand Up @@ -103,18 +105,18 @@ class SHPlonkTest : public testing::Test {
std::vector<Commitment> commitments_;
std::vector<PolynomialOpening<Poly>> prover_openings_;
std::vector<PolynomialOpening<Poly, Commitment>> verifier_openings_;
SimpleTranscriptWriter<Commitment> writer_;
};

} // namespace

TEST_F(SHPlonkTest, CreateAndVerifyProof) {
ASSERT_TRUE(pcs_.CreateOpeningProof(prover_openings_, &writer_));
base::Uint8VectorBuffer write_buffer;
TranscriptWriter writer(std::move(write_buffer));
ASSERT_TRUE(pcs_.CreateOpeningProof(prover_openings_, &writer));

base::Buffer read_buf(writer_.buffer().buffer(),
writer_.buffer().buffer_len());
SimpleTranscriptReader<Commitment> reader(std::move(read_buf));
EXPECT_TRUE((pcs_.VerifyOpeningProof(verifier_openings_, &reader)));
base::Buffer read_buf(writer.buffer().buffer(), writer.buffer().buffer_len());
TranscriptReader reader(std::move(read_buf));
EXPECT_TRUE((pcs_.VerifyOpeningProof(reader, verifier_openings_)));
}

} // namespace tachyon::crypto
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,18 @@ struct VectorCommitmentSchemeTraits<BinaryMerkleTree<Leaf, Hash, MaxSize>> {
public:
constexpr static size_t kMaxSize = MaxSize;
constexpr static bool kIsTransparent = true;
constexpr static bool kIsCommitInteractive = false;
constexpr static bool kIsOpenInteractive = false;

// TODO(chokobole): The result of Keccak256 is not a field. How can we handle
// this?
using Field = Hash;
using Commitment = Hash;
// not used
using TranscriptReader = void*;
// not used
using TranscriptWriter = void*;
using Proof = BinaryMerkleProof<Hash>;
};

} // namespace tachyon::crypto
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class BinaryMerkleTreeStorage {
virtual size_t GetSize() const = 0;
virtual const Hash& GetHash(size_t i) const = 0;
virtual void SetHash(size_t i, const Hash& hash) = 0;

Hash GetRoot() const { return GetHash(0); }
};

} // namespace tachyon::crypto
Expand Down
7 changes: 7 additions & 0 deletions tachyon/crypto/commitments/pedersen/pedersen.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,16 @@ struct VectorCommitmentSchemeTraits<Pedersen<Point, MaxSize, _Commitment>> {
public:
constexpr static size_t kMaxSize = MaxSize;
constexpr static bool kIsTransparent = true;
constexpr static bool kIsCommitInteractive = false;

using Field = typename Point::ScalarField;
using Commitment = _Commitment;
// not used
using TranscriptReader = void*;
// not used
using TranscriptWriter = void*;
// not used
using Proof = void*;
};

} // namespace crypto
Expand Down

0 comments on commit 377692a

Please sign in to comment.