arnaucube
arnaucube/plonky2-crypto-gadgetsPublic Self-hosted repository
Merge branch 'main' into aes-gcm-circuits (after workspace re-structure)
arnaucube git@arnaucube.com
Tue, 17 Feb 2026 09:52:46 +0000
commit

de7dfd1178ff423a7ef07218cfd8f01cf66014c8

parent

f8f781790feaa42024d739afcead643659025713

A .github/workflows/clippy.yml

@@ -0,0 +1,21 @@

+name: Clippy Check + +on: + pull_request: + branches: [ main ] + types: [ready_for_review, opened, synchronize, reopened] + push: + branches: [ main ] + +jobs: + clippy: + if: github.event.pull_request.draft == false + name: Rust formatting + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + components: clippy + - name: Check lints with clippy + run: cargo clippy --tests --examples
A .github/workflows/rustfmt.yml

@@ -0,0 +1,21 @@

+name: Rustfmt Check + +on: + pull_request: + branches: [ main ] + types: [ready_for_review, opened, synchronize, reopened] + push: + branches: [ main ] + +jobs: + rustfmt: + if: github.event.pull_request.draft == false + name: Rust formatting + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + components: rustfmt + - name: Check formatting + uses: actions-rust-lang/rustfmt@v1
A .github/workflows/tests.yml

@@ -0,0 +1,20 @@

+name: Rust Tests + +on: + pull_request: + branches: [ main ] + types: [ready_for_review, opened, synchronize, reopened] + push: + branches: [ main ] + +jobs: + test: + if: github.event.pull_request.draft == false + name: Rust tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up Rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + - name: Run tests + run: cargo test --release
A .github/workflows/typos.toml

@@ -0,0 +1,3 @@

+[default.extend-words] +ciph = "ciph" +ba = "ba"
A .github/workflows/typos.yml

@@ -0,0 +1,21 @@

+name: typos +on: + pull_request: + branches: [ main ] + types: [ready_for_review, opened, synchronize, reopened] + push: + branches: + - main + +jobs: + typos: + if: github.event.pull_request.draft == false + name: Spell Check with Typos + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Use typos with config file + uses: crate-ci/typos@master + with: + config: .github/workflows/typos.toml +
M Cargo.toml → Cargo.toml

@@ -1,14 +1,10 @@

-[package] -name = "plonky2-aes" -version = "0.1.0" -edition = "2024" +[workspace] +members = [ + "aes-gcm" +] -[dependencies] +resolver = "2" + +[workspace.dependencies] plonky2 = { git = "https://github.com/0xPARC/plonky2.git", rev = "109d517d09c210ae4c2cee381d3e3fbc04aa3812" } anyhow = "1.0.56" - -[dev-dependencies] -rand = "0.10.0" -aes = "0.8.4" -aes-gcm = "0.10.3" -hex = "0.4.3"
M README.md → README.md

@@ -1,8 +1,7 @@

-# plonky2-aes -Plonky2 circuits for AES encryption system as described at -- AES: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf -- AES-GCM (Galois Counter Mode): https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf +# plonky2-crypto-gadgets > Warning: this code is unaudited. -Example of usage at [examples](https://github.com/0xPARC/plonky2-aes/blob/main/examples) directory. +- [aes-gcm](/aes-gcm): Plonky2 circuits for AES & AES-GCM encryption system as described at + - AES: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf + - AES-GCM (Galois Counter Mode): https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
A aes-gcm/Cargo.toml

@@ -0,0 +1,14 @@

+[package] +name = "plonky2-aes" +version = "0.1.0" +edition = "2024" + +[dependencies] +plonky2 = { workspace = true } +anyhow = { workspace = true } + +[dev-dependencies] +rand = "0.10.0" +aes = "0.8.4" +aes-gcm = "0.10.3" +hex = "0.4.3"
A aes-gcm/README.md

@@ -0,0 +1,25 @@

+# plonky2-aes + +- [aes-gcm](/aes-gcm): Plonky2 circuits for AES & AES-GCM encryption system as described at + - AES: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf + - AES-GCM (Galois Counter Mode): https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf + + +> Warning: this code is unaudited. + +Full example of usage at [examples](https://github.com/0xPARC/plonky2-aes/blob/main/examples) directory. +```rust +// circuit declaration +let config = CircuitConfig::standard_recursion_zk_config(); +let mut builder = CircuitBuilder::<F, D>::new(config); +let aes_targets = AesGcm128Target::<L>::new_virtual(&mut builder); +aes_targets.build_circuit(&mut builder); +let data = builder.build::<PoseidonGoldilocksConfig>(); + +// set values to circuit +let mut pw = PartialWitness::<F>::new(); +aes_targets.set_targets(&mut pw, key, nonce, pt, ct, tag)?; + +let proof = data.prove(pw)?; +data.verify(proof) +```
M examples/aes_gcm_128.rs → aes-gcm/examples/aes_gcm_128.rs

