circuits for different arithemtic operations of BoolTarget, u32 and u64(needed for different hashes)

This commit is contained in:
Manish Kumar 2024-05-30 23:19:42 +05:30
parent 53dcdaa370
commit 7cc901e521
5 changed files with 217 additions and 69 deletions

View File

@ -0,0 +1,30 @@
use plonky2::hash::hash_types::RichField;
use plonky2::field::extension::Extendable;
use plonky2::plonk::circuit_builder::CircuitBuilder;
use plonky2::iop::target::BoolTarget;
pub trait CircuitBuilderBoolTarget<F: RichField + Extendable<D>, const D: usize> {
fn and(&mut self, a: BoolTarget, b: BoolTarget) -> BoolTarget;
fn or(&mut self, a: BoolTarget, b: BoolTarget) -> BoolTarget;
fn xor(&mut self, a: BoolTarget, b: BoolTarget) -> BoolTarget;
}
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilderBoolTarget<F, D>
for CircuitBuilder<F, D>{
fn xor(&mut self, a: BoolTarget, b: BoolTarget) -> BoolTarget {
// a ^ b := (a - b)^2
let s = self.sub(a.target, b.target);
BoolTarget::new_unsafe(self.mul(s, s))
}
fn and(&mut self, a: BoolTarget, b: BoolTarget) -> BoolTarget {
self.and(a, b)
}
fn or(&mut self, a: BoolTarget, b: BoolTarget) -> BoolTarget {
self.or(a, b)
}
}

View File

@ -0,0 +1,80 @@
use plonky2::iop::target::{BoolTarget, Target};
use plonky2::hash::hash_types::RichField;
use plonky2::field::extension::Extendable;
use plonky2::plonk::circuit_builder::CircuitBuilder;
use super::binary_arithmetic::CircuitBuilderBoolTarget;
#[derive(Clone, Copy, Debug)]
pub struct U32Target(pub Target);
pub trait CircuitBuilderU32<F: RichField + Extendable<D>, const D: usize> {
fn or_u32(&mut self, a: U32Target, b: U32Target) -> U32Target;
fn and_u32(&mut self, a: U32Target, b: U32Target) -> U32Target;
fn xor_u32(&mut self, a: U32Target, b: U32Target) -> U32Target;
fn from_u32(&mut self, a: U32Target) -> Vec<BoolTarget>;
fn to_u32(&mut self, a: Vec<BoolTarget>) -> U32Target;
}
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilderU32<F, D>
for CircuitBuilder<F, D>{
fn from_u32(&mut self, a: U32Target) -> Vec<BoolTarget> {
let mut res = Vec::new();
let bit_targets = self.split_le_base::<2>(a.0, 32);
for i in (0..32).rev() {
res.push(BoolTarget::new_unsafe(bit_targets[i]));
}
res
}
fn to_u32(&mut self, a: Vec<BoolTarget>) -> U32Target {
let bit_len = a.len();
assert_eq!(bit_len, 32);
U32Target(self.le_sum(a[0..32].iter().rev()))
}
fn or_u32(&mut self, a: U32Target, b: U32Target) -> U32Target {
let binary_target_a = self.from_u32(a);
let binary_target_b = self.from_u32(b);
let mut res = Vec::<BoolTarget>::new();
for i in 0..32 {
let r = self.or(binary_target_a[i], binary_target_b[i]);
res.push(r);
}
self.to_u32(res)
}
fn and_u32(&mut self, a: U32Target, b: U32Target) -> U32Target {
let binary_target_a = self.from_u32(a);
let binary_target_b = self.from_u32(b);
let mut res = Vec::<BoolTarget>::new();
for i in 0..32 {
let r = self.and(binary_target_a[i], binary_target_b[i]);
res.push(r);
}
self.to_u32(res)
}
fn xor_u32(&mut self, a: U32Target, b: U32Target) -> U32Target {
let binary_target_a = self.from_u32(a);
let binary_target_b = self.from_u32(b);
let mut res = Vec::<BoolTarget>::new();
for i in 0..32 {
let r = self.xor(binary_target_a[i], binary_target_b[i]);
res.push(r);
}
self.to_u32(res)
}
}

View File

