Skip to content

Commit

Permalink
zkevm bbf signextend
Browse files Browse the repository at this point in the history
  • Loading branch information
Antoine Cyr committed Nov 29, 2024
1 parent b06cb1a commit a1d34d6
Show file tree
Hide file tree
Showing 4 changed files with 284 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,21 @@ namespace nil {
stack.push_back(result);
pc++;
gas -= 8;
} else if (opcode == zkevm_opcode::SIGNEXTEND){
// 0x0b
zkevm_word_type b = stack.back();
stack.pop_back();
_rw_operations.push_back(stack_rw_operation(call_id, stack.size(), rw_counter++, false, b));
zkevm_word_type x = stack.back();
stack.pop_back();
_rw_operations.push_back(stack_rw_operation(call_id, stack.size(), rw_counter++, false, x));
int len = (integral_type(b) < 32) ? int(integral_type(b)) + 1 : 32;
integral_type sign = (integral_type(x) << (8 * (32 - len) + 1)) >> 256;
zkevm_word_type result = zkevm_word_type((((integral_type(1) << 8 * (32 - len)) - 1) << 8 * len) * sign) + zkevm_word_type((integral_type(x) << (8 * (32 - len) + 1)) >>(8 * (32 - len) + 1));
_rw_operations.push_back(stack_rw_operation(call_id, stack.size(), rw_counter++, true, result));
stack.push_back(result);
pc++;
gas -= 5;
} else if (opcode == zkevm_opcode::LT){
// 0x10
zkevm_word_type a = stack.back();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,6 @@ namespace nil {
if constexpr (stage == GenerationStage::ASSIGNMENT) {
zkevm_word_type a = current_state.stack_top();
zkevm_word_type b = current_state.stack_top(1);


integral_type r_integral =
b != 0u ? integral_type(a) / integral_type(b) : 0u;
zkevm_word_type r = zkevm_word_type::backend_type(r_integral.backend());
Expand Down Expand Up @@ -326,18 +324,18 @@ namespace nil {
3); // rw_counter transition
std::vector<TYPE> tmp;

// tmp = {TYPE(rw_op_to_num(rw_operation_type::stack)),
// current_state.call_id(0),
// current_state.stack_size(0) - 1,
// TYPE(0), // storage_key_hi
// TYPE(0), // storage_key_lo
// TYPE(0), // field
// current_state.rw_counter(0),
// TYPE(0), // is_write
// A0,
// A1};
// lookup(tmp, "zkevm_rw");
/*
tmp = {TYPE(rw_op_to_num(rw_operation_type::stack)),
current_state.call_id(0),
current_state.stack_size(0) - 1,
TYPE(0), // storage_key_hi
TYPE(0), // storage_key_lo
TYPE(0), // field
current_state.rw_counter(0),
TYPE(0), // is_write
A0,
A1};
lookup(tmp, "zkevm_rw");

tmp = {TYPE(rw_op_to_num(rw_operation_type::stack)),
current_state.call_id(0),
current_state.stack_size(0) - 2,
Expand All @@ -360,7 +358,7 @@ namespace nil {
TYPE(1), // is_write
Res0,
Res1};
lookup(tmp, "zkevm_rw");*/
lookup(tmp, "zkevm_rw");
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2024 Alexey Yashunsky <[email protected]>
// Copyright (c) 2024 Antoine Cyr <[email protected]>
//
// MIT License
//
Expand All @@ -24,33 +25,262 @@

#pragma once

#include <numeric>
#include <algorithm>

#include <iostream>
#include <nil/blueprint/zkevm/zkevm_word.hpp>
#include <nil/blueprint/zkevm_bbf/types/opcode.hpp>
#include <numeric>

namespace nil {
namespace blueprint {
namespace bbf{
namespace bbf {
template<typename FieldType>
class opcode_abstract;

template<typename FieldType, GenerationStage stage>
class zkevm_signextend_bbf : public generic_component<FieldType, stage> {
using generic_component<FieldType, stage>::allocate;
using generic_component<FieldType, stage>::copy_constrain;
using generic_component<FieldType, stage>::constrain;
using generic_component<FieldType, stage>::lookup;
using generic_component<FieldType, stage>::lookup_table;

using value_type = typename FieldType::value_type;

constexpr static const std::size_t chunk_amount = 16;
constexpr static const value_type two_16 = 65536;
constexpr static const value_type two_32 = 4294967296;
constexpr static const value_type two_48 = 281474976710656;
constexpr static const value_type two_64 = 0x10000000000000000_cppui_modular254;
constexpr static const value_type two_128 =
0x100000000000000000000000000000000_cppui_modular254;
constexpr static const value_type two_192 =
0x1000000000000000000000000000000000000000000000000_cppui_modular254;

public:
using typename generic_component<FieldType, stage>::TYPE;
using typename generic_component<FieldType, stage>::context_type;

std::vector<TYPE> res;

public:
zkevm_signextend_bbf(context_type &context_object,
const opcode_input_type<FieldType, stage> &current_state)
: generic_component<FieldType, stage>(context_object, false),
res(chunk_amount) {
using integral_type = boost::multiprecision::number<
boost::multiprecision::backends::cpp_int_modular_backend<257>>;

std::vector<TYPE> b_chunks(chunk_amount);
std::vector<TYPE> x_chunks(chunk_amount);
std::vector<TYPE> r_chunks(chunk_amount);
std::vector<TYPE> indic(chunk_amount);
std::vector<TYPE> cur(chunk_amount);

TYPE b_sum;
TYPE x_sum;
TYPE b_sum_inverse;
TYPE b0p;
TYPE parity;
TYPE n;
TYPE xn;
TYPE xp;
TYPE xpp;
TYPE sb;
TYPE sgn;
TYPE saux;

TYPE range_check_n;
TYPE range_check_xp;
TYPE range_check_xpp;
TYPE range_check_saux;

if constexpr (stage == GenerationStage::ASSIGNMENT) {
zkevm_word_type b = current_state.stack_top();
zkevm_word_type x = current_state.stack_top(1);

int len = (integral_type(b) < 32) ? int(integral_type(b)) + 1 : 32;
integral_type sign = (integral_type(x) << (8 * (32 - len) + 1)) >> 256;
zkevm_word_type result =
zkevm_word_type(
(((integral_type(1) << 8 * (32 - len)) - 1) << 8 * len) * sign) +
zkevm_word_type((integral_type(x) << (8 * (32 - len) + 1)) >>
(8 * (32 - len) + 1));
// +1 because integral type is 257 bits long

unsigned int b0 = static_cast<unsigned int>(integral_type(b) % 65536);
unsigned int b0p_ui = (integral_type(b) > 65535) ? 32 : b0;
b0p = b0p_ui;
unsigned int parity_ui = b0p_ui%2;
parity = parity_ui;
unsigned int n_ui = (b0p_ui-parity_ui)/2;
n = n_ui;
unsigned int xn_ui = static_cast<unsigned int>(
(integral_type(x) << (16 * (n_ui > 15 ? 16 : 15 - n_ui) + 1)) >>
(16 * 15 + 1));
xn = xn_ui;
// +1 because integral_type is 257 bits long
unsigned int xpp_ui = xn_ui % 256;
xpp = xpp_ui;
xp = (xn - xpp) / 256;
sb = (parity == 0) ? xpp : xp;
sgn = (sb > 128);
saux = sb + 128 - sgn * 256;

b_chunks = zkevm_word_to_field_element<FieldType>(b);
x_chunks = zkevm_word_to_field_element<FieldType>(x);
r_chunks = zkevm_word_to_field_element<FieldType>(result);
for (std::size_t i = 0; i < chunk_amount; i++) {
cur[i] = i;
indic[i] = (cur[i] == n) ? 0 : (cur[i]-n).inversed();
}

b_sum = 0;
for (std::size_t i = 1; i < chunk_amount; i++) {
b_sum += b_chunks[i];
}
b_sum_inverse = b_sum.is_zero() ? 0 : b_sum.inversed();

x_sum = 0;
for (std::size_t i = 0; i < chunk_amount; i++) {
x_sum += x_chunks[i] * (1 - (i - n) * indic[i]);
}
range_check_n = 2 * n;
range_check_xp = xp * 256;
range_check_xpp = xpp * 256;
range_check_saux = saux * 256;
}

allocate(n, 23, 1);
for (std::size_t i = 0; i < chunk_amount; i++) {
allocate(b_chunks[i], i, 0);
allocate(x_chunks[i], i + chunk_amount, 0);
allocate(r_chunks[i], i, 1);
allocate(indic[i], i + 2 * chunk_amount, 0);
res[i] = r_chunks[i];
constrain((i - n) * (1 - (i - n) * indic[i]));
}

allocate(b_sum, 32, 1);
allocate(b_sum_inverse, 33, 1);
allocate(x_sum, 34, 1);
allocate(b0p, 35, 1);
allocate(parity, 36, 1);
allocate(xn, 37, 1);
allocate(xp, 20, 1);
allocate(xpp, 21, 1);
allocate(sb, 38, 1);
allocate(sgn, 39, 1);
allocate(saux, 22, 1);

constrain(b_sum * (1 - b_sum_inverse * b_sum));
constrain((b0p - b_chunks[0] * (1 - b_sum * b_sum_inverse) -
32 * b_sum * b_sum_inverse));
constrain(parity * (1 - parity));
constrain(b0p - parity - 2 * n);
// n < 32768 range check
allocate(range_check_n);
// xp, xpp,saux < 256
allocate(range_check_xp);
allocate(range_check_xpp);
allocate(range_check_saux);

constrain(xn - x_sum);
constrain(xn - xp * 256 - xpp);

constrain(sb - (1 - parity) * xpp - parity * xp);
constrain(sgn * (1 - sgn));
constrain(sb + 128 - saux - 256 * sgn);

auto B_128 = chunks16_to_chunks128_reversed<TYPE>(b_chunks);
auto X_128 = chunks16_to_chunks128_reversed<TYPE>(x_chunks);
auto Res_128 = chunks16_to_chunks128_reversed<TYPE>(res);

TYPE B0, B1, X0, X1, Res0, Res1;
B0 = B_128.first;
B1 = B_128.second;
X0 = X_128.first;
X1 = X_128.second;
Res0 = Res_128.first;
Res1 = Res_128.second;
allocate(B0, 42, 1);
allocate(B1, 43, 1);
allocate(X0, 44, 1);
allocate(X1, 45, 1);
allocate(Res0, 46, 1);
allocate(Res1, 47, 1);

if constexpr (stage == GenerationStage::CONSTRAINTS) {

constrain(current_state.pc_next() - current_state.pc(1) -
1); // PC transition
constrain(current_state.gas(1) - current_state.gas_next() -
5); // GAS transition
constrain(current_state.stack_size(1) - current_state.stack_size_next() -
1); // stack_size transition
constrain(current_state.memory_size(1) -
current_state.memory_size_next()); // memory_size transition
constrain(current_state.rw_counter_next() - current_state.rw_counter(1) -
3); // rw_counter transition
std::vector<TYPE> tmp;
tmp = {TYPE(rw_op_to_num(rw_operation_type::stack)),
current_state.call_id(1),
current_state.stack_size(1) - 1,
TYPE(0), // storage_key_hi
TYPE(0), // storage_key_lo
TYPE(0), // field
current_state.rw_counter(1),
TYPE(0), // is_write
B0,
B1};
lookup(tmp, "zkevm_rw");
tmp = {TYPE(rw_op_to_num(rw_operation_type::stack)),
current_state.call_id(1),
current_state.stack_size(1) - 2,
TYPE(0), // storage_key_hi
TYPE(0), // storage_key_lo
TYPE(0), // field
current_state.rw_counter(1) + 1,
TYPE(0), // is_write
X0,
X1};
lookup(tmp, "zkevm_rw");
tmp = {TYPE(rw_op_to_num(rw_operation_type::stack)),
current_state.call_id(1),
current_state.stack_size(1) - 2,
TYPE(0), // storage_key_hi
TYPE(0), // storage_key_lo
TYPE(0), // field
current_state.rw_counter(1) + 2,
TYPE(1), // is_write
Res0,
Res1};
lookup(tmp, "zkevm_rw");
}
}
};

template<typename FieldType>
class zkevm_signextend_operation : public opcode_abstract<FieldType> {
public:
public:
virtual void fill_context(
typename generic_component<FieldType, GenerationStage::ASSIGNMENT>::context_type &context,
const opcode_input_type<FieldType, GenerationStage::ASSIGNMENT> &current_state
) {}
typename generic_component<FieldType, GenerationStage::ASSIGNMENT>::context_type
&context,
const opcode_input_type<FieldType, GenerationStage::ASSIGNMENT>
&current_state) {
zkevm_signextend_bbf<FieldType, GenerationStage::ASSIGNMENT> bbf_obj(
context, current_state);
}
virtual void fill_context(
typename generic_component<FieldType, GenerationStage::CONSTRAINTS>::context_type &context,
const opcode_input_type<FieldType, GenerationStage::CONSTRAINTS> &current_state
) {}
virtual std::size_t rows_amount() override {
return 2;
typename generic_component<FieldType,
GenerationStage::CONSTRAINTS>::context_type &context,
const opcode_input_type<FieldType, GenerationStage::CONSTRAINTS>
&current_state) {
zkevm_signextend_bbf<FieldType, GenerationStage::CONSTRAINTS> bbf_obj(
context, current_state);
}
virtual std::size_t rows_amount() override { return 2; }
};
} // namespace bbf
} // namespace blueprint
} // namespace nil
} // namespace bbf
} // namespace blueprint
} // namespace nil
Loading

0 comments on commit a1d34d6

Please sign in to comment.