@@ -11,7 +11,6 @@ circuit_builder::CircuitBuilder, circuit_data::CircuitConfig,

config::PoseidonGoldilocksConfig, }, }; - use plonky2_aes::{AesGcm128Target, D, KEY_LEN_128}; fn main() -> Result<()> {

@@ -24,7 +23,7 @@ let pt: &[u8; L] = &[231u8; L]; // plaintext

// use external rust library to compute the ciphertext & tag let nonce_ext = aes_gcm::Nonce::from_slice(nonce); - use aes_gcm::{aead::Aead, KeyInit}; // needed traits + use aes_gcm::{KeyInit, aead::Aead}; // needed traits let cipher = aes_gcm::Aes128Gcm::new_from_slice(key.as_slice()).unwrap(); let encrypt_res = cipher.encrypt(nonce_ext, pt.as_ref()).unwrap(); let ct = &encrypt_res[..L]; // ciphertext

@@ -33,8 +32,8 @@

// alternatively we could use this repo's rust implementation (only for tests) // let (ct, tag) = plonky2_aes::native_gcm::encrypt::<4, 4, 10>(key, nonce, pt); - // Circuit declaration - let config = CircuitConfig::standard_recursion_config(); + // circuit declaration + let config = CircuitConfig::standard_recursion_zk_config(); let mut builder = CircuitBuilder::<F, D>::new(config); let aes_targets = AesGcm128Target::<L>::new_virtual(&mut builder); aes_targets.build_circuit(&mut builder);

@@ -49,7 +48,7 @@ let data = builder.build::<PoseidonGoldilocksConfig>();

// set values to circuit let mut pw = PartialWitness::<F>::new(); - aes_targets.set_targets(&mut pw, key, nonce, pt, &ct, &tag)?; + aes_targets.set_targets(&mut pw, key, nonce, pt, ct, tag)?; let proof = data.prove(pw)?; data.verify(proof)
M examples/aes_gcm_256.rs → aes-gcm/examples/aes_gcm_256.rs

@@ -11,7 +11,6 @@ circuit_builder::CircuitBuilder, circuit_data::CircuitConfig,

config::PoseidonGoldilocksConfig, }, }; - use plonky2_aes::{AesGcm256Target, D, KEY_LEN_256}; fn main() -> Result<()> {

@@ -24,7 +23,7 @@ let pt: &[u8; L] = &[231u8; L]; // plaintext

// use external rust library to compute the ciphertext & tag let nonce_ext = aes_gcm::Nonce::from_slice(nonce); - use aes_gcm::{aead::Aead, KeyInit}; // needed traits + use aes_gcm::{KeyInit, aead::Aead}; // needed traits let cipher = aes_gcm::Aes256Gcm::new_from_slice(key.as_slice()).unwrap(); let encrypt_res = cipher.encrypt(nonce_ext, pt.as_ref()).unwrap(); let ct = &encrypt_res[..L]; // ciphertext

@@ -33,8 +32,8 @@

// alternatively we could use this repo's rust implementation (only for tests) // let (ct, tag) = plonky2_aes::native_gcm::encrypt::<8, 4, 14>(key, nonce, pt); - // Circuit declaration - let config = CircuitConfig::standard_recursion_config(); + // circuit declaration + let config = CircuitConfig::standard_recursion_zk_config(); let mut builder = CircuitBuilder::<F, D>::new(config); let aes_targets = AesGcm256Target::<L>::new_virtual(&mut builder); aes_targets.build_circuit(&mut builder);

@@ -49,7 +48,7 @@ let data = builder.build::<PoseidonGoldilocksConfig>();

// set values to circuit let mut pw = PartialWitness::<F>::new(); - aes_targets.set_targets(&mut pw, key, nonce, pt, &ct, &tag)?; + aes_targets.set_targets(&mut pw, key, nonce, pt, ct, tag)?; let proof = data.prove(pw)?; data.verify(proof)
A rustfmt.toml

@@ -0,0 +1,3 @@

+imports_granularity = "Crate" +reorder_imports = true # default +group_imports = "StdExternalCrate"
M src/circuit_aes.rs → aes-gcm/src/circuit_aes.rs

@@ -1,4 +1,4 @@

-//! For LICENSE check out https://github.com/0xPARC/plonky2-aes/blob/main/LICENSE +//! For LICENSE check out https://github.com/0xPARC/plonky2-crypto-gadgets/blob/main/LICENSE //! //! Plonky2 circuit implementation of //! [AES](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf).

@@ -16,9 +16,9 @@ plonk::circuit_builder::CircuitBuilder,

}; use crate::{ - constants::{RCON, SBOX}, - native_aes::{rot_word, shift_rows, State}, D, + constants::{RCON, SBOX}, + native_aes::{State, rot_word, shift_rows}, }; #[derive(Debug, Copy, Clone)]

