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

FRI Implementation: frontend + CPU Backend #795

Open
wants to merge 114 commits into
base: main
Choose a base branch
from
Open

Conversation

ShanieWinitz
Copy link
Contributor

No description provided.

ICICLE_LOG_ERROR << "Number of queries must be > 0";
return eIcicleError::INVALID_ARGUMENT;
}
if (__builtin_expect(this->m_folding_factor != 2, 0)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to check this in the constructor, it's not even an argument of this method so it's strange to fail here for that.

CpuFriBackend(const size_t folding_factor, const size_t stopping_degree, std::vector<MerkleTree> merkle_trees)
: FriBackend<S, F>(folding_factor, stopping_degree, std::move(merkle_trees)),
m_nof_fri_rounds(this->m_merkle_trees.size()),
m_log_input_size(this->m_merkle_trees.size() + std::log2(static_cast<double>(stopping_degree + 1))),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this the log_size? number of trees is probably the number of rounds, so does it assume folding factor is 2?

Comment on lines +37 to +38
const F* input_data,
FriProof<F>& fri_proof /*out*/) override
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is probably better to get the size of input_data here as another parameter. You assume it is valid but maybe it's not. If not, you need to identify and log an error.

* @return eIcicleError Error code indicating success or failure.
*/
eIcicleError commit_fold_phase(
const F* input_data, FriTranscript<F>& transcript, const FriConfig& fri_config, FriProof<F>& fri_proof)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should accept the size and not assume it it valid when you take a pointer like that


eIcicleError proof_of_work(FriTranscript<F>& transcript, const size_t pow_bits, FriProof<F>& fri_proof)
{
for (uint64_t nonce = 0; nonce < UINT64_MAX; nonce++) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nonce is only 64b? Why don't you use the pow API here?

std::vector<std::unique_ptr<F[]>> m_rounds_evals;

// Holds MerkleTree for each round. m_merkle_trees[i] is the tree for round i.
std::vector<MerkleTree>& m_merkle_trees;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a bad idea to store a reference to another object like that since you don't control its lifetime and it may be released too soon (before the FriRounds object). In such cases you need to either pass by value, move or use a smart pointer. Even if this is not exposed to users, it still creates coupling and assumptions for code using this class and changes in other places may break this code.

virtual eIcicleError get_proof(
const FriConfig& fri_config,
const FriTranscriptConfig<F>& fri_transcript_config,
const F* input_data,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to add input_size here

* @param folding_factor The factor by which the codeword is folded each round.
* @param stopping_degree Stopping degree threshold for the final polynomial.
*/
FriBackend(const size_t folding_factor, const size_t stopping_degree, std::vector<MerkleTree> merkle_trees)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably need to check the values are valid here. Since it's a constructor it may be problematic to fail here. Why are those not part of the config?

: m_transcript_config(transcript_config), m_prev_alpha(F::zero()), m_pow_nonce(0)
{
m_entry_0.clear();
m_entry_0.reserve(1024); // pre-allocate some space
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't hardcode values like that. Define it somewhere above

*/
eIcicleError init(const size_t nof_queries, const size_t nof_fri_rounds, const size_t final_poly_size)
{
if (nof_queries <= 0 || nof_fri_rounds <= 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no upper bound limit?

* @param round_idx Index of the round (FRI round).
* @return Reference to the Merkle proof at the specified position.
*/
MerkleProof& get_query_proof(const size_t query_idx, const size_t round_idx)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it not const by design?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each query has a proof per round for two values? Does it assume bit reverse vectors?

*/
std::pair<const std::byte*, std::size_t> get_merkle_tree_root(const size_t round_idx) const
{
return m_query_proofs[0][round_idx].get_root();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this [0] deserves a comment.

auto run = [log_input_size, input_size, folding_factor, stopping_degree, output_store_min_layer, nof_queries,
pow_bits, &scalars](const std::string& dev_type, bool measure) {
Device dev = {dev_type, 0};
icicle_set_device(dev);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need ICICLE_CHECK around icicle APIs in tests so it fails if this fails

ICICLE_CHECK(ntt_init_domain(scalar_t::omega(log_input_size), init_domain_config));

// ===== Prover side ======
uint64_t merkle_tree_arity = 2; // TODO SHANIE (future) - add support for other arities
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now this is not supported right? Do you check it?

Hash hash = Keccak256::create(sizeof(TypeParam)); // hash element -> 32B
Hash compress = Keccak256::create(merkle_tree_arity * hash.output_size()); // hash every 64B to 32B

Fri prover_fri = create_fri<scalar_t, TypeParam>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you only test the case of hash+compress. Do you currently expose the other API too? It's fine if not, but if you do then you must test it as well

ICICLE_CHECK(ntt_release_domain<scalar_t>());
};

run(IcicleTestBase::reference_device(), 0 /*nof_queries*/, 2 /*folding_factor*/, log_input_size /*log_domain_size*/);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(1) Please comment why each case should fail
(2) I think there are more invalid cases like tree arity > 2

}
for (size_t log_input_size = 16; log_input_size <= 24; log_input_size += 4) {
const size_t input_size = 1 << log_input_size;
const size_t folding_factor = 2; // TODO SHANIE (future) - add support for other folding factors
Copy link
Collaborator

@yshekel yshekel Mar 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you assume this when you compute the input size in the cpu backend. I commented there that it is a mistake. Also if you don't support then missing test to assert it fails.
Anyway I think you need to pass the logsize/size of data to the fri prover and not implicitly assume things like that and compute it. If you are wrong you may have segmentation faults or issues like that.

Update: I saw later that you take it in the create_fri() and use it to compute #rounds. and later you recompute the size but I think it's bug prone and better store the size for later.

eIcicleError get_proof(
const FriConfig& fri_config,
const FriTranscriptConfig<F>& fri_transcript_config,
const F* input_data,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing size here

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually now see you pass it to create_fri() but do you use it? I may be confused here. I commented about it multiple times

* @param fri_proof Reference to a FriProof object (output).
* @return An eIcicleError indicating success or failure.
*/
eIcicleError get_proof(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we expose only this constructor for now?

const size_t folding_factor, const size_t stopping_degree, std::vector<MerkleTree> merkle_trees)
{
std::shared_ptr<FriBackend<S, F>> backend;
ICICLE_CHECK(FriDispatcher::execute(folding_factor, stopping_degree, std::move(merkle_trees), backend));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't this this move does anything. It probably copies

Hash merkle_tree_compress_hash,
const uint64_t output_store_min_layer)
{
const size_t log_input_size = static_cast<size_t>(std::log2(static_cast<double>(input_size)));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

size may not be a power of two but you don't check this

Copy link
Collaborator

@yshekel yshekel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better but still I commented, I think there are a few issues still.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants