Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement poseidon transcript #107

Merged
merged 7 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tachyon/base/buffer/string_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class TACHYON_EXPORT StringBuffer : public Buffer {
: Buffer(std::move(other)),
owned_buffer_(std::move(other.owned_buffer_)) {}
StringBuffer& operator=(StringBuffer&& other) {
Buffer::operator=(std::move(other));
owned_buffer_ = std::move(other.owned_buffer_);
return *this;
}
Expand Down
3 changes: 2 additions & 1 deletion tachyon/base/buffer/vector_buffer.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#ifndef TACHYON_BASE_BUFFER_VECTOR_BUFFER_H_
#define TACHYON_BASE_BUFFER_VECTOR_BUFFER_H_

#include <vector>
#include <utility>
#include <vector>

#include "tachyon/base/buffer/buffer.h"

Expand All @@ -17,6 +17,7 @@ class TACHYON_EXPORT VectorBuffer : public Buffer {
: Buffer(std::move(other)),
owned_buffer_(std::move(other.owned_buffer_)) {}
VectorBuffer& operator=(VectorBuffer&& other) {
Buffer::operator=(std::move(other));
owned_buffer_ = std::move(other.owned_buffer_);
return *this;
}
Expand Down
1 change: 1 addition & 0 deletions tachyon/crypto/hashes/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ tachyon_cc_library(
"//tachyon/base/buffer",
"//tachyon/math/base:big_int",
"//tachyon/math/finite_fields:finite_field_traits",
"@com_google_absl//absl/container:inlined_vector",
],
)

Expand Down
24 changes: 24 additions & 0 deletions tachyon/crypto/hashes/prime_field_serializable.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
#ifndef TACHYON_CRYPTO_HASHES_PRIME_FIELD_SERIALIZABLE_H_
#define TACHYON_CRYPTO_HASHES_PRIME_FIELD_SERIALIZABLE_H_

#include <array>
#include <type_traits>
#include <vector>

#include "absl/container/inlined_vector.h"
#include "absl/types/span.h"

#include "tachyon/math/base/big_int.h"
Expand Down Expand Up @@ -69,6 +71,28 @@ class PrimeFieldSerializable<std::vector<T>> {
}
};

template <typename T, size_t N>
class PrimeFieldSerializable<absl::InlinedVector<T, N>> {
dongchangYoo marked this conversation as resolved.
Show resolved Hide resolved
public:
template <typename PrimeFieldTy>
constexpr static bool ToPrimeField(const absl::InlinedVector<T, N>& values,
std::vector<PrimeFieldTy>* fields) {
return PrimeFieldSerializable<T>::BatchToPrimeField(
absl::MakeConstSpan(values), fields);
}
};

template <typename T, size_t N>
class PrimeFieldSerializable<std::array<T, N>> {
public:
template <typename PrimeFieldTy>
constexpr static bool ToPrimeField(const std::array<T, N>& values,
std::vector<PrimeFieldTy>* fields) {
return PrimeFieldSerializable<T>::BatchToPrimeField(
absl::MakeConstSpan(values), fields);
}
};