@@ -65,7 +65,7 @@ ) -> StateTarget;

/// AddRoundKey fn state_add_round_key(&mut self, round_key: &[[ByteTarget; 4]], s: StateTarget) - -> StateTarget; + -> StateTarget; /// KeyExpansion fn key_expansion<const NK: usize, const NB: usize, const NR: usize>(

@@ -414,12 +414,10 @@ };

use rand::RngExt; use super::{ - sbox_lut, state_mix_matrix_bits, ByteTarget, CircuitBuilderAESState, - PartialWitnessAESState, PartialWitnessByteArray, + ByteTarget, CircuitBuilderAESState, D, PartialWitnessAESState, PartialWitnessByteArray, + sbox_lut, state_mix_matrix_bits, }; - use crate::native_aes::{encrypt_block, key_expansion, mix_columns, sub_bytes, State}; - - use super::D; + use crate::native_aes::{State, encrypt_block, key_expansion, mix_columns, sub_bytes}; #[test] fn test_sub_bytes() -> Result<()> {
M src/circuit_gcm.rs → aes-gcm/src/circuit_gcm.rs

@@ -1,25 +1,24 @@

-//! For LICENSE check out https://github.com/0xPARC/plonky2-aes/blob/main/LICENSE +//! For LICENSE check out https://github.com/0xPARC/plonky2-crypto-gadgets/blob/main/LICENSE //! //! Plonky2 circuit implementation of //! [AES-GCM (Galois Counter Mode)](https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf). -use anyhow::Result; use std::array; +use anyhow::Result; use plonky2::{ field::{goldilocks_field::GoldilocksField as F, types::Field}, - iop::target::BoolTarget, - iop::witness::PartialWitness, + iop::{target::BoolTarget, witness::PartialWitness}, plonk::circuit_builder::CircuitBuilder, }; use crate::{ + D, circuit_aes::{ - le_bits_from_byte, sbox_lut, state_mix_matrix_bits, xor, ByteTarget, - CircuitBuilderAESState, PartialWitnessByteArray, StateTarget, + ByteTarget, CircuitBuilderAESState, PartialWitnessByteArray, StateTarget, + le_bits_from_byte, sbox_lut, state_mix_matrix_bits, xor, }, constants::TAG_LEN, - D, }; pub struct AesGcmTarget<

@@ -101,7 +100,7 @@ out[..12].copy_from_slice(self.nonce.as_slice());

out[12..16].copy_from_slice(&[zero_byte, zero_byte, zero_byte, one_byte]); out } else { - panic!("unsuported at initial version; nonce.len()=12 (96 bits)"); + panic!("unsupported at initial version; nonce.len()=12 (96 bits)"); }; // 3. C=GCTR()

@@ -415,14 +414,12 @@ config::PoseidonGoldilocksConfig,

}, }; - use super::*; + use super::{D, *}; use crate::{ circuit_aes::PartialWitnessByteArray, native_aes::key_expansion, native_gcm::{gctr, gf_2_128_mul, ghash, right_shift_one}, }; - - use super::D; #[test] fn test_gctr() -> Result<()> {

@@ -435,8 +432,8 @@ test_gctr_opt::<8, 4, 14, 13>()?;

Ok(()) } - fn test_gctr_opt<const NK: usize, const NB: usize, const NR: usize, const L: usize>( - ) -> Result<()> + fn test_gctr_opt<const NK: usize, const NB: usize, const NR: usize, const L: usize>() + -> Result<()> where [(); 4 * (NR + 1)]:, [(); NK * NB]:,

