plonky2 circuit for keccak256. code taken from https://github.com/qope/plonky2-keccak256/tree/main

This commit is contained in:
Manish Kumar 2024-07-15 22:38:42 +05:30
parent 5e7d6fd8c8
commit 1199701caa
9 changed files with 493 additions and 971 deletions

View File

@ -13,6 +13,8 @@ plonky2 = "0.2.2"
rand = "0.8.3"
anyhow = "1.0.79"
sha2 = "0.10"
tiny-keccak={version="2.0.2", features=["keccak"]}
hex="0.4.3"

View File

@ -18,6 +18,7 @@ pub trait CircuitBuilderU64<F: RichField + Extendable<D>, const D: usize> {
fn zero_u64(&mut self) -> U64Target;
fn not_u64(&mut self, a: U64Target) -> U64Target;
fn add_virtual_u64_target(&mut self) -> U64Target;
}
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilderU64<F, D>
@ -57,4 +58,8 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilderU64<F, D>
fn not_u64(&mut self, a: U64Target) -> U64Target {
U64Target([self.not_u32(a.0[0]), self.not_u32(a.0[1])])
}
fn add_virtual_u64_target(&mut self) -> U64Target {
U64Target([U32Target(self.add_virtual_target()),U32Target(self.add_virtual_target())])
}
}

View File

@ -1,25 +0,0 @@
use plonky2::hash::hash_types::RichField;
use plonky2::plonk::circuit_builder::CircuitBuilder;
use plonky2::field::extension::Extendable;
use crate::arithmetic::u64_arithmetic::CircuitBuilderU64;
use crate::arithmetic::u64_arithmetic::U64Target;
pub fn chi<F: RichField + Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>,
state: &mut [[U64Target; 5]; 5]
){
for x in 0..5 {
let mut temp = [builder.zero_u64(); 5];
for y in 0..5 {
temp[y] = state[x][y];
}
for y in 0..5 {
let t1 = builder.not_u64(temp[(y + 1) % 5]);
let t2 = builder.and_u64(t1, temp[(y + 2) % 5]);
state[x][y] = builder.xor_u64(state[x][y], t2);
}
}
}

View File

@ -1,30 +0,0 @@
use plonky2::hash::hash_types::RichField;
use plonky2::plonk::circuit_builder::CircuitBuilder;
use plonky2::field::extension::Extendable;
use crate::arithmetic::u64_arithmetic::CircuitBuilderU64;
use crate::arithmetic::u64_arithmetic::U64Target;
use plonky2_u32::gadgets::arithmetic_u32::CircuitBuilderU32;
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,
];
//iota
pub fn iota<F: RichField + Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>,
state: &mut [[U64Target; 5]; 5],
round: usize
){
let lo = builder.constant_u32((ROUND_CONSTANTS[round] & 0xFFFFFFFF) as u32);
let hi = builder.constant_u32(((ROUND_CONSTANTS[round] >> 32)& 0xFFFFFFFF) as u32);
state[0][0] = builder.xor_u64(state[0][0], U64Target([lo,hi])) ;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +0,0 @@
use plonky2::hash::hash_types::RichField;
use plonky2::plonk::circuit_builder::CircuitBuilder;
use plonky2::field::extension::Extendable;
use crate::arithmetic::u64_arithmetic::CircuitBuilderU64;
use crate::arithmetic::u64_arithmetic::U64Target;
//pi
pub fn pi<F: RichField + Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>,
state: &mut [[U64Target; 5]; 5]
){
let mut new_state = [[builder.zero_u64(); 5]; 5];
for x in 0..5 {
for y in 0..5 {
new_state[(2 * x + 3 * y) % 5][y] = state[x][y];
}
}
*state = new_state;
}

View File

@ -1,27 +0,0 @@
use plonky2::hash::hash_types::RichField;
use plonky2::plonk::circuit_builder::CircuitBuilder;
use plonky2::field::extension::Extendable;
use crate::arithmetic::u64_arithmetic::CircuitBuilderU64;
use crate::arithmetic::u64_arithmetic::U64Target;
//rho
pub fn rho<F: RichField + Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>,
state: &mut [[U64Target; 5]; 5]
){
const RHO_OFFSETS: [[usize; 5]; 5] = [
[0, 1, 62, 28, 27],
[36, 44, 6, 55, 20],
[3, 10, 43, 25, 39],
[41, 45, 15, 21, 8],
[18, 2, 61, 56, 14],
];
for x in 0..5 {
for y in 0..5 {
let rotation = RHO_OFFSETS[x][y];
state[x][y] = builder.rotate_left_u64(state[x][y], rotation as u8);
}
}
}