template <typename T, typename PrimeFieldTy>
constexpr bool SerializeToFieldElements(const T& value,
std::vector<PrimeFieldTy>* fields) {
Expand Down
30 changes: 30 additions & 0 deletions tachyon/crypto/hashes/prime_field_serializable_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,36 @@ TEST_F(PrimeFieldSerializableTest, SerializeSingleValueToField) {
EXPECT_EQ(fields, expected);
}

TEST_F(PrimeFieldSerializableTest, SerializeVectorToField) {
std::vector<int64_t> values = {1, 2, 3, 4, 5};
std::vector<math::GF7> fields;
ASSERT_TRUE(SerializeToFieldElements(values, &fields));
std::vector<math::GF7> expected = {
math::GF7(1), math::GF7(2), math::GF7(3), math::GF7(4), math::GF7(5),
};
EXPECT_EQ(fields, expected);
}

TEST_F(PrimeFieldSerializableTest, SerializeArrayToField) {
std::array<int64_t, 5> values = {1, 2, 3, 4, 5};
std::vector<math::GF7> fields;
ASSERT_TRUE(SerializeToFieldElements(values, &fields));
std::vector<math::GF7> expected = {
math::GF7(1), math::GF7(2), math::GF7(3), math::GF7(4), math::GF7(5),
};
EXPECT_EQ(fields, expected);
}

TEST_F(PrimeFieldSerializableTest, SerializeInlinedVectorToField) {
absl::InlinedVector<int64_t, 5> values = {1, 2, 3, 4, 5};
std::vector<math::GF7> fields;
ASSERT_TRUE(SerializeToFieldElements(values, &fields));
std::vector<math::GF7> expected = {
math::GF7(1), math::GF7(2), math::GF7(3), math::GF7(4), math::GF7(5),
};
EXPECT_EQ(fields, expected);
}

TEST_F(PrimeFieldSerializableTest, SerializeBatchToField) {
std::vector<int64_t> values = {1, 2, 3, 4, 5};
std::vector<math::GF7> fields;
Expand Down
10 changes: 10 additions & 0 deletions tachyon/crypto/hashes/sponge/poseidon/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ tachyon_cc_library(
],
)

tachyon_cc_library(
name = "halo2_poseidon",
hdrs = ["halo2_poseidon.h"],
deps = [
":poseidon",
"@local_config_gmp//:gmp",
],
)

tachyon_cc_library(
name = "poseidon_config",
hdrs = ["poseidon_config.h"],
Expand Down Expand Up @@ -43,5 +52,6 @@ tachyon_cc_unittest(
":poseidon",
":poseidon_config",
"//tachyon/math/elliptic_curves/bls/bls12_381:fr",
"//tachyon/math/elliptic_curves/bn/bn254:fr",
],
)
59 changes: 59 additions & 0 deletions tachyon/crypto/hashes/sponge/poseidon/halo2_poseidon.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2020-2022 The Electric Coin Company
// Copyright 2022 The Halo2 developers
// Use of this source code is governed by a MIT/Apache-2.0 style license that
// can be found in the LICENSE-MIT.halo2 and the LICENCE-APACHE.halo2
// file.

#ifndef TACHYON_CRYPTO_HASHES_SPONGE_POSEIDON_HALO2_POSEIDON_H_
chokobole marked this conversation as resolved.
Show resolved Hide resolved
#define TACHYON_CRYPTO_HASHES_SPONGE_POSEIDON_HALO2_POSEIDON_H_

#include <vector>

#include "third_party/gmp/include/gmpxx.h"

#include "tachyon/crypto/hashes/sponge/poseidon/poseidon.h"

namespace tachyon::crypto {

template <typename PrimeFieldTy>
struct Halo2PoseidonSponge : public PoseidonSponge<PrimeFieldTy> {
using F = PrimeFieldTy;

Halo2PoseidonSponge() = default;
explicit Halo2PoseidonSponge(const PoseidonConfig<F>& config)
: PoseidonSponge<PrimeFieldTy>(config) {
this->state.elements[0] = F::FromMpzClass(mpz_class(1) << 64);
}

// FieldBasedCryptographicSponge methods
std::vector<F> SqueezeNativeFieldElements(size_t num_elements) {
chokobole marked this conversation as resolved.
Show resolved Hide resolved
std::vector<F> ret = base::CreateVector(num_elements, F::Zero());
size_t squeeze_index = this->state.mode.next_index;
if (squeeze_index == this->config.rate) {
squeeze_index = 0;
}
this->state[squeeze_index + 1] = F::One();
switch (this->state.mode.type) {
case DuplexSpongeMode::Type::kAbsorbing: {
this->Permute();
this->SqueezeInternal(0, &ret);
return ret;
}
case DuplexSpongeMode::Type::kSqueezing: {
size_t squeeze_index = this->state.mode.next_index;
if (squeeze_index == this->config.rate) {
this->Permute();
squeeze_index = 0;
}
this->SqueezeInternal(squeeze_index, &ret);
return ret;
}
}
NOTREACHED();
return {};
}
};

} // namespace tachyon::crypto

#endif // TACHYON_CRYPTO_HASHES_SPONGE_POSEIDON_HALO2_POSEIDON_H_
3 changes: 3 additions & 0 deletions tachyon/crypto/hashes/sponge/poseidon/poseidon.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct PoseidonSponge
// Sponge State
State state;

PoseidonSponge() = default;
explicit PoseidonSponge(const PoseidonConfig<F>& config)
: config(config), state(config.rate + config.capacity) {}
PoseidonSponge(const PoseidonConfig<F>& config, const State& state)
Expand Down Expand Up @@ -241,6 +242,8 @@ struct PoseidonSponge
}

