use crate::air::SP1Operation;
use serde::{Deserialize, Serialize};
use slop_algebra::Field;
use sp1_core_executor::{
events::{ByteLookupEvent, ByteRecord},
ByteOpcode, Opcode,
};
use sp1_derive::{AlignedBorrow, InputExpr, InputParams, IntoShape, SP1OperationBuilder};
use sp1_hypercube::air::SP1AirBuilder;
use sp1_primitives::consts::WORD_BYTE_SIZE;
#[derive(
AlignedBorrow,
Default,
Debug,
Clone,
Copy,
Serialize,
Deserialize,
IntoShape,
SP1OperationBuilder,
)]
#[repr(C)]
pub struct BitwiseOperation<T> {
pub result: [T; WORD_BYTE_SIZE],
}
impl<F: Field> BitwiseOperation<F> {
pub fn populate_bitwise(
&mut self,
record: &mut impl ByteRecord,
a_u64: u64,
b_u64: u64,
c_u64: u64,
opcode: Opcode,
) {
let a = a_u64.to_le_bytes();
let b = b_u64.to_le_bytes();
let c = c_u64.to_le_bytes();
self.result = a.map(|x| F::from_canonical_u8(x));
for ((b_a, b_b), b_c) in a.into_iter().zip(b).zip(c) {
let byte_event =
ByteLookupEvent { opcode: ByteOpcode::from(opcode), a: b_a as u16, b: b_b, c: b_c };
record.add_byte_lookup_event(byte_event);
}
}
fn eval_bitwise<AB: SP1AirBuilder>(
builder: &mut AB,
a: [AB::Expr; WORD_BYTE_SIZE],
b: [AB::Expr; WORD_BYTE_SIZE],
cols: BitwiseOperation<AB::Var>,
opcode: AB::Expr,
is_real: AB::Expr,
) {
for i in 0..WORD_BYTE_SIZE {
builder.send_byte(
opcode.clone(),
cols.result[i],
a[i].clone(),
b[i].clone(),
is_real.clone(),
);
}
}
}
#[derive(Clone, InputParams, InputExpr)]
pub struct BitwiseOperationInput<AB: SP1AirBuilder> {
pub a: [AB::Expr; WORD_BYTE_SIZE],
pub b: [AB::Expr; WORD_BYTE_SIZE],
pub cols: BitwiseOperation<AB::Var>,
pub opcode: AB::Expr,
pub is_real: AB::Expr,
}
impl<AB: SP1AirBuilder> SP1Operation<AB> for BitwiseOperation<AB::F> {
type Input = BitwiseOperationInput<AB>;
type Output = ();
fn lower(builder: &mut AB, input: Self::Input) {
BitwiseOperation::<AB::F>::eval_bitwise(
builder,
input.a,
input.b,
input.cols,
input.opcode,
input.is_real,
);
}
}