@ -0,0 +1,32 @@
use plonky2::hash::hash_types::RichField;
use plonky2::field::extension::Extendable;
use plonky2::plonk::circuit_builder::CircuitBuilder;
use super::u32_arithmetic::CircuitBuilderU32;
use super::u32_arithmetic::U32Target;
#[derive(Clone, Copy, Debug)]
pub struct U64Target(pub [U32Target;2]);
pub trait CircuitBuilderU64<F: RichField + Extendable<D>, const D: usize> {
fn and(&mut self, a: U64Target, b: U64Target) -> U64Target;
fn xor(&mut self, a: U64Target, b: U64Target) -> U64Target;
}
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilderU64<F, D>
for CircuitBuilder<F, D>{
fn xor(&mut self, a: U64Target, b: U64Target) -> U64Target {
let mut result = Vec::new();
for i in 0..2 {
result.push(self.xor_u32(a.0[i], b.0[i]));
}
U64Target([result[0], result[1]])
}
fn and(&mut self, a: U64Target, b: U64Target) -> U64Target {
let mut result = Vec::new();
for i in 0..2 {
result.push(self.and_u32(a.0[i], b.0[i]));
}
U64Target([result[0], result[1]])
}
}

View File

@ -56,87 +56,87 @@ pub fn keccak_bench(_size: usize) {
//----------------------------------------------------------
const KECCAK_WIDTH: usize = 1600;
const KECCAK_RATE: usize = 1088;
const KECCAK_CAPACITY: usize = KECCAK_WIDTH - KECCAK_RATE;
const KECCAK_LANES: usize = KECCAK_WIDTH / 64;
const KECCAK_ROUNDS: usize = 24;
// const KECCAK_WIDTH: usize = 1600;
// const KECCAK_RATE: usize = 1088;
// const KECCAK_CAPACITY: usize = KECCAK_WIDTH - KECCAK_RATE;
// const KECCAK_LANES: usize = KECCAK_WIDTH / 64;
// const KECCAK_ROUNDS: usize = 24;
const ROUND_CONSTANTS: [u64; KECCAK_ROUNDS] = [
0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 0x8000000080008000,
0x000000000000808B, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
0x000000000000008A, 0x0000000000000088, 0x0000000080008009, 0x000000008000000A,
0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 0x8000000000008003,
0x8000000000008002, 0x8000000000000080, 0x000000000000800A, 0x800000008000000A,
0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
];
// const ROUND_CONSTANTS: [u64; KECCAK_ROUNDS] = [
// 0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 0x8000000080008000,
// 0x000000000000808B, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
// 0x000000000000008A, 0x0000000000000088, 0x0000000080008009, 0x000000008000000A,
// 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 0x8000000000008003,
// 0x8000000000008002, 0x8000000000000080, 0x000000000000800A, 0x800000008000000A,
// 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
// ];
fn initialize_state() -> [u64; KECCAK_LANES] {
[0; KECCAK_LANES]
}
pub struct U64Target([U32Target;2]);
// fn initialize_state() -> [u64; KECCAK_LANES] {
// [0; KECCAK_LANES]
// }
// pub struct U64Target([U32Target;2]);
// copied from sha256 circuit
// TODO: move to some common place
pub fn u32_to_bits_target<F: RichField + Extendable<D>, const D: usize, const B: usize>(
builder: &mut CircuitBuilder<F, D>,
a: &U32Target,
) -> Vec<BoolTarget> {
let mut res = Vec::new();
let bit_targets = builder.split_le_base::<B>(a.0, 32);
for i in (0..32).rev() {
res.push(BoolTarget::new_unsafe(bit_targets[i]));
}
res
}
// // copied from sha256 circuit
// // TODO: move to some common place
// pub fn u32_to_bits_target<F: RichField + Extendable<D>, const D: usize, const B: usize>(
// builder: &mut CircuitBuilder<F, D>,
// a: &U32Target,
// ) -> Vec<BoolTarget> {
// let mut res = Vec::new();
// let bit_targets = builder.split_le_base::<B>(a.0, 32);
// for i in (0..32).rev() {
// res.push(BoolTarget::new_unsafe(bit_targets[i]));
// }
// res
// }
// copied from sha256 circuit
// TODO: move to some common place
pub fn bits_to_u32_target<F: RichField + Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>,
bits_target: Vec<BoolTarget>,
) -> U32Target {
let bit_len = bits_target.len();
assert_eq!(bit_len, 32);
U32Target(builder.le_sum(bits_target[0..32].iter().rev()))
}
// // copied from sha256 circuit
// // TODO: move to some common place
// pub fn bits_to_u32_target<F: RichField + Extendable<D>, const D: usize>(
// builder: &mut CircuitBuilder<F, D>,
// bits_target: Vec<BoolTarget>,
// ) -> U32Target {
// let bit_len = bits_target.len();
// assert_eq!(bit_len, 32);
// U32Target(builder.le_sum(bits_target[0..32].iter().rev()))
// }
//TODO: not tested
pub fn xor_u64<F: RichField + Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>,
x: U64Target,
y: U64Target,
) -> U64Target {
let xor_x0_y0 = xor_u32(builder, x.0[0], y.0[0]);
let xor_x1_y1 = xor_u32(builder, x.0[1], y.0[1]);
// //TODO: not tested
// pub fn xor_u64<F: RichField + Extendable<D>, const D: usize>(
// builder: &mut CircuitBuilder<F, D>,
// x: U64Target,
// y: U64Target,
// ) -> U64Target {
// let xor_x0_y0 = xor_u32(builder, x.0[0], y.0[0]);
// let xor_x1_y1 = xor_u32(builder, x.0[1], y.0[1]);
U64Target([xor_x0_y0,xor_x1_y1])
// U64Target([xor_x0_y0,xor_x1_y1])
}
// }
pub fn xor_u32<F: RichField + Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>,
x: U32Target,
y: U32Target,
) -> U32Target {
// pub fn xor_u32<F: RichField + Extendable<D>, const D: usize>(
// builder: &mut CircuitBuilder<F, D>,
// x: U32Target,
// y: U32Target,
// ) -> U32Target {
let bits_target_x = u32_to_bits_target::<F, D, 2>(builder, &x);
let bits_target_y = u32_to_bits_target::<F, D, 2>(builder, &y);
// let bits_target_x = u32_to_bits_target::<F, D, 2>(builder, &x);
// let bits_target_y = u32_to_bits_target::<F, D, 2>(builder, &y);
assert_eq!(bits_target_x.len(), bits_target_y.len());
// assert_eq!(bits_target_x.len(), bits_target_y.len());
let mut xor_result_final = Vec::<BoolTarget>::new();
for i in 0..bits_target_x.len() {
let a_plus_b = builder.add(bits_target_x.get(i).unwrap().target, bits_target_y.get(i).unwrap().target);
let ab = builder.mul(bits_target_x.get(i).unwrap().target, bits_target_y.get(i).unwrap().target);
let two_ab = builder.mul_const(F::from_canonical_u64(2), ab);
let xor_result = builder.sub(a_plus_b, two_ab);
xor_result_final.push(BoolTarget::new_unsafe(xor_result));
}
let result = bits_to_u32_target(builder, xor_result_final);
result
// let mut xor_result_final = Vec::<BoolTarget>::new();
// for i in 0..bits_target_x.len() {
// let a_plus_b = builder.add(bits_target_x.get(i).unwrap().target, bits_target_y.get(i).unwrap().target);
// let ab = builder.mul(bits_target_x.get(i).unwrap().target, bits_target_y.get(i).unwrap().target);
// let two_ab = builder.mul_const(F::from_canonical_u64(2), ab);
// let xor_result = builder.sub(a_plus_b, two_ab);
// xor_result_final.push(BoolTarget::new_unsafe(xor_result));
// }
// let result = bits_to_u32_target(builder, xor_result_final);
// result
}
// }
// Theta
// pub fn theta<F: RichField + Extendable<D>, const D: usize>(

View File

@ -15,6 +15,12 @@ mod bench{
}
}
mod arithmetic {
pub mod binary_arithmetic;
pub mod u32_arithmetic;
pub mod u64_arithmetic;
}
use bench::poseidon::poseidon_bench;
use bench::keccak::keccak_bench;
use bench::sha256::sha::sha256_bench;