// FieldBasedCryptographicSponge methods
// NOTE(TomTaehoonKim): If you ever update this, please update
// |Halo2PoseidonSponge| for consistency.
std::vector<F> SqueezeNativeFieldElements(size_t num_elements) {
std::vector<F> ret =
base::CreateVector(num_elements, []() { return F::Zero(); });
Expand Down
79 changes: 42 additions & 37 deletions tachyon/crypto/hashes/sponge/poseidon/poseidon_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ namespace tachyon::crypto {
template <typename PrimeFieldTy>
struct PoseidonConfig;

// An entry in the default Poseidon config
struct TACHYON_EXPORT PoseidonDefaultConfigEntry {
// An entry in the Poseidon config
struct TACHYON_EXPORT PoseidonConfigEntry {
// The rate (in terms of number of field elements).
size_t rate;

Expand All @@ -37,12 +37,9 @@ struct TACHYON_EXPORT PoseidonDefaultConfigEntry {
// https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/generate_parameters_grain.sage
size_t skip_matrices;

constexpr PoseidonDefaultConfigEntry()
: PoseidonDefaultConfigEntry(0, 0, 0, 0, 0) {}
constexpr PoseidonDefaultConfigEntry(size_t rate, uint64_t alpha,
size_t full_rounds,
size_t partial_rounds,
size_t skip_matrices)
constexpr PoseidonConfigEntry() : PoseidonConfigEntry(0, 0, 0, 0, 0) {}
constexpr PoseidonConfigEntry(size_t rate, uint64_t alpha, size_t full_rounds,
size_t partial_rounds, size_t skip_matrices)
: rate(rate),
alpha(alpha),
full_rounds(full_rounds),
Expand All @@ -63,32 +60,29 @@ struct TACHYON_EXPORT PoseidonDefaultConfigEntry {
PoseidonConfig<PrimeFieldTy> ToPoseidonConfig() const;
};

// An array of the config optimized for constraints
// An array of the default config optimized for constraints
// (rate, alpha, full_rounds, partial_rounds, skip_matrices)
// for rate = 2, 3, 4, 5, 6, 7, 8
// Here, |skip_matrices| denotes how many matrices to skip before finding one
// that satisfy all the requirements.
constexpr const PoseidonDefaultConfigEntry kOptimizedConstraintsParams[] = {
PoseidonDefaultConfigEntry(2, 17, 8, 31, 0),
PoseidonDefaultConfigEntry(3, 5, 8, 56, 0),
PoseidonDefaultConfigEntry(4, 5, 8, 56, 0),
PoseidonDefaultConfigEntry(5, 5, 8, 57, 0),
PoseidonDefaultConfigEntry(6, 5, 8, 57, 0),
PoseidonDefaultConfigEntry(7, 5, 8, 57, 0),
PoseidonDefaultConfigEntry(8, 5, 8, 57, 0),
constexpr const PoseidonConfigEntry kOptimizedConstraintsDefaultParams[] = {
PoseidonConfigEntry(2, 17, 8, 31, 0), PoseidonConfigEntry(3, 5, 8, 56, 0),
PoseidonConfigEntry(4, 5, 8, 56, 0), PoseidonConfigEntry(5, 5, 8, 57, 0),
PoseidonConfigEntry(6, 5, 8, 57, 0), PoseidonConfigEntry(7, 5, 8, 57, 0),
PoseidonConfigEntry(8, 5, 8, 57, 0),
};

// An array of the config optimized for weights
// An array of the default config optimized for weights
// (rate, alpha, full_rounds, partial_rounds, skip_matrices)
// for rate = 2, 3, 4, 5, 6, 7, 8
constexpr const PoseidonDefaultConfigEntry kOptimizedWeightsParams[] = {
PoseidonDefaultConfigEntry(2, 257, 8, 13, 0),
PoseidonDefaultConfigEntry(3, 257, 8, 13, 0),
PoseidonDefaultConfigEntry(4, 257, 8, 13, 0),
PoseidonDefaultConfigEntry(5, 257, 8, 13, 0),
PoseidonDefaultConfigEntry(6, 257, 8, 13, 0),
PoseidonDefaultConfigEntry(7, 257, 8, 13, 0),
PoseidonDefaultConfigEntry(8, 257, 8, 13, 0),
constexpr const PoseidonConfigEntry kOptimizedWeightsDefaultParams[] = {
PoseidonConfigEntry(2, 257, 8, 13, 0),
PoseidonConfigEntry(3, 257, 8, 13, 0),
PoseidonConfigEntry(4, 257, 8, 13, 0),
PoseidonConfigEntry(5, 257, 8, 13, 0),
PoseidonConfigEntry(6, 257, 8, 13, 0),
PoseidonConfigEntry(7, 257, 8, 13, 0),
PoseidonConfigEntry(8, 257, 8, 13, 0),
};

// ARK(AddRoundKey) is a matrix that contains an ARC(AddRoundConstant) array in
Expand Down Expand Up @@ -157,16 +151,15 @@ struct PoseidonConfig {
size_t capacity = 0;

static PoseidonConfig CreateDefault(size_t rate, bool optimized_for_weights) {
absl::Span<const PoseidonDefaultConfigEntry> param_set =
absl::Span<const PoseidonConfigEntry> param_set =
optimized_for_weights
? absl::MakeConstSpan(kOptimizedWeightsParams)
: absl::MakeConstSpan(kOptimizedConstraintsParams);

auto it =
base::ranges::find_if(param_set.begin(), param_set.end(),
[rate](const PoseidonDefaultConfigEntry& param) {
return param.rate == rate;
});
? absl::MakeConstSpan(kOptimizedWeightsDefaultParams)
: absl::MakeConstSpan(kOptimizedConstraintsDefaultParams);

auto it = base::ranges::find_if(param_set.begin(), param_set.end(),
[rate](const PoseidonConfigEntry& param) {
return param.rate == rate;
});
CHECK_NE(it, param_set.end());
PoseidonConfig ret = it->template ToPoseidonConfig<PrimeFieldTy>();
FindPoseidonArkAndMds<PrimeFieldTy>(
Expand All @@ -175,6 +168,19 @@ struct PoseidonConfig {
return ret;
}

constexpr static PoseidonConfig CreateCustom(size_t rate, uint64_t alpha,
size_t full_rounds,
size_t partial_rounds,
size_t skip_matrices) {
PoseidonConfigEntry config_entry(rate, alpha, full_rounds, partial_rounds,
skip_matrices);
PoseidonConfig ret = config_entry.ToPoseidonConfig<PrimeFieldTy>();
FindPoseidonArkAndMds<PrimeFieldTy>(
config_entry.ToPoseidonGrainLFSRConfig<PrimeFieldTy>(), skip_matrices,
&ret.ark, &ret.mds);
return ret;
}

bool IsValid() const {
return static_cast<size_t>(ark.rows()) == full_rounds + partial_rounds &&
static_cast<size_t>(ark.cols()) == rate + capacity &&
Expand All @@ -184,8 +190,7 @@ struct PoseidonConfig {
};

template <typename PrimeFieldTy>
PoseidonConfig<PrimeFieldTy> PoseidonDefaultConfigEntry::ToPoseidonConfig()
const {
PoseidonConfig<PrimeFieldTy> PoseidonConfigEntry::ToPoseidonConfig() const {
PoseidonConfig<PrimeFieldTy> config;
config.full_rounds = full_rounds;
config.partial_rounds = partial_rounds;
Expand Down
Loading