View File

@ -1,204 +0,0 @@
use plonky2::hash::hash_types::RichField;
use plonky2::plonk::circuit_builder::CircuitBuilder;
use plonky2::field::extension::Extendable;
use crate::arithmetic::u64_arithmetic::CircuitBuilderU64;
use crate::arithmetic::u64_arithmetic::U64Target;
// Theta
pub fn theta<F: RichField + Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>,
state: &mut [[U64Target; 5]; 5]
){
let mut c = [builder.zero_u64(); 5];
let mut d = [builder.zero_u64(); 5];
// Compute column parities
for x in 0..5 {
let xor_x0_x1 = builder.xor_u64(state[x][0], state[x][1]);
let xor_x0_x1_x2 = builder.xor_u64(xor_x0_x1, state[x][2]);
let xor_x0_x1_x2_x3 = builder.xor_u64(xor_x0_x1_x2, state[x][3]);
c[x] = builder.xor_u64(xor_x0_x1_x2_x3, state[x][4]);
}
// Compute rotated parities
for x in 0..5 {
let c_left = c[(x + 4) % 5];
let c_right_rot = builder.rotate_left_u64(c[(x + 1) % 5], 1);
d[x] = builder.xor_u64(c_left, c_right_rot);
}
// Modify the state
for x in 0..5 {
for y in 0..5 {
state[x][y] = builder.xor_u64(state[x][y], d[x]);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use plonky2::field::goldilocks_field::GoldilocksField;
use plonky2::hash::hash_types::RichField;
use plonky2::iop::witness::PartialWitness;
use plonky2::plonk::circuit_builder::CircuitBuilder;
use plonky2::plonk::circuit_data::CircuitConfig;
use plonky2::plonk::config::PoseidonGoldilocksConfig;
use crate::arithmetic::u64_arithmetic::U64Target;
use plonky2_u32::gadgets::arithmetic_u32::CircuitBuilderU32;
use crate::bench::keccak256::keccak::WitnessU64;
fn create_u64_target<F: RichField + Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>,
value: u64
) -> U64Target {
let lo = value as u32;
let hi = (value >> 32) as u32;
U64Target([builder.constant_u32(lo), builder.constant_u32(hi)])
}
#[test]
fn test_theta_function() {
type F = GoldilocksField;
const D: usize = 2;
// Create circuit builder
let config = CircuitConfig::standard_recursion_config();
let mut builder = CircuitBuilder::<F, D>::new(config);
// Input state
let input_state: [[U64Target; 5]; 5] = [
[
create_u64_target(&mut builder, 0x0000000000000001),
create_u64_target(&mut builder, 0x0000000000000002),
create_u64_target(&mut builder, 0x0000000000000003),
create_u64_target(&mut builder, 0x0000000000000004),
create_u64_target(&mut builder, 0x0000000000000005)
],
[
create_u64_target(&mut builder, 0x0000000000000006),
create_u64_target(&mut builder, 0x0000000000000007),
create_u64_target(&mut builder, 0x0000000000000008),
create_u64_target(&mut builder, 0x0000000000000009),
create_u64_target(&mut builder, 0x000000000000000A)
],
[
create_u64_target(&mut builder, 0x000000000000000B),
create_u64_target(&mut builder, 0x000000000000000C),
create_u64_target(&mut builder, 0x000000000000000D),
create_u64_target(&mut builder, 0x000000000000000E),
create_u64_target(&mut builder, 0x000000000000000F)
],
[
create_u64_target(&mut builder, 0x0000000000000010),
create_u64_target(&mut builder, 0x0000000000000011),
create_u64_target(&mut builder, 0x0000000000000012),
create_u64_target(&mut builder, 0x0000000000000013),
create_u64_target(&mut builder, 0x0000000000000014)
],
[
create_u64_target(&mut builder, 0x0000000000000015),
create_u64_target(&mut builder, 0x0000000000000016),
create_u64_target(&mut builder, 0x0000000000000017),
create_u64_target(&mut builder, 0x0000000000000018),
create_u64_target(&mut builder, 0x0000000000000019)
]
];
// Expected output state (after theta)
let expected_state = [
[
create_u64_target(&mut builder, 0x7B7B7B7B7B7B7B7B),
create_u64_target(&mut builder, 0x8B8B8B8B8B8B8B8B),
create_u64_target(&mut builder, 0x9B9B9B9B9B9B9B9B),
create_u64_target(&mut builder, 0xABABABABABABABAB),
create_u64_target(&mut builder, 0xBBBBBBBBBBBBBBBB)
],
[
create_u64_target(&mut builder, 0xCBCBCBCBCBCBCBCB),
create_u64_target(&mut builder, 0xDBDBDBDBDBDBDBDB),
create_u64_target(&mut builder, 0xEBEBEBEBEBEBEBEB),
create_u64_target(&mut builder, 0xFBFBFBFBFBFBFBFB),
create_u64_target(&mut builder, 0x0B0B0B0B0B0B0B0B)
],
[
create_u64_target(&mut builder, 0x1B1B1B1B1B1B1B1B),
create_u64_target(&mut builder, 0x2B2B2B2B2B2B2B2B),
create_u64_target(&mut builder, 0x3B3B3B3B3B3B3B3B),
create_u64_target(&mut builder, 0x4B4B4B4B4B4B4B4B),
create_u64_target(&mut builder, 0x5B5B5B5B5B5B5B5B)
],
[
create_u64_target(&mut builder, 0x6B6B6B6B6B6B6B6B),
create_u64_target(&mut builder, 0x7B7B7B7B7B7B7B7B),
create_u64_target(&mut builder, 0x8B8B8B8B8B8B8B8B),
create_u64_target(&mut builder, 0x9B9B9B9B9B9B9B9B),
create_u64_target(&mut builder, 0xABABABABABABABAB)
],
[
create_u64_target(&mut builder, 0xBBBBBBBBBBBBBBBB),
create_u64_target(&mut builder, 0xCBCBCBCBCBCBCBCB),
create_u64_target(&mut builder, 0xDBDBDBDBDBDBDBDB),
create_u64_target(&mut builder, 0xEBEBEBEBEBEBEBEB),
create_u64_target(&mut builder, 0xFBFBFBFBFBFBFBFB)
]
];
// Run the theta function
let mut state = input_state;
let _ = theta(&mut builder, &mut state);
// Check if the output state matches the expected state
for x in 0..5 {
for y in 0..5 {
for i in 0..2 {
println!("Comparing: {:?} and {:?}", state[x][y].0[i].0, expected_state[x][y].0[i].0);
let res = builder.is_equal(state[x][y].0[i].0, expected_state[x][y].0[i].0);
builder.assert_bool(res);
}
}
}
println!("{:?}", builder.num_gates());
// Build the circuit
let data = builder.build::<PoseidonGoldilocksConfig>();
// Create witness and prove
let mut pw = PartialWitness::new();
pw.set_u64_target(input_state[0][0], 0x0000000000000001);
pw.set_u64_target(input_state[0][1], 0x0000000000000002);
pw.set_u64_target(input_state[0][2], 0x0000000000000003);
pw.set_u64_target(input_state[0][3], 0x0000000000000004);
pw.set_u64_target(input_state[0][4], 0x0000000000000005);
pw.set_u64_target(input_state[1][0], 0x0000000000000006);
pw.set_u64_target(input_state[1][1], 0x0000000000000007);
pw.set_u64_target(input_state[1][2], 0x0000000000000008);
pw.set_u64_target(input_state[1][3], 0x0000000000000009);
pw.set_u64_target(input_state[1][4], 0x000000000000000A);
pw.set_u64_target(input_state[2][0], 0x000000000000000B);
pw.set_u64_target(input_state[2][1], 0x000000000000000C);
pw.set_u64_target(input_state[2][2], 0x000000000000000D);
pw.set_u64_target(input_state[2][3], 0x000000000000000E);
pw.set_u64_target(input_state[2][4], 0x000000000000000F);
pw.set_u64_target(input_state[3][0], 0x0000000000000010);
pw.set_u64_target(input_state[3][1], 0x0000000000000011);
pw.set_u64_target(input_state[3][2], 0x0000000000000012);
pw.set_u64_target(input_state[3][3], 0x0000000000000013);
pw.set_u64_target(input_state[3][4], 0x0000000000000014);
pw.set_u64_target(input_state[4][0], 0x0000000000000015);
pw.set_u64_target(input_state[4][1], 0x0000000000000016);
pw.set_u64_target(input_state[4][2], 0x0000000000000017);
pw.set_u64_target(input_state[4][3], 0x0000000000000018);
pw.set_u64_target(input_state[4][4], 0x0000000000000019);
let proof = data.prove(pw).unwrap();
assert!(data.verify(proof).is_ok());
}
}

View File

@ -14,11 +14,6 @@ mod bench{
}
pub mod keccak256{
pub mod theta;
pub mod rho;
pub mod pi;
pub mod iota;
pub mod chi;
pub mod keccak;
}
}