Add range checks
@@ -34,12 +34,43 @@ StateTarget(array::from_fn(|i| array::from_fn(|j| b[j * 4 + i])))
} } -/// Type alias for byte targets -pub type ByteTarget = Target; +/// Type for byte targets +#[derive(Debug, Copy, Clone)] +pub struct ByteTarget(pub(crate) Target); pub trait CircuitBuilderAESState<F: RichField + Extendable<D>, const D: usize> { - /// Adds state target. - fn add_virtual_state(&mut self) -> StateTarget; + /// Adds byte target (unsafe). + fn add_virtual_byte_target_unsafe(&mut self) -> ByteTarget; + + /// Adds byte target safely assuming an appropriate lookup table + /// (see `assert_byte`). + fn add_virtual_byte_target(&mut self, u8_table_idx: usize) -> ByteTarget { + let byte_target = self.add_virtual_byte_target_unsafe(); + self.assert_byte(byte_target.0, u8_table_idx); + byte_target + } + + /// Asserts that a given target is a byte. + /// Requires a lookup table of the form {(x, y): x ∈ u8}. + fn assert_byte(&mut self, x: Target, u8_table_idx: usize); + + /// Adds byte constant + fn byte_constant(&mut self, c: u8) -> ByteTarget; + + /// Adds state target (unsafe). + fn add_virtual_state_target_unsafe(&mut self) -> StateTarget { + StateTarget(array::from_fn(|_| { + array::from_fn(|_| self.add_virtual_byte_target_unsafe()) + })) + } + + /// Adds state target under the same assumptions as + /// `add_virtual_byte_target`. + fn add_virtual_state_target(&mut self, u8_table_idx: usize) -> StateTarget { + StateTarget(array::from_fn(|_| { + array::from_fn(|_| self.add_virtual_byte_target(u8_table_idx)) + })) + } /// AES cipher as in spec. fn encrypt_block<const NR: usize>(@@ -84,7 +115,7 @@ s: StateTarget,
) -> StateTarget { let cols: [_; 4] = array::from_fn(|i| array::from_fn(|j| s.0[j][i])); let out_cols: [_; 4] = array::from_fn(|i| { - self.bytearray_matrix_apply_bits(xor_lut_idx, gf_2_8_mul_lut_idx, mix_matrix, cols[i]) + self.byte_matrix_apply(xor_lut_idx, gf_2_8_mul_lut_idx, mix_matrix, cols[i]) }); StateTarget(array::from_fn(|i| array::from_fn(|j| out_cols[j][i]))) }@@ -110,13 +141,14 @@ key: [ByteTarget; NK * NB],
) -> [[ByteTarget; 4]; 4 * (NR + 1)]; /// GF(2^8) addition - fn gf_2_8_add(&mut self, xor_lut_idx: usize, x: Target, y: Target) -> Target; + fn gf_2_8_add(&mut self, xor_lut_idx: usize, x: ByteTarget, y: ByteTarget) -> ByteTarget; /// GF(2^8) multiplication - fn gf_2_8_mul(&mut self, gf_2_8_mul_lut_idx: usize, x: Target, y: Target) -> Target; + fn gf_2_8_mul(&mut self, gf_2_8_mul_lut_idx: usize, x: ByteTarget, y: ByteTarget) + -> ByteTarget; /// Bytearray inner product. - fn bytearray_ip_bits<const N: usize>( + fn bytearray_ip<const N: usize>( &mut self, xor_lut_idx: usize, gf_2_8_mul_lut_idx: usize,@@ -124,15 +156,15 @@ x: [ByteTarget; N],
y: [ByteTarget; N], ) -> ByteTarget; - /// Bytearray matrix application. - fn bytearray_matrix_apply_bits<const M: usize, const N: usize>( + /// Byte matrix application. + fn byte_matrix_apply<const M: usize, const N: usize>( &mut self, xor_lut_idx: usize, gf_2_8_mul_lut_idx: usize, a: [[ByteTarget; N]; M], x: [ByteTarget; N], ) -> [ByteTarget; M] { - std::array::from_fn(|i| self.bytearray_ip_bits(xor_lut_idx, gf_2_8_mul_lut_idx, a[i], x)) + std::array::from_fn(|i| self.bytearray_ip(xor_lut_idx, gf_2_8_mul_lut_idx, a[i], x)) } /// returns a 0u8 in the shape of a ByteTarget.@@ -142,17 +174,23 @@ fn empty_state(&mut self) -> StateTarget;
} impl CircuitBuilderAESState<F, D> for CircuitBuilder<F, D> { - fn add_virtual_state(&mut self) -> StateTarget { - StateTarget(array::from_fn(|_| { - array::from_fn(|_| self.add_virtual_target()) - })) + fn add_virtual_byte_target_unsafe(&mut self) -> ByteTarget { + ByteTarget(self.add_virtual_target()) + } + + fn assert_byte(&mut self, x: Target, u8_table_idx: usize) { + self.add_lookup_from_index(x, u8_table_idx); + } + + fn byte_constant(&mut self, c: u8) -> ByteTarget { + ByteTarget(self.constant(F::from_canonical_u8(c))) } fn state_sub_word(&mut self, sbox_lut_idx: usize, word: [ByteTarget; 4]) -> [ByteTarget; 4] { array::from_fn(|i| { let byte_target = word[i]; - self.add_lookup_from_index(byte_target, sbox_lut_idx) + ByteTarget(self.add_lookup_from_index(byte_target.0, sbox_lut_idx)) }) }@@ -162,8 +200,7 @@ xor_lut_idx: usize,
sbox_lut_idx: usize, key: [ByteTarget; NK * NB], ) -> [[ByteTarget; 4]; 4 * (NR + 1)] { - let rcon: [ByteTarget; 11] = - array::from_fn(|i| self.constant(F::from_canonical_u8(RCON[i]))); + let rcon: [ByteTarget; 11] = array::from_fn(|i| self.byte_constant(RCON[i])); let key: [[_; 4]; NK] = array::from_fn(|i| array::from_fn(|j| key[4 * i + j]));@@ -199,23 +236,28 @@ }
}) } - fn gf_2_8_add(&mut self, xor_lut_idx: usize, x: Target, y: Target) -> Target { + fn gf_2_8_add(&mut self, xor_lut_idx: usize, x: ByteTarget, y: ByteTarget) -> ByteTarget { byte_xor(self, xor_lut_idx, x, y) } - fn gf_2_8_mul(&mut self, gf_2_8_mul_lut_idx: usize, x: Target, y: Target) -> Target { - let lookup_idx = self.mul_const_add(F::from_canonical_u64(1 << 8), x, y); - self.add_lookup_from_index(lookup_idx, gf_2_8_mul_lut_idx) + fn gf_2_8_mul( + &mut self, + gf_2_8_mul_lut_idx: usize, + x: ByteTarget, + y: ByteTarget, + ) -> ByteTarget { + let lookup_idx = self.mul_const_add(F::from_canonical_u64(1 << 8), x.0, y.0); + ByteTarget(self.add_lookup_from_index(lookup_idx, gf_2_8_mul_lut_idx)) } - fn bytearray_ip_bits<const N: usize>( + fn bytearray_ip<const N: usize>( &mut self, xor_lut_idx: usize, gf_2_8_mul_lut_idx: usize, x: [ByteTarget; N], y: [ByteTarget; N], ) -> ByteTarget { - let zero = self.zero(); + let zero = ByteTarget(self.zero()); std::iter::zip(x, y).fold(zero, |acc, (a, b)| { let prod = self.gf_2_8_mul(gf_2_8_mul_lut_idx, a, b); self.gf_2_8_add(xor_lut_idx, acc, prod)@@ -223,7 +265,7 @@ })
} fn zero_byte(&mut self) -> ByteTarget { - self.zero() + ByteTarget(self.zero()) } fn empty_state(&mut self) -> StateTarget {@@ -233,23 +275,23 @@ }
} pub trait PartialWitnessByteArray { - fn set_byte_array_target(&mut self, target: ByteTarget, value: u8) -> anyhow::Result<()>; + fn set_byte_target(&mut self, target: ByteTarget, value: u8) -> anyhow::Result<()>; } impl<F: Field> PartialWitnessByteArray for PartialWitness<F> { - fn set_byte_array_target(&mut self, target: ByteTarget, value: u8) -> anyhow::Result<()> { - self.set_target(target, F::from_canonical_u8(value)) + fn set_byte_target(&mut self, target: ByteTarget, value: u8) -> anyhow::Result<()> { + self.set_target(target.0, F::from_canonical_u8(value)) } } pub trait PartialWitnessAESState { - fn set_target_state(&mut self, target: StateTarget, value: State) -> anyhow::Result<()>; + fn set_state_target(&mut self, target: StateTarget, value: State) -> anyhow::Result<()>; } impl<F: Field> PartialWitnessAESState for PartialWitness<F> { - fn set_target_state(&mut self, target: StateTarget, value: State) -> anyhow::Result<()> { + fn set_state_target(&mut self, target: StateTarget, value: State) -> anyhow::Result<()> { std::iter::zip(target.0, value).try_for_each(|(t, v)| { - std::iter::zip(t, v).try_for_each(|(t, v)| self.set_byte_array_target(t, v)) + std::iter::zip(t, v).try_for_each(|(t, v)| self.set_byte_target(t, v)) }) } }@@ -292,10 +334,10 @@ .collect();
builder.add_lookup_table_from_pairs(Arc::new(gf_2_8_mul_table)) } -pub fn state_mix_matrix_bits(builder: &mut CircuitBuilder<F, D>) -> [[ByteTarget; 4]; 4] { - let one = builder.one(); - let two = builder.two(); - let three = builder.constant(F::from_canonical_u64(3)); +pub fn state_mix_matrix(builder: &mut CircuitBuilder<F, D>) -> [[ByteTarget; 4]; 4] { + let one = builder.byte_constant(1); + let two = builder.byte_constant(2); + let three = builder.byte_constant(3); [ [two, three, one, one],@@ -311,8 +353,8 @@ xor_lut_idx: usize,
x: ByteTarget, y: ByteTarget, ) -> ByteTarget { - let lookup_idx = builder.mul_const_add(F::from_canonical_u64(1 << 8), x, y); - builder.add_lookup_from_index(lookup_idx, xor_lut_idx) + let lookup_idx = builder.mul_const_add(F::from_canonical_u64(1 << 8), x.0, y.0); + ByteTarget(builder.add_lookup_from_index(lookup_idx, xor_lut_idx)) } #[cfg(test)]@@ -321,7 +363,10 @@ use std::array;
use anyhow::Result; use plonky2::{ - field::{goldilocks_field::GoldilocksField as F, types::Field}, + field::{ + goldilocks_field::GoldilocksField as F, + types::{Field, Field64}, + }, iop::witness::{PartialWitness, WitnessWrite}, plonk::{ circuit_builder::CircuitBuilder, circuit_data::CircuitConfig,@@ -332,17 +377,46 @@ use rand::RngExt;
use super::{ ByteTarget, CircuitBuilderAESState, D, PartialWitnessAESState, PartialWitnessByteArray, - byte_xor_lut, gf_2_8_mul_lut, sbox_lut, state_mix_matrix_bits, + byte_xor_lut, gf_2_8_mul_lut, sbox_lut, state_mix_matrix, }; use crate::native_aes::{State, encrypt_block, key_expansion, mix_columns, sub_bytes}; #[test] + fn test_assert_byte() -> Result<()> { + // Circuit declaration + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::<F, D>::new(config); + + let u8_table_idx = sbox_lut(&mut builder); + + let byte_target = builder.add_virtual_byte_target(u8_table_idx); + + let data = builder.build::<PoseidonGoldilocksConfig>(); + + let mut rng = rand::rng(); + let test_values: [u64; 10] = array::from_fn(|_| rng.random_range(0..F::ORDER)); + + test_values.into_iter().try_for_each(|tv| { + let mut pw = PartialWitness::<F>::new(); + pw.set_target(byte_target.0, F::from_canonical_u64(tv))?; + + if tv > u8::MAX as u64 { + assert!(data.prove(pw).is_err()); + Ok(()) + } else { + let proof = data.prove(pw)?; + data.verify(proof) + } + }) + } + + #[test] fn test_sub_bytes() -> Result<()> { // Circuit declaration let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::<F, D>::new(config); - let state_target = builder.add_virtual_state(); + let state_target = builder.add_virtual_state_target_unsafe(); let sbox_lut = sbox_lut(&mut builder); let out_state_target = builder.state_sub_bytes(sbox_lut, state_target);@@ -356,8 +430,8 @@ test_states.into_iter().try_for_each(|s| {
let expected_result = sub_bytes(s); let mut pw = PartialWitness::<F>::new(); - pw.set_target_state(state_target, s)?; - pw.set_target_state(out_state_target, expected_result)?; + pw.set_state_target(state_target, s)?; + pw.set_state_target(out_state_target, expected_result)?; let proof = data.prove(pw)?; data.verify(proof)@@ -372,8 +446,8 @@ let mut builder = CircuitBuilder::<F, D>::new(config);
let xor_lut_idx = byte_xor_lut(&mut builder); let gf_2_8_mul_lut_idx = gf_2_8_mul_lut(&mut builder); - let state_target = builder.add_virtual_state(); - let mix_matrix = state_mix_matrix_bits(&mut builder); + let state_target = builder.add_virtual_state_target_unsafe(); + let mix_matrix = state_mix_matrix(&mut builder); let out_state_target = builder.state_mix_columns(xor_lut_idx, gf_2_8_mul_lut_idx, mix_matrix, state_target);@@ -387,8 +461,8 @@ test_states.into_iter().try_for_each(|s| {
let expected_result = mix_columns(s); let mut pw = PartialWitness::<F>::new(); - pw.set_target_state(state_target, s)?; - pw.set_target_state(out_state_target, expected_result)?; + pw.set_state_target(state_target, s)?; + pw.set_state_target(out_state_target, expected_result)?; let proof = data.prove(pw)?; data.verify(proof)@@ -403,8 +477,8 @@ let mut builder = CircuitBuilder::<F, D>::new(config);
let gf_2_8_mul_lut_idx = gf_2_8_mul_lut(&mut builder); - let a = builder.add_virtual_target(); - let b = builder.add_virtual_target(); + let a = builder.add_virtual_byte_target_unsafe(); + let b = builder.add_virtual_byte_target_unsafe(); let a_times_b = builder.gf_2_8_mul(gf_2_8_mul_lut_idx, a, b);@@ -424,18 +498,11 @@ (0x57, 0x13, 0xfe),
]; test_values .into_iter() - .map(|(a, b, c)| { - ( - F::from_canonical_u8(a), - F::from_canonical_u8(b), - F::from_canonical_u8(c), - ) - }) .try_for_each(|(a_val, b_val, expected_result)| { let mut pw = PartialWitness::<F>::new(); - pw.set_target(a, a_val)?; - pw.set_target(b, b_val)?; - pw.set_target(a_times_b, expected_result)?; + pw.set_byte_target(a, a_val)?; + pw.set_byte_target(b, b_val)?; + pw.set_byte_target(a_times_b, expected_result)?; let proof = data.prove(pw)?; data.verify(proof)@@ -450,8 +517,8 @@ let mut builder = CircuitBuilder::<F, D>::new(config);
let xor_lut_idx = byte_xor_lut(&mut builder); - let a = builder.add_virtual_target(); - let b = builder.add_virtual_target(); + let a = builder.add_virtual_byte_target_unsafe(); + let b = builder.add_virtual_byte_target_unsafe(); let a_plus_b = builder.gf_2_8_add(xor_lut_idx, a, b);@@ -466,18 +533,11 @@ (x, y, x ^ y)
}); test_values .into_iter() - .map(|(a, b, c)| { - ( - F::from_canonical_u8(a), - F::from_canonical_u8(b), - F::from_canonical_u8(c), - ) - }) .try_for_each(|(a_val, b_val, expected_result)| { let mut pw = PartialWitness::<F>::new(); - pw.set_target(a, a_val)?; - pw.set_target(b, b_val)?; - pw.set_target(a_plus_b, expected_result)?; + pw.set_byte_target(a, a_val)?; + pw.set_byte_target(b, b_val)?; + pw.set_byte_target(a_plus_b, expected_result)?; let proof = data.prove(pw)?; data.verify(proof)@@ -523,7 +583,8 @@ // Circuit declaration
let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::<F, D>::new(config); - let key_target: [ByteTarget; NK * NB] = array::from_fn(|_| builder.add_virtual_target()); + let key_target: [ByteTarget; NK * NB] = + array::from_fn(|_| builder.add_virtual_byte_target_unsafe()); let xor_lut_idx = byte_xor_lut(&mut builder); let sbox_lut_idx = sbox_lut(&mut builder); let expanded_key_target =@@ -543,10 +604,10 @@ let w = key_expansion::<NK, NB, NR>(&key);
let mut pw = PartialWitness::<F>::new(); - std::iter::zip(key_target, key).try_for_each(|(t, v)| pw.set_byte_array_target(t, v))?; + std::iter::zip(key_target, key).try_for_each(|(t, v)| pw.set_byte_target(t, v))?; std::iter::zip(expanded_key_target, w).try_for_each(|(t, v)| { - std::iter::zip(t, v).try_for_each(|(t, v)| pw.set_byte_array_target(t, v)) + std::iter::zip(t, v).try_for_each(|(t, v)| pw.set_byte_target(t, v)) })?; let proof = data.prove(pw)?;@@ -606,15 +667,16 @@ // Circuit declaration
let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::<F, D>::new(config); - let key_target: [ByteTarget; NK * NB] = array::from_fn(|_| builder.add_virtual_target()); + let key_target: [ByteTarget; NK * NB] = + array::from_fn(|_| builder.add_virtual_byte_target_unsafe()); let xor_lut_idx = byte_xor_lut(&mut builder); let gf_2_8_mul_lut_idx = gf_2_8_mul_lut(&mut builder); let sbox_lut_idx = sbox_lut(&mut builder); - let mix_matrix = state_mix_matrix_bits(&mut builder); + let mix_matrix = state_mix_matrix(&mut builder); let expanded_key_target: [[ByteTarget; 4]; 4 * (NR + 1)] = builder.key_expansion::<NK, NB, NR>(xor_lut_idx, sbox_lut_idx, key_target); - let input_state_target = builder.add_virtual_state(); + let input_state_target = builder.add_virtual_state_target(sbox_lut_idx); let output = builder.encrypt_block( xor_lut_idx,@@ -647,16 +709,16 @@ let native_ciphertext = encrypt_block::<NR>(&input_state, &expanded_key);
let mut pw = PartialWitness::<F>::new(); - std::iter::zip(key_target, key).try_for_each(|(t, v)| pw.set_byte_array_target(t, v))?; + std::iter::zip(key_target, key).try_for_each(|(t, v)| pw.set_byte_target(t, v))?; - pw.set_target_state(input_state_target, input_state_matrix)?; + pw.set_state_target(input_state_target, input_state_matrix)?; std::iter::zip(expanded_key_target, expanded_key).try_for_each(|(t, v)| { - std::iter::zip(t, v).try_for_each(|(t, v)| pw.set_byte_array_target(t, v)) + std::iter::zip(t, v).try_for_each(|(t, v)| pw.set_byte_target(t, v)) })?; std::iter::zip(output.0, native_ciphertext).try_for_each(|(o, e)| { - std::iter::zip(o, e).try_for_each(|(o, e)| pw.set_byte_array_target(o, e)) + std::iter::zip(o, e).try_for_each(|(o, e)| pw.set_byte_target(o, e)) })?; let proof = data.prove(pw)?;
@@ -16,7 +16,7 @@ use crate::{
D, circuit_aes::{ ByteTarget, CircuitBuilderAESState, PartialWitnessByteArray, StateTarget, byte_xor, - byte_xor_lut, gf_2_8_mul_lut, sbox_lut, state_mix_matrix_bits, + byte_xor_lut, gf_2_8_mul_lut, sbox_lut, state_mix_matrix, }, constants::TAG_LEN, };@@ -47,17 +47,21 @@ [(); NK * NB]:,
[(); 4 * (NR + 1)]:, { pub fn build(builder: &mut CircuitBuilder<F, D>) -> Self { + // Declare LUTs + let sbox_lut = sbox_lut(builder); + let xor_lut = byte_xor_lut(builder); + let gf_2_8_mul_lut = gf_2_8_mul_lut(builder); + // add targets - let key: [ByteTarget; NK * NB] = array::from_fn(|_| builder.add_virtual_target()); - let nonce: [ByteTarget; 12] = array::from_fn(|_| builder.add_virtual_target()); - let pt: [ByteTarget; L] = array::from_fn(|_| builder.add_virtual_target()); + let key: [ByteTarget; NK * NB] = + array::from_fn(|_| builder.add_virtual_byte_target(sbox_lut)); + let nonce: [ByteTarget; 12] = array::from_fn(|_| builder.add_virtual_byte_target(sbox_lut)); + let pt: [ByteTarget; L] = array::from_fn(|_| builder.add_virtual_byte_target(sbox_lut)); - let tag: [ByteTarget; TAG_LEN / 8] = array::from_fn(|_| builder.add_virtual_target()); + let tag: [ByteTarget; TAG_LEN / 8] = + array::from_fn(|_| builder.add_virtual_byte_target(sbox_lut)); - let sbox_lut = sbox_lut(builder); - let xor_lut = byte_xor_lut(builder); - let gf_2_8_mul_lut = gf_2_8_mul_lut(builder); - let mix_matrix = state_mix_matrix_bits(builder); + let mix_matrix = state_mix_matrix(builder); let a: &[ByteTarget] = &[]; // additional authenticated data@@ -79,7 +83,7 @@ .flatten();
// 2. J_0 let zero_byte = builder.zero_byte(); - let one_byte = builder.one(); + let one_byte = builder.byte_constant(1); let j0: [ByteTarget; 16] = if nonce.len() * 8 == 96 { // J_0 = IV || 0^31 || 1 let mut out = [zero_byte; 16];@@ -121,9 +125,9 @@ // 5. S = GHASH()
let const_a_len_u8: [u8; 8] = (a.len() * 8).to_be_bytes(); // const let const_c_len_u8: [u8; 8] = (ct.len() * 8).to_be_bytes(); // const let a_len: [ByteTarget; 8] = - array::from_fn(|byte_i| builder.constant(F::from_canonical_u8(const_a_len_u8[byte_i]))); + array::from_fn(|byte_i| builder.byte_constant(const_a_len_u8[byte_i])); let c_len: [ByteTarget; 8] = - array::from_fn(|byte_i| builder.constant(F::from_canonical_u8(const_c_len_u8[byte_i]))); + array::from_fn(|byte_i| builder.byte_constant(const_c_len_u8[byte_i])); let ghash_input_vec = [ a.to_vec(), vec![zero_byte; v],@@ -156,7 +160,7 @@ &s,
); let t_vec = msb_t_target(TAG_LEN / 8, &msb_input); - std::iter::zip(tag, t_vec).for_each(|(a, b)| builder.connect(a, b)); + std::iter::zip(tag, t_vec).for_each(|(a, b)| builder.connect(a.0, b.0)); Self { key,@@ -188,18 +192,17 @@ ct_arr.copy_from_slice(ct);
let mut tag_arr: [u8; TAG_LEN / 8] = [0u8; TAG_LEN / 8]; tag_arr.copy_from_slice(tag); - std::iter::zip(self.key, key).try_for_each(|(t, v)| pw.set_byte_array_target(t, *v))?; - std::iter::zip(self.nonce, nonce).try_for_each(|(t, v)| pw.set_byte_array_target(t, *v))?; - std::iter::zip(self.pt, pt_arr).try_for_each(|(t, v)| pw.set_byte_array_target(t, v))?; + std::iter::zip(self.key, key).try_for_each(|(t, v)| pw.set_byte_target(t, *v))?; + std::iter::zip(self.nonce, nonce).try_for_each(|(t, v)| pw.set_byte_target(t, *v))?; + std::iter::zip(self.pt, pt_arr).try_for_each(|(t, v)| pw.set_byte_target(t, v))?; - std::iter::zip(self.ct, ct_arr).try_for_each(|(t, v)| pw.set_byte_array_target(t, v))?; + std::iter::zip(self.ct, ct_arr).try_for_each(|(t, v)| pw.set_byte_target(t, v))?; if TAG { - std::iter::zip(self.tag, tag_arr) - .try_for_each(|(t, v)| pw.set_byte_array_target(t, v))?; + std::iter::zip(self.tag, tag_arr).try_for_each(|(t, v)| pw.set_byte_target(t, v))?; } else { self.tag .iter() - .try_for_each(|t| pw.set_byte_array_target(*t, 0u8))?; + .try_for_each(|t| pw.set_byte_target(*t, 0u8))?; } Ok(()) }@@ -292,37 +295,32 @@ u8_bitref_lut_idx: usize,
x: [ByteTarget; 16], y: [ByteTarget; 16], ) -> [ByteTarget; 16] { - let zero = builder.zero(); + let zero = builder.zero_byte(); // R: 10000111 (= 225) || 0^120 (in little-endian) - let r_first = builder.constant(F::from_canonical_u8(225)); + let r_first = builder.byte_constant(225); let mut z = [zero; 16]; let mut v = y; for i in 0..128 { let byte_index = i / 8; let bit_index = 7 - (i % 8); - let bit_idx_target = builder.constant(F::from_canonical_usize(bit_index)); - let xi = BoolTarget::new_unsafe(u8_bitref( - builder, - u8_bitref_lut_idx, - x[byte_index], - bit_idx_target, - )); + let bit_idx_target = builder.byte_constant(bit_index as u8); + let xi = u8_bitref(builder, u8_bitref_lut_idx, x[byte_index], bit_idx_target); // set z = if xi==1: z^v, else: z for b in 0..16 { let z_xor_v = byte_xor(builder, xor_lut_idx, z[b], v[b]); - z[b] = builder.select(xi, z_xor_v, z[b]); + z[b] = ByteTarget(builder.select(xi, z_xor_v.0, z[b].0)); } - let lsb = BoolTarget::new_unsafe(u8_bitref(builder, u8_bitref_lut_idx, v[15], zero)); // (little-endian) + let lsb = u8_bitref(builder, u8_bitref_lut_idx, v[15], zero); // (little-endian) v = right_shift_one_target(builder, u8_unit_right_shift_lut_idx, &v); // if lsb==1: v=v^R, else: v let v_xor_r = byte_xor(builder, xor_lut_idx, v[0], r_first); - v[0] = builder.select(lsb, v_xor_r, v[0]); + v[0] = ByteTarget(builder.select(lsb, v_xor_r.0, v[0].0)); } z }@@ -338,9 +336,10 @@ for i in 0..16 {
let current = v[i]; let mut shifted = u8_unit_right_shift(builder, u8_unit_right_shift_lut_idx, current); let next_carry = - builder.mul_const_add(F::from_canonical_u64(2) * F::NEG_ONE, shifted, current); + builder.mul_const_add(F::from_canonical_u64(2) * F::NEG_ONE, shifted.0, current.0); - shifted = builder.mul_const_add(F::from_canonical_u64(1 << 7), carry, shifted); + shifted = + ByteTarget(builder.mul_const_add(F::from_canonical_u64(1 << 7), carry, shifted.0)); r[i] = shifted; carry = next_carry;@@ -359,10 +358,10 @@
let mut carry = builder.one(); for byte_index in (12..16).rev() { let a = block[byte_index]; - let sum = builder.add(a, carry); - let a_is_u8_max = builder.is_equal(a, u8_max); + let sum = builder.add(a.0, carry); + let a_is_u8_max = builder.is_equal(a.0, u8_max); let carry_out = builder.mul(carry, a_is_u8_max.target); - r[byte_index] = builder.select(a_is_u8_max, zero, sum); + r[byte_index] = ByteTarget(builder.select(a_is_u8_max, zero, sum)); carry = carry_out; } r@@ -401,7 +400,7 @@ builder: &mut CircuitBuilder<F, D>,
u8_unit_right_shift_lut_idx: usize, x: ByteTarget, ) -> ByteTarget { - builder.add_lookup_from_index(x, u8_unit_right_shift_lut_idx) + ByteTarget(builder.add_lookup_from_index(x.0, u8_unit_right_shift_lut_idx)) } /// Lookup table for u8 bit referencing.@@ -420,9 +419,9 @@ builder: &mut CircuitBuilder<F, D>,
u8_bitref_lut_idx: usize, x: ByteTarget, i: ByteTarget, -) -> ByteTarget { - let lookup_idx = builder.mul_const_add(F::from_canonical_u64(8), x, i); - builder.add_lookup_from_index(lookup_idx, u8_bitref_lut_idx) +) -> BoolTarget { + let lookup_idx = builder.mul_const_add(F::from_canonical_u64(8), x.0, i.0); + BoolTarget::new_unsafe(builder.add_lookup_from_index(lookup_idx, u8_bitref_lut_idx)) } fn le_bits_from_byte(v: u8) -> [bool; 8] {@@ -486,14 +485,18 @@ // Circuit declaration
let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::<F, D>::new(config); - let key_target: [ByteTarget; NK * NB] = array::from_fn(|_| builder.add_virtual_target()); - let nonce_target: [ByteTarget; 12] = array::from_fn(|_| builder.add_virtual_target()); - let icb_target: [ByteTarget; 16] = array::from_fn(|_| builder.add_virtual_target()); - let pt_target: [ByteTarget; L] = array::from_fn(|_| builder.add_virtual_target()); + let key_target: [ByteTarget; NK * NB] = + array::from_fn(|_| builder.add_virtual_byte_target_unsafe()); + let nonce_target: [ByteTarget; 12] = + array::from_fn(|_| builder.add_virtual_byte_target_unsafe()); + let icb_target: [ByteTarget; 16] = + array::from_fn(|_| builder.add_virtual_byte_target_unsafe()); + let pt_target: [ByteTarget; L] = + array::from_fn(|_| builder.add_virtual_byte_target_unsafe()); let sbox_lut = sbox_lut(&mut builder); let xor_lut = byte_xor_lut(&mut builder); let gf_2_8_mul_lut = gf_2_8_mul_lut(&mut builder); - let mix_matrix = state_mix_matrix_bits(&mut builder); + let mix_matrix = state_mix_matrix(&mut builder); let key_expanded_target = builder.key_expansion::<NK, NB, NR>(xor_lut, sbox_lut, key_target);@@ -518,14 +521,13 @@ let data = builder.build::<PoseidonGoldilocksConfig>();
// set values to circuit let mut pw = PartialWitness::<F>::new(); - std::iter::zip(key_target, key).try_for_each(|(t, v)| pw.set_byte_array_target(t, *v))?; - std::iter::zip(nonce_target, nonce) - .try_for_each(|(t, v)| pw.set_byte_array_target(t, *v))?; - std::iter::zip(icb_target, icb).try_for_each(|(t, v)| pw.set_byte_array_target(t, *v))?; - std::iter::zip(pt_target, pt).try_for_each(|(t, v)| pw.set_byte_array_target(t, *v))?; + std::iter::zip(key_target, key).try_for_each(|(t, v)| pw.set_byte_target(t, *v))?; + std::iter::zip(nonce_target, nonce).try_for_each(|(t, v)| pw.set_byte_target(t, *v))?; + std::iter::zip(icb_target, icb).try_for_each(|(t, v)| pw.set_byte_target(t, *v))?; + std::iter::zip(pt_target, pt).try_for_each(|(t, v)| pw.set_byte_target(t, *v))?; std::iter::zip(gctr_out_target, expected) - .try_for_each(|(t, v)| pw.set_byte_array_target(t, v))?; + .try_for_each(|(t, v)| pw.set_byte_target(t, v))?; let proof = data.prove(pw)?; data.verify(proof)@@ -544,7 +546,8 @@ let mut builder = CircuitBuilder::<F, D>::new(config);
let u8_unit_right_shift_lut_idx = u8_unit_right_shift_lut(&mut builder); - let x_target: [ByteTarget; 16] = array::from_fn(|_| builder.add_virtual_target()); + let x_target: [ByteTarget; 16] = + array::from_fn(|_| builder.add_virtual_byte_target_unsafe()); let out_target: [ByteTarget; 16] = right_shift_one_target(&mut builder, u8_unit_right_shift_lut_idx, &x_target);@@ -554,10 +557,9 @@ let data = builder.build::<PoseidonGoldilocksConfig>();
// set values to circuit let mut pw = PartialWitness::<F>::new(); - std::iter::zip(x_target, x).try_for_each(|(t, v)| pw.set_byte_array_target(t, v))?; + std::iter::zip(x_target, x).try_for_each(|(t, v)| pw.set_byte_target(t, v))?; - std::iter::zip(out_target, expected) - .try_for_each(|(t, v)| pw.set_byte_array_target(t, v))?; + std::iter::zip(out_target, expected).try_for_each(|(t, v)| pw.set_byte_target(t, v))?; let proof = data.prove(pw)?; data.verify(proof)?;@@ -601,8 +603,10 @@ let xor_lut_idx = byte_xor_lut(&mut builder);
let u8_unit_right_shift_lut_idx = u8_unit_right_shift_lut(&mut builder); let u8_bitref_lut_idx = u8_bitref_lut(&mut builder); - let x_target: [ByteTarget; 16] = array::from_fn(|_| builder.add_virtual_target()); - let y_target: [ByteTarget; 16] = array::from_fn(|_| builder.add_virtual_target()); + let x_target: [ByteTarget; 16] = + array::from_fn(|_| builder.add_virtual_byte_target_unsafe()); + let y_target: [ByteTarget; 16] = + array::from_fn(|_| builder.add_virtual_byte_target_unsafe()); let out_target = gf_2_128_mul_target( &mut builder,@@ -618,11 +622,10 @@ let data = builder.build::<PoseidonGoldilocksConfig>();
// set values to circuit let mut pw = PartialWitness::<F>::new(); - std::iter::zip(x_target, x).try_for_each(|(t, v)| pw.set_byte_array_target(t, v))?; - std::iter::zip(y_target, y).try_for_each(|(t, v)| pw.set_byte_array_target(t, v))?; + std::iter::zip(x_target, x).try_for_each(|(t, v)| pw.set_byte_target(t, v))?; + std::iter::zip(y_target, y).try_for_each(|(t, v)| pw.set_byte_target(t, v))?; - std::iter::zip(out_target, expected) - .try_for_each(|(t, v)| pw.set_byte_array_target(t, v))?; + std::iter::zip(out_target, expected).try_for_each(|(t, v)| pw.set_byte_target(t, v))?; let proof = data.prove(pw)?; data.verify(proof)@@ -658,8 +661,10 @@ let xor_lut_idx = byte_xor_lut(&mut builder);
let u8_unit_right_shift_lut_idx = u8_unit_right_shift_lut(&mut builder); let u8_bitref_lut_idx = u8_bitref_lut(&mut builder); - let h_target: [ByteTarget; 16] = array::from_fn(|_| builder.add_virtual_target()); - let x_target: [ByteTarget; L] = array::from_fn(|_| builder.add_virtual_target()); + let h_target: [ByteTarget; 16] = + array::from_fn(|_| builder.add_virtual_byte_target_unsafe()); + let x_target: [ByteTarget; L] = + array::from_fn(|_| builder.add_virtual_byte_target_unsafe()); // let ghash_out_target = ghash_target::<L>(&mut builder, h_target, &x_target); let ghash_out_target = ghash_target(@@ -676,11 +681,11 @@ let data = builder.build::<PoseidonGoldilocksConfig>();
// set values to circuit let mut pw = PartialWitness::<F>::new(); - std::iter::zip(h_target, h).try_for_each(|(t, v)| pw.set_byte_array_target(t, v))?; - std::iter::zip(x_target, x).try_for_each(|(t, v)| pw.set_byte_array_target(t, *v))?; + std::iter::zip(h_target, h).try_for_each(|(t, v)| pw.set_byte_target(t, v))?; + std::iter::zip(x_target, x).try_for_each(|(t, v)| pw.set_byte_target(t, *v))?; std::iter::zip(ghash_out_target, expected) - .try_for_each(|(t, v)| pw.set_byte_array_target(t, v))?; + .try_for_each(|(t, v)| pw.set_byte_target(t, v))?; let proof = data.prove(pw)?; data.verify(proof)