@@ -541,8 +538,8 @@ test_gf_mul_opt::<8, 4, 14, 16>()?;

Ok(()) } - fn test_gf_mul_opt<const NK: usize, const NB: usize, const NR: usize, const L: usize>( - ) -> Result<()> + fn test_gf_mul_opt<const NK: usize, const NB: usize, const NR: usize, const L: usize>() + -> Result<()> where [(); 4 * (NR + 1)]:, [(); NK * NB]:,

@@ -599,8 +596,8 @@ test_ghash_opt::<8, 4, 14, 16>()?;

Ok(()) } - fn test_ghash_opt<const NK: usize, const NB: usize, const NR: usize, const L: usize>( - ) -> Result<()> + fn test_ghash_opt<const NK: usize, const NB: usize, const NR: usize, const L: usize>() + -> Result<()> where [(); 4 * (NR + 1)]:, [(); NK * NB]:,
M src/constants.rs → aes-gcm/src/constants.rs

@@ -1,4 +1,4 @@

-//! For LICENSE check out https://github.com/0xPARC/plonky2-aes/blob/main/LICENSE +//! For LICENSE check out https://github.com/0xPARC/plonky2-crypto-gadgets/blob/main/LICENSE //! //! Constants for the implementation of AES following the specification from //! https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf.
M src/lib.rs → aes-gcm/src/lib.rs

@@ -1,4 +1,4 @@

-//! For LICENSE check out https://github.com/0xPARC/plonky2-aes/blob/main/LICENSE +//! For LICENSE check out https://github.com/0xPARC/plonky2-crypto-gadgets/blob/main/LICENSE #![allow(incomplete_features)] #![feature(generic_const_exprs)] #![allow(dead_code)] // TMP
M src/native_aes.rs → aes-gcm/src/native_aes.rs

@@ -1,4 +1,4 @@

-//! For LICENSE check out https://github.com/0xPARC/plonky2-aes/blob/main/LICENSE +//! For LICENSE check out https://github.com/0xPARC/plonky2-crypto-gadgets/blob/main/LICENSE //! //! Rust native implementation of //! [AES](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf) having

@@ -224,8 +224,8 @@ assert_eq!(flatten_state(c), expected);

} use aes::{ + Aes128, Aes192, Aes256, cipher::{BlockDecrypt, BlockEncrypt, BlockSizeUser, KeyInit, generic_array::GenericArray}, - {Aes128, Aes192, Aes256}, }; use rand::RngExt; /// test with loop of random-values against a rust well-tested library
M src/native_gcm.rs → aes-gcm/src/native_gcm.rs

@@ -1,4 +1,4 @@

-//! For LICENSE check out https://github.com/0xPARC/plonky2-aes/blob/main/LICENSE +//! For LICENSE check out https://github.com/0xPARC/plonky2-crypto-gadgets/blob/main/LICENSE //! //! Rust native implementation of [AES-GCM (Galois Counter //! Mode)](https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf)

@@ -36,7 +36,7 @@ out[..12].copy_from_slice(nonce.as_slice());

out[12..16].copy_from_slice(&[0x00, 0x00, 0x00, 0x01]); out } else { - panic!("unsuported at initial version; nonce.len()=12 (96 bits)"); + panic!("unsupported at initial version; nonce.len()=12 (96 bits)"); }; // 3. C=GCTR()

@@ -266,13 +266,13 @@ }

#[cfg(test)] mod tests { - use super::*; - use aes_gcm::{ - aead::{Aead, KeyInit}, Aes128Gcm, Aes256Gcm, Nonce, + aead::{Aead, KeyInit}, }; use rand::Rng; + + use super::*; fn hex_to_array<const N: usize>(h: &str) -> [u8; N] { let bytes = hex::decode(h).unwrap();

@@ -335,8 +335,8 @@ fn test_with_external_lib() -> anyhow::Result<()> {

test_with_external_lib_op::<4, 4, 10, Aes128Gcm>()?; test_with_external_lib_op::<8, 4, 14, Aes256Gcm>() } - fn test_with_external_lib_op<const NK: usize, const NB: usize, const NR: usize, C>( - ) -> anyhow::Result<()> + fn test_with_external_lib_op<const NK: usize, const NB: usize, const NR: usize, C>() + -> anyhow::Result<()> where [(); NK * NB]:, [(); 4 * (NR + 1)]:,