From 8199110e1d02b13bf7b3297e82c4b3b362b254c5 Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Sat, 10 Aug 2024 18:02:34 -0400 Subject: [PATCH 1/8] compiling aes --- circuits/aes-gcm/aes_128_enc.circom | 8 +++-- circuits/multiplier.circom | 53 ----------------------------- src/main.rs | 2 +- 3 files changed, 6 insertions(+), 57 deletions(-) delete mode 100644 circuits/multiplier.circom diff --git a/circuits/aes-gcm/aes_128_enc.circom b/circuits/aes-gcm/aes_128_enc.circom index 9af256c..0aca6ec 100644 --- a/circuits/aes-gcm/aes_128_enc.circom +++ b/circuits/aes-gcm/aes_128_enc.circom @@ -9,16 +9,18 @@ include "helper_functions.circom"; /// AES-128 Encrypt template /// AES-128 has 10 rounds, 9 partial rounds, and 1 final round -// The number of full rounds for this key size (Not the last partial round) -const ROUNDS = 10 - 1 template AES128Encrypt() { /// Input is 128 bit of plaintext signal input in[128]; // ciphertext + + // The number of full rounds for this key size (Not the last partial round) + var ROUNDS = 10 - 1; // Key schedule for initial, final, and between each full round - key_size <== (1 + 1 + ROUNDS) * 4 * 32 + var key_size = (1 + 1 + ROUNDS) * 4 * 32; + signal input ks[key_size]; /// Output is 128 bit of ciphertext diff --git a/circuits/multiplier.circom b/circuits/multiplier.circom deleted file mode 100644 index 2dc2df8..0000000 --- a/circuits/multiplier.circom +++ /dev/null @@ -1,53 +0,0 @@ -pragma circom 2.0.0; - -template MultiplicationGate() { - signal input in[2]; - signal output out <== in[0] * in[1]; -} - -template Multiplier(N) { - assert(N > 1); - signal input in[N]; - signal output out; - component gate[N-1]; - - // instantiate gates - for (var i = 0; i < N-1; i++) { - gate[i] = MultiplicationGate(); - } - - // multiply - gate[0].in <== [in[0], in[1]]; - for (var i = 0; i < N-2; i++) { - gate[i+1].in <== [gate[i].out, in[i+2]]; - } - out <== gate[N-2].out; -} - -// Alternative way using anonymous components -template MultiplierAnonymous(N) { - assert(N > 1); - signal input in[N]; - signal output out; - - signal inner[N-1]; - inner[0] <== MultiplicationGate()([in[0], in[1]]); - for(var i = 0; i < N-2; i++) { - inner[i+1] <== MultiplicationGate()([inner[i], in[i+2]]); - } - out <== inner[N-2]; -} - -// Alternative way without the gate component -template MultiplierSimple(N) { - assert(N > 1); - signal input in[N]; - signal output out; - - signal inner[N-1]; - inner[0] <== in[0] * in[1]; - for(var i = 2; i < N; i++) { - inner[i-1] <== inner[i-2] * in[i]; - } - out <== inner[N-2]; -} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 12e9959..5807799 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,7 @@ pub(crate) type Block = GenericArray; #[tokio::main] async fn main() -> io::Result<()> { - let mut witness = witness::aes_witnesses(witness::CipherMode::GcmSiv).unwrap(); + let mut witness = witness::aes_witnesses(witness::CipherMode::Vanilla).unwrap(); witness.iv.extend_from_slice(&[0, 0, 0, 0]); make_json_witness(&witness).unwrap(); From 943171aa73b55f22107c5b94eee8d507faad18fa Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Sat, 10 Aug 2024 18:25:45 -0400 Subject: [PATCH 2/8] witness generation --- circuits/aes-gcm/aes_128_enc.circom | 2 +- src/consts.rs | 2 +- src/main.rs | 2 +- src/utils.rs | 63 ++++++++++++++++++++--------- src/witness.rs | 8 ++-- 5 files changed, 50 insertions(+), 27 deletions(-) diff --git a/circuits/aes-gcm/aes_128_enc.circom b/circuits/aes-gcm/aes_128_enc.circom index 0aca6ec..379a357 100644 --- a/circuits/aes-gcm/aes_128_enc.circom +++ b/circuits/aes-gcm/aes_128_enc.circom @@ -19,7 +19,7 @@ template AES128Encrypt() var ROUNDS = 10 - 1; // Key schedule for initial, final, and between each full round - var key_size = (1 + 1 + ROUNDS) * 4 * 32; + varkey_size = (1 + 1 + ROUNDS) * 4 * 32; signal input ks[key_size]; diff --git a/src/consts.rs b/src/consts.rs index 81489eb..1195321 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -3,7 +3,7 @@ pub(crate) const KEY_ASCII: &str = "1111111111111111"; // 16 bytes pub(crate) const IV_ASCII: &str = "111111111111"; // 12 bytes pub(crate) const MESSAGE: &str = "test000000000000"; -pub(crate) const KEY_BYTES: [u8; 16] = [ +pub(crate) const KEY_BYTES_128: [u8; 16] = [ 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, ]; pub(crate) const KEY_BYTES_256: [u8; 32] = [ diff --git a/src/main.rs b/src/main.rs index 5807799..83c53a4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,7 +43,7 @@ async fn main() -> io::Result<()> { let mut witness = witness::aes_witnesses(witness::CipherMode::Vanilla).unwrap(); witness.iv.extend_from_slice(&[0, 0, 0, 0]); - make_json_witness(&witness).unwrap(); + make_json_witness(&witness, witness::CipherMode::Vanilla).unwrap(); Ok(()) } diff --git a/src/utils.rs b/src/utils.rs index cf37af6..eb2f70f 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -5,9 +5,10 @@ use anyhow::Result; use ark_bn254::Fr; use ark_circom::CircomBuilder; use ark_ec::pairing::Pairing; +use serde::Serialize; use crate::{ - witness::{AesGcmSivInputs, Witness}, + witness::{AesGcmSivInputs, CipherMode, Witness}, Ctr32BE, Nonce, AAD, }; @@ -74,36 +75,58 @@ pub(crate) fn parse_bit_from_field(j: &Fr) -> u8 { panic!("results should be bits") } } - +#[derive(Serialize)] +pub(crate) struct AESInputs { + k1: Vec, + r#in: Vec, +} /// Input signals for the AES-GCM-SIV circuit: /// signal input K1[256]; /// signal input N[128]; /// signal input AAD[n_bits_aad]; /// signal input CT[(msg_len+16)*8]; -pub(crate) fn make_json_witness(witness: &Witness) -> Result<()> { +pub(crate) fn make_json_witness(witness: &Witness, mode: CipherMode) -> Result<()> { let aad = [0; 16]; + match mode { + CipherMode::GcmSiv => { + let data = AesGcmSivInputs { + K1: bytes_to_bits(&witness.key), + N: bytes_to_bits(&witness.iv), + AAD: bytes_to_bits(&aad), + CT: bytes_to_bits(&witness.ct), + }; - let data = AesGcmSivInputs { - K1: bytes_to_bits(&witness.key), - N: bytes_to_bits(&witness.iv), - AAD: bytes_to_bits(&aad), - CT: bytes_to_bits(&witness.ct), - }; - - // Assert that K1 is 256 bits - assert_eq!(data.K1.len(), 256, "K1 must be 256 bits"); + // Assert that K1 is 256 bits + assert_eq!(data.K1.len(), 256, "K1 must be 256 bits"); - // Assert that N is 128 bits - assert_eq!(data.N.len(), 128, "N must be 128 bits"); + // Assert that N is 128 bits + assert_eq!(data.N.len(), 128, "N must be 128 bits"); - // Assert that AAD is 128 bits - assert_eq!(data.AAD.len(), 128, "AAD must be 128 bits"); + // Assert that AAD is 128 bits + assert_eq!(data.AAD.len(), 128, "AAD must be 128 bits"); - // Assert that CT is 256 bits - assert_eq!(data.CT.len(), 256, "CT must be 256 bits"); + // Assert that CT is 256 bits + assert_eq!(data.CT.len(), 256, "CT must be 256 bits"); + let mut file = std::fs::File::create("inputs/aes_gcm_siv_witness.json").unwrap(); + file.write_all(serde_json::to_string_pretty(&data).unwrap().as_bytes()).unwrap(); - let mut file = std::fs::File::create("inputs/witness.json").unwrap(); - file.write_all(serde_json::to_string_pretty(&data).unwrap().as_bytes()).unwrap(); + } + CipherMode::Ctr256 => { } + CipherMode::Vanilla => { + let data = AESInputs { + k1: bytes_to_bits(&witness.key), + r#in: bytes_to_bits(&witness.pt), + }; + assert_eq!(data.k1.len(), 128, "k1 must be 128 bits"); + + let mut file = std::fs::File::create("inputs/aes_128_enc_witness.json").unwrap(); + file.write_all(serde_json::to_string_pretty(&data).unwrap().as_bytes()).unwrap(); + + }, + CipherMode::GCM256 => { }, + CipherMode::Ctr128 => { }, + CipherMode::GCM128 => { }, + } Ok(()) } diff --git a/src/witness.rs b/src/witness.rs index 23df202..947c6ce 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -52,7 +52,7 @@ impl Witness { /// AES cipher modes. #[derive(Default)] -pub enum CipherMode { +pub(crate) enum CipherMode { Vanilla, // no IV Here Ctr256, GcmSiv, @@ -95,7 +95,7 @@ pub fn aes_witnesses(cipher_mode: CipherMode) -> Result { let ct = encrypt_tls(MESSAGE.as_bytes(), KEY_ASCII.as_bytes(), IV_ASCII.as_bytes(), 1).unwrap(); println!("ENC: cipher_text={:?}, cipher_len={:?}", hex::encode(ct.clone()), ct.len()); - let key = GenericArray::from(KEY_BYTES); + let key = GenericArray::from(KEY_BYTES_128); let key_256 = GenericArray::from(KEY_BYTES_256); let iv = GenericArray::from(IV_BYTES); let mut block = GenericArray::from(MESSAGE_BYTES); @@ -173,7 +173,7 @@ pub fn aes_witnesses(cipher_mode: CipherMode) -> Result { apply_keystream(ctr, &mut buffer); // WORKING! The aes-ctr and aes-gcm now match. - println!("INPUT iv={:?}, key={:?}", hex::encode(IV_BYTES), hex::encode(KEY_BYTES)); + println!("INPUT iv={:?}, key={:?}", hex::encode(IV_BYTES), hex::encode(KEY_BYTES_128)); println!( "AES GCM IV={:?}, tm={:?}, ct={:?}", hex::encode(ghash_iv), @@ -184,5 +184,5 @@ pub fn aes_witnesses(cipher_mode: CipherMode) -> Result { println!("AES CTR 256, 96 IV: ct={:?}", hex::encode(block)); println!("AES GCM 256: ct={:?}", hex::encode(ct.clone())); - Ok(Witness::new(&key_256, &IV_BYTES_SHORT_256, &ct, &ZERO_MESSAGE_BYTES_256)) + Ok(Witness::new(&KEY_BYTES_128, &IV_BYTES_SHORT_256, &ct, &ZERO_MESSAGE_BYTES_256)) } From 8b359b5e714086642acda4bedbecb01a024698a4 Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Sat, 10 Aug 2024 18:26:01 -0400 Subject: [PATCH 3/8] json witness --- inputs/aes_128_enc_witness.json | 262 ++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 inputs/aes_128_enc_witness.json diff --git a/inputs/aes_128_enc_witness.json b/inputs/aes_128_enc_witness.json new file mode 100644 index 0000000..4b0b7d8 --- /dev/null +++ b/inputs/aes_128_enc_witness.json @@ -0,0 +1,262 @@ +{ + "k1": [ + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1 + ], + "in": [ + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] +} \ No newline at end of file From f56fb4b3434b5b151d79503fc4350e596ff0adc0 Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Sat, 10 Aug 2024 18:39:37 -0400 Subject: [PATCH 4/8] passing emulation tests --- circuits/test/aes_emulation.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/circuits/test/aes_emulation.test.ts b/circuits/test/aes_emulation.test.ts index b546afd..308f663 100644 --- a/circuits/test/aes_emulation.test.ts +++ b/circuits/test/aes_emulation.test.ts @@ -6,7 +6,7 @@ describe("AES Emulation", () => { before(async () => { circuit = await circomkit.WitnessTester(`RowShifting`, { - file: "aes/aes_emulation", + file: "aes-gcm/aes_emulation", template: "EmulatedAesencRowShifting", }); console.log("#constraints:", await circuit.getConstraintCount()); @@ -14,11 +14,11 @@ describe("AES Emulation", () => { // TODO: Do we actually understand this? it("should have correct number of constraints", async () => { - await circuit.expectConstraintCount(16, true); + await circuit.expectConstraintCount(16, true); /// should fail }); const zeroArray: number[] = new Array(16).fill(0); - 2 + it("witness: in = [0,...]", async () => { await circuit.expectPass( { in: zeroArray }, From fb9db9c985ff703c4a9cc0ebb1b544c30ca87112 Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Sat, 10 Aug 2024 18:55:44 -0400 Subject: [PATCH 5/8] test org --- circuits/aes-gcm/aes_128_enc.circom | 2 +- circuits/aes-gcm/aes_128_enc_test.circom | 5 - circuits/test/aes_128_enc.test.ts | 47 ++++++++ circuits/test/ghash/ghash.test.ts | 18 ---- inputs/aes_128_enc_witness.json | 130 +++++++++++++++++++++++ src/utils.rs | 2 + 6 files changed, 180 insertions(+), 24 deletions(-) delete mode 100644 circuits/aes-gcm/aes_128_enc_test.circom create mode 100644 circuits/test/aes_128_enc.test.ts delete mode 100644 circuits/test/ghash/ghash.test.ts diff --git a/circuits/aes-gcm/aes_128_enc.circom b/circuits/aes-gcm/aes_128_enc.circom index 379a357..0aca6ec 100644 --- a/circuits/aes-gcm/aes_128_enc.circom +++ b/circuits/aes-gcm/aes_128_enc.circom @@ -19,7 +19,7 @@ template AES128Encrypt() var ROUNDS = 10 - 1; // Key schedule for initial, final, and between each full round - varkey_size = (1 + 1 + ROUNDS) * 4 * 32; + var key_size = (1 + 1 + ROUNDS) * 4 * 32; signal input ks[key_size]; diff --git a/circuits/aes-gcm/aes_128_enc_test.circom b/circuits/aes-gcm/aes_128_enc_test.circom deleted file mode 100644 index 85c55b8..0000000 --- a/circuits/aes-gcm/aes_128_enc_test.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.3; - -include "./aes_128_enc.circom"; - -component main = AES128Encrypt(); \ No newline at end of file diff --git a/circuits/test/aes_128_enc.test.ts b/circuits/test/aes_128_enc.test.ts new file mode 100644 index 0000000..fa9a418 --- /dev/null +++ b/circuits/test/aes_128_enc.test.ts @@ -0,0 +1,47 @@ +import { WitnessTester } from "circomkit"; +import * as fs from 'fs'; +import { circomkit } from "./common"; + + +describe("AES 128 Enc", () => { + let circuit: WitnessTester<["in"], ["out"]>; + + const witness_data = parseJsonFile("inputs/aes_128_enc_witness.json"); + + before(async () => { + circuit = await circomkit.WitnessTester(`aes_128_enc`, { + file: "aes-gcm/aes_128_enc", + template: "AES128Encrypt", + // params: if the template has parameters + }); + console.log("#constraints:", await circuit.getConstraintCount()); + }); + + // TODO: Do we actually understand this? + it("should have correct number of constraints", async () => { + await circuit.expectConstraintCount(9920, true); /// should fail + }); + + // non-linear constraints: 9600 Where does the extra 320 constraints come from? + // linear constraints: 0 + // public inputs: 0 + // private inputs: 1536 + // public outputs: 128 + // wires: 11137 + // labels: 22657 + + let key1 = witness_data["k1"]; + let inputs = witness_data["in"]; + // let outputs = witness_data["out"]; + it("witness: in = [0,...]", async () => { + await circuit.expectPass( + { ks: key1 }, + { in: inputs }, + ); + }); +}); + +function parseJsonFile(filePath: string): any { + const fileContent = fs.readFileSync(filePath, 'utf-8'); + return JSON.parse(fileContent); + } \ No newline at end of file diff --git a/circuits/test/ghash/ghash.test.ts b/circuits/test/ghash/ghash.test.ts deleted file mode 100644 index dfeb150..0000000 --- a/circuits/test/ghash/ghash.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { WitnessTester } from "circomkit"; -import { circomkit } from "../common"; - -describe("ghash", () => { - let circuit: WitnessTester<["in"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`ghash`, { - file: "aes/polyval", - template: "POLYVAL", - params: [128], - }); - }); - - it("should have correct number of constraints", async () => { - await circuit.expectConstraintCount(1000); - }); -}); \ No newline at end of file diff --git a/inputs/aes_128_enc_witness.json b/inputs/aes_128_enc_witness.json index 4b0b7d8..82e0e67 100644 --- a/inputs/aes_128_enc_witness.json +++ b/inputs/aes_128_enc_witness.json @@ -258,5 +258,135 @@ 0, 0, 0 + ], + "out": [ + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0 ] } \ No newline at end of file diff --git a/src/utils.rs b/src/utils.rs index eb2f70f..5b8bca0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -79,6 +79,7 @@ pub(crate) fn parse_bit_from_field(j: &Fr) -> u8 { pub(crate) struct AESInputs { k1: Vec, r#in: Vec, + out: Vec, } /// Input signals for the AES-GCM-SIV circuit: /// signal input K1[256]; @@ -116,6 +117,7 @@ pub(crate) fn make_json_witness(witness: &Witness, mode: CipherMode) -> Result<( let data = AESInputs { k1: bytes_to_bits(&witness.key), r#in: bytes_to_bits(&witness.pt), + out: bytes_to_bits(&witness.ct), }; assert_eq!(data.k1.len(), 128, "k1 must be 128 bits"); From a298865c413d27a63af22043da807c30776f7e39 Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Sat, 10 Aug 2024 20:07:02 -0400 Subject: [PATCH 6/8] test fails because circuit doesn't have key expansion algorithm in it yet --- circuits/test/aes_128_enc.test.ts | 10 +++++----- src/consts.rs | 14 ++++++++++++-- src/utils.rs | 2 +- src/witness.rs | 8 ++++---- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/circuits/test/aes_128_enc.test.ts b/circuits/test/aes_128_enc.test.ts index fa9a418..adacd1e 100644 --- a/circuits/test/aes_128_enc.test.ts +++ b/circuits/test/aes_128_enc.test.ts @@ -4,7 +4,7 @@ import { circomkit } from "./common"; describe("AES 128 Enc", () => { - let circuit: WitnessTester<["in"], ["out"]>; + let circuit: WitnessTester<["in", "ks"], ["out"]>; const witness_data = parseJsonFile("inputs/aes_128_enc_witness.json"); @@ -19,7 +19,7 @@ describe("AES 128 Enc", () => { // TODO: Do we actually understand this? it("should have correct number of constraints", async () => { - await circuit.expectConstraintCount(9920, true); /// should fail + await circuit.expectConstraintCount(9920, true); }); // non-linear constraints: 9600 Where does the extra 320 constraints come from? @@ -32,11 +32,11 @@ describe("AES 128 Enc", () => { let key1 = witness_data["k1"]; let inputs = witness_data["in"]; - // let outputs = witness_data["out"]; + let outputs = witness_data["out"]; it("witness: in = [0,...]", async () => { await circuit.expectPass( - { ks: key1 }, - { in: inputs }, + { in: inputs , ks: key1 }, + { out: outputs } ); }); }); diff --git a/src/consts.rs b/src/consts.rs index 1195321..9b99eb0 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -3,8 +3,18 @@ pub(crate) const KEY_ASCII: &str = "1111111111111111"; // 16 bytes pub(crate) const IV_ASCII: &str = "111111111111"; // 12 bytes pub(crate) const MESSAGE: &str = "test000000000000"; -pub(crate) const KEY_BYTES_128: [u8; 16] = [ - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, +pub(crate) const KEY_BYTES_176: [u8; 176] = [ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, + 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, + 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, ]; pub(crate) const KEY_BYTES_256: [u8; 32] = [ 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00, 0x0, diff --git a/src/utils.rs b/src/utils.rs index 5b8bca0..eeffc34 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -119,7 +119,7 @@ pub(crate) fn make_json_witness(witness: &Witness, mode: CipherMode) -> Result<( r#in: bytes_to_bits(&witness.pt), out: bytes_to_bits(&witness.ct), }; - assert_eq!(data.k1.len(), 128, "k1 must be 128 bits"); + assert_eq!(data.k1.len(), 1408, "k1 must be 1408 bits"); let mut file = std::fs::File::create("inputs/aes_128_enc_witness.json").unwrap(); file.write_all(serde_json::to_string_pretty(&data).unwrap().as_bytes()).unwrap(); diff --git a/src/witness.rs b/src/witness.rs index 947c6ce..bc23d21 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -11,7 +11,7 @@ use aes::{ cipher::{BlockEncrypt, InnerIvInit, KeyInit, KeyIvInit, StreamCipher, StreamCipherCore}, - Aes128, + Aes128 }; use aes_gcm::{ aead::{generic_array::GenericArray, Aead, NewAead, Payload}, @@ -95,7 +95,7 @@ pub fn aes_witnesses(cipher_mode: CipherMode) -> Result { let ct = encrypt_tls(MESSAGE.as_bytes(), KEY_ASCII.as_bytes(), IV_ASCII.as_bytes(), 1).unwrap(); println!("ENC: cipher_text={:?}, cipher_len={:?}", hex::encode(ct.clone()), ct.len()); - let key = GenericArray::from(KEY_BYTES_128); + let key = GenericArray::from(KEY_BYTES_176); let key_256 = GenericArray::from(KEY_BYTES_256); let iv = GenericArray::from(IV_BYTES); let mut block = GenericArray::from(MESSAGE_BYTES); @@ -173,7 +173,7 @@ pub fn aes_witnesses(cipher_mode: CipherMode) -> Result { apply_keystream(ctr, &mut buffer); // WORKING! The aes-ctr and aes-gcm now match. - println!("INPUT iv={:?}, key={:?}", hex::encode(IV_BYTES), hex::encode(KEY_BYTES_128)); + println!("INPUT iv={:?}, key={:?}", hex::encode(IV_BYTES), hex::encode(KEY_BYTES_176)); println!( "AES GCM IV={:?}, tm={:?}, ct={:?}", hex::encode(ghash_iv), @@ -184,5 +184,5 @@ pub fn aes_witnesses(cipher_mode: CipherMode) -> Result { println!("AES CTR 256, 96 IV: ct={:?}", hex::encode(block)); println!("AES GCM 256: ct={:?}", hex::encode(ct.clone())); - Ok(Witness::new(&KEY_BYTES_128, &IV_BYTES_SHORT_256, &ct, &ZERO_MESSAGE_BYTES_256)) + Ok(Witness::new(&KEY_BYTES_176, &IV_BYTES_SHORT_256, &ct, &ZERO_MESSAGE_BYTES_256)) } From 1e9675936013d92f9910e90bbdf7d77601a5feb9 Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Sat, 10 Aug 2024 20:59:27 -0400 Subject: [PATCH 7/8] better aes + passing tests --- circuits.json | 5 + circuits/aes-ctr/cipher.circom | 106 ++++++ circuits/aes-ctr/ctr.circom | 144 +++++++ circuits/aes-ctr/key_expansion.circom | 123 ++++++ circuits/aes-ctr/mix_columns.circom | 199 ++++++++++ circuits/aes-ctr/sbox128.circom | 29 ++ circuits/aes-ctr/tbox.circom | 38 ++ circuits/aes-ctr/transformations.circom | 119 ++++++ circuits/aes-ctr/utils.circom | 161 ++++++++ circuits/aes-gcm-siv/README.md | 10 - circuits/aes-gcm-siv/aes_256_ctr.circom | 75 ---- circuits/aes-gcm-siv/aes_256_ctr_test.circom | 50 --- circuits/aes-gcm-siv/aes_256_encrypt.circom | 181 --------- .../aes-gcm-siv/aes_256_key_expansion.circom | 130 ------- circuits/aes-gcm-siv/aes_emulation.circom | 41 -- .../aes-gcm-siv/aes_emulation_tables.circom | 190 --------- .../aes-gcm-siv/dec_aes_256_ctr_try1.circom | 187 --------- .../aes-gcm-siv/gcm_siv_dec_2_keys.circom | 199 ---------- .../gcm_siv_dec_2_keys_test.circom | 5 - .../aes-gcm-siv/gcm_siv_enc_2_keys.circom | 170 --------- circuits/aes-gcm-siv/gfmul_int.circom | 168 -------- circuits/aes-gcm-siv/helper_functions.circom | 251 ------------ circuits/aes-gcm-siv/mul.circom | 82 ---- circuits/aes-gcm-siv/polyval.circom | 63 --- circuits/aes-gcm-siv/tiny.circom | 16 - circuits/aes-gcm-siv/vclmul_emulator.circom | 48 --- circuits/aes-gcm/aes_128_enc.circom | 181 --------- circuits/aes-gcm/aes_emulation.circom | 44 --- circuits/aes-gcm/aes_emulation_tables.circom | 190 --------- circuits/test/aes_128_enc.test.ts | 47 --- circuits/test/aes_emulation.test.ts | 38 -- circuits/test/cipher.test.ts | 67 ++++ circuits/test/ctr.test.ts | 306 +++++++++++++++ circuits/test/key_expansion.test.ts | 208 ++++++++++ circuits/test/next_round.test.ts | 64 ++++ circuits/test/sbox128.test.ts | 21 + circuits/test/transformations.test.ts | 360 ++++++++++++++++++ inputs/cipher_4/default.json | 10 + inputs/multiplier_3/default.json | 3 - 39 files changed, 1960 insertions(+), 2369 deletions(-) create mode 100644 circuits/aes-ctr/cipher.circom create mode 100644 circuits/aes-ctr/ctr.circom create mode 100644 circuits/aes-ctr/key_expansion.circom create mode 100644 circuits/aes-ctr/mix_columns.circom create mode 100644 circuits/aes-ctr/sbox128.circom create mode 100644 circuits/aes-ctr/tbox.circom create mode 100644 circuits/aes-ctr/transformations.circom create mode 100644 circuits/aes-ctr/utils.circom delete mode 100644 circuits/aes-gcm-siv/README.md delete mode 100644 circuits/aes-gcm-siv/aes_256_ctr.circom delete mode 100644 circuits/aes-gcm-siv/aes_256_ctr_test.circom delete mode 100644 circuits/aes-gcm-siv/aes_256_encrypt.circom delete mode 100644 circuits/aes-gcm-siv/aes_256_key_expansion.circom delete mode 100644 circuits/aes-gcm-siv/aes_emulation.circom delete mode 100644 circuits/aes-gcm-siv/aes_emulation_tables.circom delete mode 100644 circuits/aes-gcm-siv/dec_aes_256_ctr_try1.circom delete mode 100644 circuits/aes-gcm-siv/gcm_siv_dec_2_keys.circom delete mode 100644 circuits/aes-gcm-siv/gcm_siv_dec_2_keys_test.circom delete mode 100644 circuits/aes-gcm-siv/gcm_siv_enc_2_keys.circom delete mode 100644 circuits/aes-gcm-siv/gfmul_int.circom delete mode 100644 circuits/aes-gcm-siv/helper_functions.circom delete mode 100644 circuits/aes-gcm-siv/mul.circom delete mode 100644 circuits/aes-gcm-siv/polyval.circom delete mode 100644 circuits/aes-gcm-siv/tiny.circom delete mode 100644 circuits/aes-gcm-siv/vclmul_emulator.circom delete mode 100644 circuits/aes-gcm/aes_128_enc.circom delete mode 100644 circuits/aes-gcm/aes_emulation.circom delete mode 100644 circuits/aes-gcm/aes_emulation_tables.circom delete mode 100644 circuits/test/aes_128_enc.test.ts delete mode 100644 circuits/test/aes_emulation.test.ts create mode 100644 circuits/test/cipher.test.ts create mode 100644 circuits/test/ctr.test.ts create mode 100644 circuits/test/key_expansion.test.ts create mode 100644 circuits/test/next_round.test.ts create mode 100644 circuits/test/sbox128.test.ts create mode 100644 circuits/test/transformations.test.ts create mode 100644 inputs/cipher_4/default.json delete mode 100644 inputs/multiplier_3/default.json diff --git a/circuits.json b/circuits.json index 71f9408..4ad26bf 100644 --- a/circuits.json +++ b/circuits.json @@ -3,5 +3,10 @@ "file": "aes/polyval", "template": "POLYVAL", "params": [128] + }, + "cipher_4": { + "file": "cipher", + "template": "Cipher", + "params": [4] } } diff --git a/circuits/aes-ctr/cipher.circom b/circuits/aes-ctr/cipher.circom new file mode 100644 index 0000000..ee8a9c1 --- /dev/null +++ b/circuits/aes-ctr/cipher.circom @@ -0,0 +1,106 @@ +pragma circom 2.1.9; + +include "key_expansion.circom"; +include "circomlib/circuits/comparators.circom"; +include "circomlib/circuits/bitify.circom"; +include "circomlib/circuits/gates.circom"; +include "transformations.circom"; +include "mix_columns.circom"; + +// Cipher Process +// nk: number of keys which can be 4, 6, 8 +// AES 128, 192, 256 have 10, 12, 14 rounds. +// Input Block Initial Round Key Round Key Final Round Key +// │ │ │ │ +// ▼ ▼ ▼ ▼ +// ┌─────────┐ ┌──────────┐ ┌────────┐ ┌──────────┐ ┌────────┐ ┌──────────┐ +// │ Block │──► │ Add │ │ Sub │ │ Mix │ │ Sub │ │ Add │ +// │ │ │ Round │ │ Bytes │ │ Columns │ │ Bytes │ │ Round │ +// │ │ │ Key │ │ │ │ │ │ │ │ Key │ +// └─────────┘ └────┬─────┘ └───┬────┘ └────┬─────┘ └───┬────┘ └────┬─────┘ +// │ │ │ │ │ +// ▼ ▼ ▼ ▼ ▼ +// ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ +// │ Round 0 │ │ Round 1 │ │ Round 2 │ │ Round │ │ Final │ +// │ │ │ to │ │ to │ │ Nr - 1 │ │ Round │ +// │ │ │ Nr - 2 │ │ Nr - 1 │ │ │ │ │ +// └─────────┘ └─────────┘ └─────────┘ └─────────┘ └────┬────┘ +// │ +// ▼ +// Ciphertext + +// @param nk: number of keys which can be 4, 6, 8 +// @inputs block: 4x4 matrix representing the input block +// @inputs key: array of nk*4 bytes representing the key +// @outputs cipher: 4x4 matrix representing the output block +template Cipher(nk){ + assert(nk == 4 || nk == 6 || nk == 8 ); + signal input block[4][4]; + signal input key[nk * 4]; + signal output cipher[4][4]; + + var nr = Rounds(nk); + + component keyExpansion = KeyExpansion(nk,nr); + keyExpansion.key <== key; + + component addRoundKey[nr+1]; + component subBytes[nr]; + component shiftRows[nr]; + component mixColumns[nr-1]; + + signal interBlock[nr][4][4]; + + addRoundKey[0] = AddRoundKey(); + addRoundKey[0].state <== block; + for (var i = 0; i < 4; i++) { + addRoundKey[0].roundKey[i] <== keyExpansion.keyExpanded[i]; + } + + interBlock[0] <== addRoundKey[0].newState; + for (var i = 1; i < nr; i++) { + subBytes[i-1] = SubBlock(); + subBytes[i-1].state <== interBlock[i-1]; + + shiftRows[i-1] = ShiftRows(); + shiftRows[i-1].state <== subBytes[i-1].newState; + + mixColumns[i-1] = MixColumns(); + mixColumns[i-1].state <== shiftRows[i-1].newState; + + addRoundKey[i] = AddRoundKey(); + addRoundKey[i].state <== mixColumns[i-1].out; + for (var j = 0; j < 4; j++) { + addRoundKey[i].roundKey[j] <== keyExpansion.keyExpanded[j + (i * 4)]; + } + + interBlock[i] <== addRoundKey[i].newState; + } + + subBytes[nr-1] = SubBlock(); + subBytes[nr-1].state <== interBlock[nr-1]; + + shiftRows[nr-1] = ShiftRows(); + shiftRows[nr-1].state <== subBytes[nr-1].newState; + + addRoundKey[nr] = AddRoundKey(); + addRoundKey[nr].state <== shiftRows[nr-1].newState; + for (var i = 0; i < 4; i++) { + addRoundKey[nr].roundKey[i] <== keyExpansion.keyExpanded[i + (nr * 4)]; + } + + cipher <== addRoundKey[nr].newState; +} + +// @param nk: number of keys which can be 4, 6, 8 +// @returns number of rounds +// AES 128, 192, 256 have 10, 12, 14 rounds. +function Rounds (nk) { + if (nk == 4) { + return 10; + } else if (nk == 6) { + return 12; + } else { + return 14; + } +} \ No newline at end of file diff --git a/circuits/aes-ctr/ctr.circom b/circuits/aes-ctr/ctr.circom new file mode 100644 index 0000000..c388d99 --- /dev/null +++ b/circuits/aes-ctr/ctr.circom @@ -0,0 +1,144 @@ +pragma circom 2.1.9; + +include "cipher.circom"; +include "transformations.circom"; + +template EncryptCTR(l,nk){ + signal input plainText[l]; + signal input iv[16]; + signal input key[nk * 4]; + signal output cipher[l]; + + var n = l\16; + if(l%16 > 0){ + n = n + 1; + } + + component toBlocks = ToBlocks(l); + toBlocks.stream <== plainText; + + component aes[n]; + + signal cipherBlocks[n][4][4]; + component AddCipher[n]; + + component generateCtrBlocks = GenerateCounterBlocks(n); + generateCtrBlocks.iv <== iv; + + for(var i = 0 ; i < n; i++){ + aes[i] = Cipher(nk); + aes[i].key <== key; + aes[i].block <== generateCtrBlocks.counterBlocks[i]; + + AddCipher[i] = AddCipher(); + AddCipher[i].state <== toBlocks.blocks[i]; + AddCipher[i].cipher <== aes[i].cipher; + + cipherBlocks[i] <== AddCipher[i].newState; + } + + component toStream = ToStream(n,l); + toStream.blocks <== cipherBlocks; + + cipher <== toStream.stream; +} + + +//convert stream of plain text to blocks of 16 bytes +template ToBlocks(l){ + signal input stream[l]; + + var n = l\16; + if(l%16 > 0){ + n = n + 1; + } + signal output blocks[n][4][4]; + + var i, j, k; + + for (var idx = 0; idx < l; idx++) { + blocks[i][k][j] <== stream[idx]; + k = k + 1; + if (k == 4){ + k = 0; + j = j + 1; + if (j == 4){ + j = 0; + i = i + 1; + } + } + } + + if (l%16 > 0){ + blocks[i][k][j] <== 1; + k = k + 1; + } +} + +// convert blocks of 16 bytes to stream of bytes +template ToStream(n,l){ + signal input blocks[n][4][4]; + + signal output stream[l]; + + var i, j, k; + + while(i*16 + j*4 + k < l){ + stream[i*16 + j*4 + k] <== blocks[i][k][j]; + k = k + 1; + if (k == 4){ + k = 0; + j = j + 1; + if (j == 4){ + j = 0; + i = i + 1; + } + } + } +} + +template AddCipher(){ + signal input state[4][4]; + signal input cipher[4][4]; + signal output newState[4][4]; + + component xorbyte[4][4]; + + for (var i = 0; i < 4; i++) { + for (var j = 0; j < 4; j++) { + xorbyte[i][j] = XorByte(); + xorbyte[i][j].a <== state[i][j]; + xorbyte[i][j].b <== cipher[i][j]; + newState[i][j] <== xorbyte[i][j].out; + } + } +} + +// converts iv to counter blocks +// iv is 16 bytes +template GenerateCounterBlocks(n){ + assert(n < 0xffffffff); + signal input iv[16]; + signal output counterBlocks[n][4][4]; + + var ivr[16] = iv; + + component toBlocks[n]; + + for (var i = 0; i < n; i++) { + toBlocks[i] = ToBlocks(16); + toBlocks[i].stream <-- ivr; + counterBlocks[i] <== toBlocks[i].blocks[0]; + ivr[15] = (ivr[15] + 1)%256; + if (ivr[15] == 0){ + ivr[14] = (ivr[14] + 1)%256; + if (ivr[14] == 0){ + ivr[13] = (ivr[13] + 1)%256; + if (ivr[13] == 0){ + ivr[12] = (ivr[12] + 1)%256; + } + } + } + + } +} \ No newline at end of file diff --git a/circuits/aes-ctr/key_expansion.circom b/circuits/aes-ctr/key_expansion.circom new file mode 100644 index 0000000..81c8c14 --- /dev/null +++ b/circuits/aes-ctr/key_expansion.circom @@ -0,0 +1,123 @@ +pragma circom 2.1.9; + +include "sbox128.circom"; +include "utils.circom"; + +// Key Expansion Process +// +// Original Key (Nk words) +// ┌───┬───┬───┬───┐ +// │W0 │W1 │W2 │W3 │ (for AES-128, Nk=4) +// └─┬─┴─┬─┴─┬─┴─┬─┘ +// │ │ │ │ +// ▼ ▼ ▼ ▼ +// ┌───────────────────────────────────────────────────────┐ +// │ Key Expansion Process │ +// │ │ +// │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ +// │ │RotWord │ │SubWord │ │ XOR │ │ XOR │ │ +// │ │ │ │ │ │ Rcon(i) │ │ W[i-Nk] │ │ +// │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ +// │ │ │ │ │ │ +// │ └───────────┴───────────┴───────────┘ │ +// │ │ │ +// │ ▼ │ +// │ ┌─────────────────────┐ │ +// │ │ New Expanded Key │ │ +// │ │ Word │ │ +// │ └─────────────────────┘ │ +// │ │ │ +// └───────────────────────┼───────────────────────────────┘ +// │ +// ▼ +// Expanded Key Words +// ┌───┬───┬───┬───┬───┬───┬───┬───┐ +// │W4 │W5 │W6 │W7 │W8 │W9 │...│W43│ (for AES-128, 44 words total) +// └───┴───┴───┴───┴───┴───┴───┴───┘ + + +// @param nk: number of keys which can be 4, 6, 8 +// @param nr: number of rounds which can be 10, 12, 14 for AES 128, 192, 256 +// @inputs key: array of nk*4 bytes representing the key +// @outputs keyExpanded: array of (nr+1)*4 words i.e for AES 128, 192, 256 it will be 44, 52, 60 words +template KeyExpansion(nk,nr) { + assert(nk == 4 || nk == 6 || nk == 8 ); + signal input key[nk * 4]; + + var totalWords = (4 * (nr + 1)); + var effectiveRounds = nk == 4 ? 10 : totalWords\nk; + + signal output keyExpanded[totalWords][4]; + + for (var i = 0; i < nk; i++) { + for (var j = 0; j < 4; j++) { + keyExpanded[i][j] <== key[(4 * i) + j]; + } + } + + component nextRound[effectiveRounds]; + + for (var round = 1; round <= effectiveRounds; round++) { + var outputWordLen = round == effectiveRounds ? 4 : nk; + nextRound[round - 1] = NextRound(nk, outputWordLen); + + for (var i = 0; i < nk; i++) { + for (var j = 0; j < 4; j++) { + nextRound[round - 1].key[i][j] <== keyExpanded[(round * nk) + i - nk][j]; + } + } + + nextRound[round - 1].round <== round; + + for (var i = 0; i < outputWordLen; i++) { + for (var j = 0; j < 4; j++) { + keyExpanded[(round * nk) + i][j] <== nextRound[round - 1].nextKey[i][j]; + } + } + } +} + +// @param nk: number of keys which can be 4, 6, 8 +// @param o: number of output words which can be 4 or nk +template NextRound(nk, o){ + signal input key[nk][4]; + signal input round; + signal output nextKey[o][4]; + + component rotateWord = Rotate(1, 4); + for (var i = 0; i < 4; i++) { + rotateWord.bytes[i] <== key[nk - 1][i]; + } + + component substituteWord[2]; + substituteWord[0] = SubstituteWord(); + substituteWord[0].bytes <== rotateWord.rotated; + + component rcon = RCon(); + rcon.round <== round; + + component xorWord[o + 1]; + xorWord[0] = XorWord(); + xorWord[0].bytes1 <== substituteWord[0].substituted; + xorWord[0].bytes2 <== rcon.out; + + for (var i = 0; i < o; i++) { + xorWord[i+1] = XorWord(); + if (i == 0) { + xorWord[i+1].bytes1 <== xorWord[0].out; + } else if(nk == 8 && i == 4) { + substituteWord[1] = SubstituteWord(); + substituteWord[1].bytes <== nextKey[i - 1]; + xorWord[i+1].bytes1 <== substituteWord[1].substituted; + } else { + xorWord[i+1].bytes1 <== nextKey[i-1]; + } + xorWord[i+1].bytes2 <== key[i]; + + for (var j = 0; j < 4; j++) { + nextKey[i][j] <== xorWord[i+1].out[j]; + } + } +} + + diff --git a/circuits/aes-ctr/mix_columns.circom b/circuits/aes-ctr/mix_columns.circom new file mode 100644 index 0000000..ec8ff70 --- /dev/null +++ b/circuits/aes-ctr/mix_columns.circom @@ -0,0 +1,199 @@ +pragma circom 2.1.9; + +include "transformations.circom"; +include "circomlib/circuits/comparators.circom"; +include "circomlib/circuits/bitify.circom"; +include "circomlib/circuits/gates.circom"; +include "tbox.circom"; + +// MixColumns: Applies the equation for each column: +// [s'0,c] [2 3 1 1][s0,c] +// [s'1,c] = [1 2 3 1][s1,c] +// [s'2,c] [1 1 2 3][s2,c] +// [s'3,c] [3 1 1 2][s3,c] +// Where c is the column number, s are input bytes, s' are output bytes +template MixColumns(){ + signal input state[4][4]; + signal output out[4][4]; + + component s0[4]; + component s1[4]; + component s2[4]; + component s3[4]; + + for (var i = 0; i < 4; i++) { + s0[i] = S0(); + s1[i] = S1(); + s2[i] = S2(); + s3[i] = S3(); + + for(var j = 0; j < 4; j++) { + s0[i].in[j] <== state[j][i]; + s1[i].in[j] <== state[j][i]; + s2[i].in[j] <== state[j][i]; + s3[i].in[j] <== state[j][i]; + } + + out[0][i] <== s0[i].out; + out[1][i] <== s1[i].out; + out[2][i] <== s2[i].out; + out[3][i] <== s3[i].out; + } +} + +// S0: Implements the equation +// out = (2 • in[0]) ⊕ (3 • in[1]) ⊕ in[2] ⊕ in[3] +template S0(){ + signal input in[4]; + signal output out; + component num2bits[4]; + component xor[3]; + + for (var i = 2; i < 4; i++) { + num2bits[i] = Num2Bits(8); + num2bits[i].in <== in[i]; + } + + num2bits[0] = Num2Bits(8); + num2bits[0].in <-- TBox(0, in[0]); + + num2bits[1] = Num2Bits(8); + num2bits[1].in <-- TBox(1, in[1]); + + xor[0] = XorBits(); + xor[0].a <== num2bits[0].out; + xor[0].b <== num2bits[1].out; + + xor[1] = XorBits(); + xor[1].a <== xor[0].out; + xor[1].b <== num2bits[2].out; + + xor[2] = XorBits(); + xor[2].a <== xor[1].out; + xor[2].b <== num2bits[3].out; + + component b2n = Bits2Num(8); + for (var i = 0; i < 8; i++) { + b2n.in[i] <== xor[2].out[i]; + } + + out <== b2n.out; +} + +// S1: Implements the equation +// out = in[0] ⊕ (2 • in[1]) ⊕ (3 • in[2]) ⊕ in[3] +template S1(){ + signal input in[4]; + signal output out; + component num2bits[4]; + component xor[3]; + + num2bits[0] = Num2Bits(8); + num2bits[0].in <== in[0]; + + num2bits[1] = Num2Bits(8); + num2bits[1].in <-- TBox(0, in[1]); + + num2bits[2] = Num2Bits(8); + num2bits[2].in <-- TBox(1, in[2]); + + num2bits[3] = Num2Bits(8); + num2bits[3].in <== in[3]; + + xor[0] = XorBits(); + xor[0].a <== num2bits[0].out; + xor[0].b <== num2bits[1].out; + + xor[1] = XorBits(); + xor[1].a <== xor[0].out; + xor[1].b <== num2bits[2].out; + + xor[2] = XorBits(); + xor[2].a <== xor[1].out; + xor[2].b <== num2bits[3].out; + + component b2n = Bits2Num(8); + for (var i = 0; i < 8; i++) { + b2n.in[i] <== xor[2].out[i]; + } + + out <== b2n.out; +} + +// S2: Implements the equation +// out = in[0] ⊕ in[1] ⊕ (2 • in[2]) ⊕ (3 • in[3]) +template S2() { + signal input in[4]; + signal output out; + component num2bits[4]; + component xor[3]; + + for (var i = 0; i < 2; i++) { + num2bits[i] = Num2Bits(8); + num2bits[i].in <== in[i]; + } + + num2bits[2] = Num2Bits(8); + num2bits[2].in <-- TBox(0, in[2]); + + num2bits[3] = Num2Bits(8); + num2bits[3].in <-- TBox(1, in[3]); + + xor[0] = XorBits(); + xor[0].a <== num2bits[0].out; + xor[0].b <== num2bits[1].out; + + xor[1] = XorBits(); + xor[1].a <== xor[0].out; + xor[1].b <== num2bits[2].out; + + xor[2] = XorBits(); + xor[2].a <== xor[1].out; + xor[2].b <== num2bits[3].out; + + component b2n = Bits2Num(8); + for (var i = 0; i < 8; i++) { + b2n.in[i] <== xor[2].out[i]; + } + + out <== b2n.out; +} + +// S3: Implements the equation +// out = (3 • in[0]) ⊕ in[1] ⊕ in[2] ⊕ (2 • in[3]) +template S3() { + signal input in[4]; + signal output out; + component num2bits[4]; + component xor[3]; + + for (var i = 1; i < 3; i++) { + num2bits[i] = Num2Bits(8); + num2bits[i].in <== in[i]; + } + + num2bits[0] = Num2Bits(8); + num2bits[0].in <-- TBox(1, in[0]); + + num2bits[3] = Num2Bits(8); + num2bits[3].in <-- TBox(0, in[3]); + + xor[0] = XorBits(); + xor[0].a <== num2bits[0].out; + xor[0].b <== num2bits[1].out; + + xor[1] = XorBits(); + xor[1].a <== xor[0].out; + xor[1].b <== num2bits[2].out; + + xor[2] = XorBits(); + xor[2].a <-- num2bits[3].out; + xor[2].b <== xor[1].out; + + component b2n = Bits2Num(8); + for (var i = 0; i < 8; i++) { + b2n.in[i] <== xor[2].out[i]; + } + + out <== b2n.out; +} \ No newline at end of file diff --git a/circuits/aes-ctr/sbox128.circom b/circuits/aes-ctr/sbox128.circom new file mode 100644 index 0000000..c949f0e --- /dev/null +++ b/circuits/aes-ctr/sbox128.circom @@ -0,0 +1,29 @@ +pragma circom 2.1.9; + +include "circomlib/circuits/comparators.circom"; + +template SBox128() { + signal input in; + signal output out; + + var sbox[16 * 16] = [ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 + ]; + + out <-- sbox[in]; +} diff --git a/circuits/aes-ctr/tbox.circom b/circuits/aes-ctr/tbox.circom new file mode 100644 index 0000000..976fbea --- /dev/null +++ b/circuits/aes-ctr/tbox.circom @@ -0,0 +1,38 @@ +pragma circom 2.1.9; + +include "transformations.circom"; +include "circomlib/circuits/bitify.circom"; + +//tbox[0] =>> multiplication by 2 +//tbox[1] =>> multiplication by 3 +function TBox(index, subbyte) { + var tbox[2][256] = [ + [ + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, + 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, + 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, + 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, + 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, + 254, 27, 25, 31, 29, 19, 17, 23, 21, 11, 9, 15, 13, 3, 1, 7, 5, 59, 57, 63, 61, 51, 49, 55, 53, 43, 41, 47, 45, 35, + 33, 39, 37, 91, 89, 95, 93, 83, 81, 87, 85, 75, 73, 79, 77, 67, 65, 71, 69, 123, 121, 127, 125, 115, 113, 119, 117, + 107, 105, 111, 109, 99, 97, 103, 101, 155, 153, 159, 157, 147, 145, 151, 149, 139, 137, 143, 141, 131, 129, 135, 133, + 187, 185, 191, 189, 179, 177, 183, 181, 171, 169, 175, 173, 163, 161, 167, 165, 219, 217, 223, 221, 211, 209, 215, + 213, 203, 201, 207, 205, 195, 193, 199, 197, 251, 249, 255, 253, 243, 241, 247, 245, 235, 233, 239, 237, 227, 225, + 231, 229 + ], + [ + 0, 3, 6, 5, 12, 15, 10, 9, 24, 27, 30, 29, 20, 23, 18, 17, 48, 51, 54, 53, 60, 63, 58, 57, 40, 43, 46, 45, 36, 39, 34, + 33, 96, 99, 102, 101, 108, 111, 106, 105, 120, 123, 126, 125, 116, 119, 114, 113, 80, 83, 86, 85, 92, 95, 90, 89, 72, + 75, 78, 77, 68, 71, 66, 65, 192, 195, 198, 197, 204, 207, 202, 201, 216, 219, 222, 221, 212, 215, 210, 209, 240, 243, + 246, 245, 252, 255, 250, 249, 232, 235, 238, 237, 228, 231, 226, 225, 160, 163, 166, 165, 172, 175, 170, 169, 184, + 187, 190, 189, 180, 183, 178, 177, 144, 147, 150, 149, 156, 159, 154, 153, 136, 139, 142, 141, 132, 135, 130, 129, + 155, 152, 157, 158, 151, 148, 145, 146, 131, 128, 133, 134, 143, 140, 137, 138, 171, 168, 173, 174, 167, 164, 161, + 162, 179, 176, 181, 182, 191, 188, 185, 186, 251, 248, 253, 254, 247, 244, 241, 242, 227, 224, 229, 230, 239, 236, + 233, 234, 203, 200, 205, 206, 199, 196, 193, 194, 211, 208, 213, 214, 223, 220, 217, 218, 91, 88, 93, 94, 87, 84, 81, + 82, 67, 64, 69, 70, 79, 76, 73, 74, 107, 104, 109, 110, 103, 100, 97, 98, 115, 112, 117, 118, 127, 124, 121, 122, 59, + 56, 61, 62, 55, 52, 49, 50, 35, 32, 37, 38, 47, 44, 41, 42, 11, 8, 13, 14, 7, 4, 1, 2, 19, 16, 21, 22, 31, 28, 25, 26 + ] + ]; + + return tbox[index][subbyte]; +} \ No newline at end of file diff --git a/circuits/aes-ctr/transformations.circom b/circuits/aes-ctr/transformations.circom new file mode 100644 index 0000000..3120e52 --- /dev/null +++ b/circuits/aes-ctr/transformations.circom @@ -0,0 +1,119 @@ +pragma circom 2.1.9; + +include "circomlib/circuits/comparators.circom"; +include "circomlib/circuits/bitify.circom"; +include "circomlib/circuits/gates.circom"; +include "utils.circom"; + +// ShiftRows: Performs circular left shift on each row +// 0, 1, 2, 3 shifts for rows 0, 1, 2, 3 respectively +template ShiftRows(){ + signal input state[4][4]; + signal output newState[4][4]; + + component shiftWord[4]; + + for (var i = 0; i < 4; i++) { + // Rotate: Performs circular left shift on each row + shiftWord[i] = Rotate(i, 4); + shiftWord[i].bytes <== state[i]; + newState[i] <== shiftWord[i].rotated; + } +} + + // Applies S-box substitution to each byte +template SubBlock(){ + signal input state[4][4]; + signal output newState[4][4]; + component sbox[4]; + + for (var i = 0; i < 4; i++) { + sbox[i] = SubstituteWord(); + sbox[i].bytes <== state[i]; + newState[i] <== sbox[i].substituted; + } +} + +// AddRoundKey: XORs the state with transposed the round key +template AddRoundKey(){ + signal input state[4][4]; + signal input roundKey[4][4]; + signal output newState[4][4]; + + component xorbyte[4][4]; + + for (var i = 0; i < 4; i++) { + for (var j = 0; j < 4; j++) { + xorbyte[i][j] = XorByte(); + xorbyte[i][j].a <== state[i][j]; + xorbyte[i][j].b <== roundKey[j][i]; + newState[i][j] <== xorbyte[i][j].out; + } + } +} + +// XTimes2: Multiplies by 2 in GF(2^8) +template XTimes2(){ + signal input in[8]; + signal output out[8]; + + component xtimeConstant = Num2Bits(8); + xtimeConstant.in <== 0x1b; + + component xor[7]; + + component isZero = IsZero(); + isZero.in <== in[7]; + + out[0] <== 1-isZero.out; + for (var i = 0; i < 7; i++) { + xor[i] = XOR(); + xor[i].a <== in[i]; + xor[i].b <== xtimeConstant.out[i+1] * (1-isZero.out); + out[i+1] <== xor[i].out; + } +} + +// XTimes: Multiplies by n in GF(2^8) +// This uses a fast multiplication algorithm that uses the XTimes2 component +// Number of constaints is always constant +template XTimes(n){ + signal input in[8]; + signal output out[8]; + + component bits = Num2Bits(8); + bits.in <== n; + + component XTimes2[7]; + + XTimes2[0] = XTimes2(); + XTimes2[0].in <== in; + + for (var i = 1; i < 7; i++) { + XTimes2[i] = XTimes2(); + XTimes2[i].in <== XTimes2[i-1].out; + } + + component xor[8]; + component mul[8]; + signal inter[8][8]; + + mul[0] = MulByte(); + mul[0].a <== bits.out[0]; + mul[0].b <== in; + inter[0] <== mul[0].c; + + for (var i = 1; i < 8; i++) { + mul[i] = MulByte(); + mul[i].a <== bits.out[i]; + mul[i].b <== XTimes2[i-1].out; + + xor[i] = XorBits(); + xor[i].a <== inter[i-1]; + xor[i].b <== mul[i].c; + inter[i] <== xor[i].out; + } + + out <== inter[7]; +} + diff --git a/circuits/aes-ctr/utils.circom b/circuits/aes-ctr/utils.circom new file mode 100644 index 0000000..d9b6bea --- /dev/null +++ b/circuits/aes-ctr/utils.circom @@ -0,0 +1,161 @@ +pragma circom 2.1.9; + +include "sbox128.circom"; +include "circomlib/circuits/comparators.circom"; +include "circomlib/circuits/bitify.circom"; +include "circomlib/circuits/gates.circom"; + +// Converts an array of bytes to an array of words +template BytesToWords(n) { + assert(n % 4 == 0); + signal input bytes[n]; + signal output words[n \ 4][n]; + + for (var i = 0; i < n \ 4; i++) { + for(var j = 0; j < 4; j++) { + words[i][j] <== bytes[i * 4 + j]; + } + } +} + +// Rotates an array of bytes to the left by a specified rotation +template Rotate(rotation, length) { + assert(rotation < length); + signal input bytes[length]; + signal output rotated[length]; + + for(var i = 0; i < length - rotation; i++) { + rotated[i] <== bytes[i + rotation]; + } + + for(var i = length - rotation; i < length; i++) { + rotated[i] <== bytes[i - length + rotation]; + } +} + +// Substitutes each byte in a word using the S-Box +template SubstituteWord() { + signal input bytes[4]; + signal output substituted[4]; + + component sbox[4]; + + for(var i = 0; i < 4; i++) { + sbox[i] = SBox128(); + sbox[i].in <== bytes[i]; + substituted[i] <== sbox[i].out; + } +} + +// Outputs a round constant for a given round number +template RCon() { + signal input round; + signal output out[4]; + + assert(round > 0 && round <= 10); + + var rcon[10][4] = [ + [0x01, 0x00, 0x00, 0x00], + [0x02, 0x00, 0x00, 0x00], + [0x04, 0x00, 0x00, 0x00], + [0x08, 0x00, 0x00, 0x00], + [0x10, 0x00, 0x00, 0x00], + [0x20, 0x00, 0x00, 0x00], + [0x40, 0x00, 0x00, 0x00], + [0x80, 0x00, 0x00, 0x00], + [0x1b, 0x00, 0x00, 0x00], + [0x36, 0x00, 0x00, 0x00] + ]; + + out <-- rcon[round-1]; +} + + +// XORs two words (arrays of 4 bytes each) +template XorWord() { + signal input bytes1[4]; + signal input bytes2[4]; + + component n2b[4 * 2]; + component b2n[4]; + component xor[4][8]; + + signal output out[4]; + + for(var i = 0; i < 4; i++) { + n2b[2 * i] = Num2Bits(8); + n2b[2 * i + 1] = Num2Bits(8); + n2b[2 * i].in <== bytes1[i]; + n2b[2 * i + 1].in <== bytes2[i]; + b2n[i] = Bits2Num(8); + + for (var j = 0; j < 8; j++) { + xor[i][j] = XOR(); + xor[i][j].a <== n2b[2 * i].out[j]; + xor[i][j].b <== n2b[2 * i + 1].out[j]; + b2n[i].in[j] <== xor[i][j].out; + } + + out[i] <== b2n[i].out; + } +} + +// Selects between two words based on a condition +template WordSelector() { + signal input condition; + signal input bytes1[4]; + signal input bytes2[4]; + signal output out[4]; + + for (var i = 0; i < 4; i++) { + out[i] <== condition * (bytes1[i] - bytes2[i]) + bytes2[i]; + } +} + +// Multiplies a byte by an array of bits +template MulByte(){ + signal input a; + signal input b[8]; + signal output c[8]; + + for (var i = 0; i < 8; i++) { + c[i] <== a * b[i]; + } +} + +// XORs two bytes +template XorByte(){ + signal input a; + signal input b; + signal output out; + + component abits = Num2Bits(8); + abits.in <== a; + + component bbits = Num2Bits(8); + bbits.in <== b; + + component XorBits = XorBits(); + XorBits.a <== abits.out; + XorBits.b <== bbits.out; + + component num = Bits2Num(8); + num.in <== XorBits.out; + + out <== num.out; +} + +// XORs two arrays of bits +template XorBits(){ + signal input a[8]; + signal input b[8]; + signal output out[8]; + + component xor[8]; + for (var i = 0; i < 8; i++) { + xor[i] = XOR(); + xor[i].a <== a[i]; + xor[i].b <== b[i]; + out[i] <== xor[i].out; + } +} \ No newline at end of file diff --git a/circuits/aes-gcm-siv/README.md b/circuits/aes-gcm-siv/README.md deleted file mode 100644 index 9e43d08..0000000 --- a/circuits/aes-gcm-siv/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# AES-GCM Implementation in Circom -Circom circuits for aes-gcm-siv, borrowed from [electron-labs/aes-circom](https://github.com/Electron-Labs/aes-circom). - -❗❗❗ Note that these circuits have been [shown](https://github.com/Electron-Labs/aes-circom/issues/25) to be underconstrained. ❗❗❗ - -We intend to work on correctly constraining these circuits. - -This is based on the S-table implementation of [AES GCM SIV](https://datatracker.ietf.org/doc/html/rfc8452) encryption scheme. - -It is heavily inspired by the C implementation of [AES-GCM-SIV](https://github.com/Shay-Gueron/AES-GCM-SIV) \ No newline at end of file diff --git a/circuits/aes-gcm-siv/aes_256_ctr.circom b/circuits/aes-gcm-siv/aes_256_ctr.circom deleted file mode 100644 index 6dc6a98..0000000 --- a/circuits/aes-gcm-siv/aes_256_ctr.circom +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright © 2022, Electron Labs -pragma circom 2.0.0; - -include "aes_256_encrypt.circom"; -include "helper_functions.circom"; - -/// AES-256 CTR template -/// We will need to change this to AES-128 CTR -/// Which means we will need to change the aes_256_encrypt.circom to aes_128_encrypt.circom -template AES256CTR(n_bits) -{ - var msg_len = n_bits/8; - signal input in[n_bits]; - signal input ctr[128]; - /// TODO(WJ 2024-08-09): change to correct key bytes - /// Question: 1920 / 8 = 240? why is there key 16 bits less than the input size? - /// niavely it should be 128 * 8 = 1240 bits? - signal input ks[1920]; - - /// output is amount of input bits - signal output out[n_bits]; - - /// What is EK? - var EK[128]; - var p_index = 0, c_index = 0; - var ctr_t[128] = ctr; - var out_t[msg_len][8]; - - /// iterator varirables - var i, j, k, l; - - /// components for 16 bit blocks - component aes_256_encrypt_1[msg_len/16]; - component xor_1[msg_len/16][4][4][32]; - component num2bits_1[msg_len/16]; - component bits2num_1[msg_len/16]; - - for(i=0; i 32 bits = 1 row of state - { - xor_2[i][j][k-1][l*8+m].b <== num2bits_1[i][j][k].out[l*8+7-m]; - - xor_2[i][j][k][l*8+m] = XOR(); - xor_2[i][j][k][l*8+m].a <== xor_2[i][j][k-1][l*8+m].out; - } - } - } - /// Thought 1: is this maybe just copying memory? - else - { - for(l=0; l<4; l++) - { - for(m=0; m<8; m++) - { - xor_2[i][j][k-1][l*8+m].b <== num2bits_1[i][j][k].out[l*8+7-m]; - - xor_3[i][j][l*8+m] = XOR(); - xor_3[i][j][l*8+m].a <== xor_2[i][j][k-1][l*8+m].out; - } - } - } - } - } - for(j=0; j<4; j++) - { - for(l=0; l<32; l++) - { - xor_3[i][j][l].b <== ks[(j+ks_index)*32+l]; - s[j][l] = xor_3[i][j][l].out; - } - } - ks_index += 4; - } // end of round - - component bits2num_2[16]; - var s_bytes[16]; - - for(i=0; i<4; i++) - { - for(j=0; j<4; j++) - { - bits2num_2[i*4+j] = Bits2Num(8); - for(k=0; k<8; k++) bits2num_2[i*4+j].in[k] <== s[i][j*8+7-k]; - s_bytes[i*4+j] = bits2num_2[i*4+j].out; - } - } - - /// Row shifting and substitution - component row_shifting = EmulatedAesencRowShifting(); - component sub_bytes = EmulatedAesencSubstituteBytes(); - for(i=0; i<16; i++) row_shifting.in[i] <== s_bytes[i]; - for(i=0; i<16; i++) sub_bytes.in[i] <== row_shifting.out[i]; - - component num2bits_2[16]; - - for(i=0; i<4; i++) - { - for(j=0; j<4; j++) - { - num2bits_2[i*4+j] = Num2Bits(8); - num2bits_2[i*4+j].in <== sub_bytes.out[i*4+j]; - for(k=0; k<8; k++) s[i][j*8+k] = num2bits_2[i*4+j].out[7-k]; - } - } - - component xor_4[4][32]; - - for(i=0; i<4; i++) // final key XOR? - { - for(j=0; j<32; j++) - { - xor_4[i][j] = XOR(); - xor_4[i][j].a <== s[i][j]; - xor_4[i][j].b <== ks[(i+ks_index)*32+j]; - - s[i][j] = xor_4[i][j].out; - } - } - - for(i=0; i<4; i++) - { - for(j=0; j<32; j++) out[i*32+j] <== s[i][j]; - } -} - - diff --git a/circuits/aes-gcm-siv/aes_256_key_expansion.circom b/circuits/aes-gcm-siv/aes_256_key_expansion.circom deleted file mode 100644 index 676420b..0000000 --- a/circuits/aes-gcm-siv/aes_256_key_expansion.circom +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright © 2022, Electron Labs -pragma circom 2.0.0; - -include "helper_functions.circom"; -include "aes_emulation_tables.circom"; - -template AES256KeyExpansion() -{ - signal input key[256]; - signal output w[1920]; - - var rcon[10] = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36]; - - var Nk = 8; - var Nb = 4; - var Nr = 14; - var ks[60][32]; - var key_bits[32][8]; - - var i, j, k; - - for(i=0; i<32; i++) - { - for(j=0; j<8; j++) key_bits[i][j] = key[i*8+j]; - } - - i = 0; - while(i=n){ - out[i] <== 0; - } else { - out[i] <== in[i+r]; - } - } -} - -template IntRightShift(n, x) -{ - signal input in; - signal output out; - - component num2bits = Num2Bits(n); - num2bits.in <== in; - - component bits2num = Bits2Num(n); - var i; - for(i=0; i out_bits) - { - var ratio = in_bits/out_bits; - for(i=0; i in_bits) - { - var ratio = out_bits/in_bits; - for(i=0; i 32 bits = 1 row of state - { - xor_2[i][j][k-1][l*8+m].b <== num2bits_1[i][j][k].out[l*8+7-m]; - - xor_2[i][j][k][l*8+m] = XOR(); - xor_2[i][j][k][l*8+m].a <== xor_2[i][j][k-1][l*8+m].out; - } - } - } - else - { - for(l=0; l<4; l++) - { - for(m=0; m<8; m++) - { - xor_2[i][j][k-1][l*8+m].b <== num2bits_1[i][j][k].out[l*8+7-m]; - - xor_3[i][j][l*8+m] = XOR(); - xor_3[i][j][l*8+m].a <== xor_2[i][j][k-1][l*8+m].out; - } - } - } - } - } - /// AddRoundKey - for(j=0; j<4; j++) - { - for(l=0; l<32; l++) - { - xor_3[i][j][l].b <== ks[(j+ks_index)*32+l]; - s[j][l] = xor_3[i][j][l].out; - } - } - ks_index += 4; - } // end of round - - component bits2num_2[16]; - var s_bytes[16]; - - for(i=0; i<4; i++) - { - for(j=0; j<4; j++) - { - bits2num_2[i*4+j] = Bits2Num(8); - for(k=0; k<8; k++) bits2num_2[i*4+j].in[k] <== s[i][j*8+7-k]; - s_bytes[i*4+j] = bits2num_2[i*4+j].out; - } - } - - /// Row shifting and substitution - component row_shifting = EmulatedAesencRowShifting(); - component sub_bytes = EmulatedAesencSubstituteBytes(); - for(i=0; i<16; i++) row_shifting.in[i] <== s_bytes[i]; - for(i=0; i<16; i++) sub_bytes.in[i] <== row_shifting.out[i]; - - component num2bits_2[16]; - - for(i=0; i<4; i++) - { - for(j=0; j<4; j++) - { - num2bits_2[i*4+j] = Num2Bits(8); - num2bits_2[i*4+j].in <== sub_bytes.out[i*4+j]; - for(k=0; k<8; k++) s[i][j*8+k] = num2bits_2[i*4+j].out[7-k]; - } - } - - component xor_4[4][32]; - - for(i=0; i<4; i++) // final key XOR - { - for(j=0; j<32; j++) - { - xor_4[i][j] = XOR(); - xor_4[i][j].a <== s[i][j]; - xor_4[i][j].b <== ks[(i+ks_index)*32+j]; - - s[i][j] = xor_4[i][j].out; - } - } - - for(i=0; i<4; i++) - { - for(j=0; j<32; j++) out[i*32+j] <== s[i][j]; - } -} - - diff --git a/circuits/aes-gcm/aes_emulation.circom b/circuits/aes-gcm/aes_emulation.circom deleted file mode 100644 index 523561f..0000000 --- a/circuits/aes-gcm/aes_emulation.circom +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright © 2022, Electron Labs -pragma circom 2.0.0; - -include "aes_emulation_tables.circom"; - -/// template or row shifting -template EmulatedAesencRowShifting() -{ - - /// Opperating on 16 bits at a time - signal input in[16]; - signal output out[16]; - - var byte_order[16]; - byte_order[0] = 0; - byte_order[1] = 5; - byte_order[2] = 10; - byte_order[3] = 15; - byte_order[4] = 4; - byte_order[5] = 9; - byte_order[6] = 14; - byte_order[7] = 3; - byte_order[8] = 8; - byte_order[9] = 13; - byte_order[10] = 2; - byte_order[11] = 7; - byte_order[12] = 12; - byte_order[13] = 1; - byte_order[14] = 6; - byte_order[15] = 11; - - for(var i=0; i<16; i++) out[i] <== in[byte_order[i]]; -} - -/// Template for S-Box using the aes_encoding_rijndael_sbox -/// https://en.wikipedia.org/wiki/Rijndael_S-box -template EmulatedAesencSubstituteBytes() -{ - signal input in[16]; - signal output out[16]; - - for(var i=0; i<16; i++) out[i] <-- emulated_aesenc_rijndael_sbox(in[i]); - -} diff --git a/circuits/aes-gcm/aes_emulation_tables.circom b/circuits/aes-gcm/aes_emulation_tables.circom deleted file mode 100644 index c5dd399..0000000 --- a/circuits/aes-gcm/aes_emulation_tables.circom +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright © 2022, Electron Labs -pragma circom 2.0.0; - -function emulated_aesenc_enc_table(table_num, index) -{ - var lut[4][256]; - - lut[0] = [ - 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, - 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, - 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, - 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, - 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, - 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, - 0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, - 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, - 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, - 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, - 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, - 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, - 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, - 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, - 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, - 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, - 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, - 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, - 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, - 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, - 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, - 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, - 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, - 0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, - 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, - 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, - 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, - 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, - 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, - 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, - 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, - 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c - ]; - - lut[1] = [ - 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, - 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, - 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, - 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, - 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, - 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, - 0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5, - 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, - 0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, - 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, - 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, - 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, - 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, - 0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, - 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, - 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, - 0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, - 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, - 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, - 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, - 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4, - 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, - 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, - 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018, - 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, - 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, - 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12, - 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, - 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, - 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, - 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, - 0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a - ]; - - lut[2] = [ - 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, - 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, - 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, - 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, - 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, - 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, - 0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a, - 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, - 0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, - 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, - 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, - 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, - 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, - 0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, - 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, - 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, - 0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, - 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, - 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, - 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, - 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c, - 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, - 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, - 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808, - 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, - 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, - 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e, - 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, - 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, - 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, - 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, - 0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16 - ]; - - lut[3] = [ - 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, - 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, - 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, - 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, - 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, - 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, - 0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a, - 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, - 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, - 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, - 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, - 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, - 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, - 0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, - 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, - 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, - 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, - 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, - 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888, - 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, - 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c, - 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, - 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, - 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, - 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, - 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, - 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e, - 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, - 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494, - 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, - 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, - 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616 - ]; - - return lut[table_num][index]; -} - -function emulated_aesenc_rijndael_sbox(in) -{ - var lut[256] = [ - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, - 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, - 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, - 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, - 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, - 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, - 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, - 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, - 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, - 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, - 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, - 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, - 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, - 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, - 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, - 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 - ]; - - return lut[in]; -} - diff --git a/circuits/test/aes_128_enc.test.ts b/circuits/test/aes_128_enc.test.ts deleted file mode 100644 index adacd1e..0000000 --- a/circuits/test/aes_128_enc.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { WitnessTester } from "circomkit"; -import * as fs from 'fs'; -import { circomkit } from "./common"; - - -describe("AES 128 Enc", () => { - let circuit: WitnessTester<["in", "ks"], ["out"]>; - - const witness_data = parseJsonFile("inputs/aes_128_enc_witness.json"); - - before(async () => { - circuit = await circomkit.WitnessTester(`aes_128_enc`, { - file: "aes-gcm/aes_128_enc", - template: "AES128Encrypt", - // params: if the template has parameters - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - // TODO: Do we actually understand this? - it("should have correct number of constraints", async () => { - await circuit.expectConstraintCount(9920, true); - }); - - // non-linear constraints: 9600 Where does the extra 320 constraints come from? - // linear constraints: 0 - // public inputs: 0 - // private inputs: 1536 - // public outputs: 128 - // wires: 11137 - // labels: 22657 - - let key1 = witness_data["k1"]; - let inputs = witness_data["in"]; - let outputs = witness_data["out"]; - it("witness: in = [0,...]", async () => { - await circuit.expectPass( - { in: inputs , ks: key1 }, - { out: outputs } - ); - }); -}); - -function parseJsonFile(filePath: string): any { - const fileContent = fs.readFileSync(filePath, 'utf-8'); - return JSON.parse(fileContent); - } \ No newline at end of file diff --git a/circuits/test/aes_emulation.test.ts b/circuits/test/aes_emulation.test.ts deleted file mode 100644 index 308f663..0000000 --- a/circuits/test/aes_emulation.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { WitnessTester } from "circomkit"; -import { circomkit } from "./common"; - -describe("AES Emulation", () => { - let circuit: WitnessTester<["in"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`RowShifting`, { - file: "aes-gcm/aes_emulation", - template: "EmulatedAesencRowShifting", - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - // TODO: Do we actually understand this? - it("should have correct number of constraints", async () => { - await circuit.expectConstraintCount(16, true); /// should fail - }); - - const zeroArray: number[] = new Array(16).fill(0); - - it("witness: in = [0,...]", async () => { - await circuit.expectPass( - { in: zeroArray }, - { out: zeroArray } - ); - }); - - const indexArray: number[] = Array.from({ length: 16 }, (_, index) => index); - // State([[0, 5, 10, 15], [4, 9, 14, 3], [8, 13, 2, 7], [12, 1, 6, 11]]) - const outArray: number[] = [0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11]; - it("witness: in = [0,1,2,3,...,15]", async () => { - await circuit.expectPass( - { in: indexArray }, - { out: outArray } - ); - }); -}); \ No newline at end of file diff --git a/circuits/test/cipher.test.ts b/circuits/test/cipher.test.ts new file mode 100644 index 0000000..7c9d5e1 --- /dev/null +++ b/circuits/test/cipher.test.ts @@ -0,0 +1,67 @@ +import { WitnessTester } from "circomkit"; +import { circomkit } from "./common"; + +// todo: should debug cipher +describe("Cipher", () => { + let circuit: WitnessTester<["block", "key"], ["cipher"]>; + it("should perform Cipher#1", async () => { + circuit = await circomkit.WitnessTester(`Cipher`, { + file: "aes-ctr/cipher", + template: "Cipher", + params: [4], + }); + console.log("@Cipher #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass( + { + block: [ + [0x32, 0x88, 0x31, 0xe0], + [0x43, 0x5a, 0x31, 0x37], + [0xf6, 0x30, 0x98, 0x07], + [0xa8, 0x8d, 0xa2, 0x34], + ], + key: [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c], + }, + { + cipher: [ + [0x39, 0x02, 0xdc, 0x19], + [0x25, 0xdc, 0x11, 0x6a], + [0x84, 0x09, 0x85, 0x0b], + [0x1d, 0xfb, 0x97, 0x32], + ], + } + ); + }); + + // in : f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff + // out : ec8cdf7398607cb0f2d21675ea9ea1e4 + // key : 2b7e151628aed2a6abf7158809cf4f3c + it("should perform Cipher#2", async () => { + circuit = await circomkit.WitnessTester(`Cipher`, { + file: "aes-ctr/cipher", + template: "Cipher", + params: [4], + }); + console.log("@Cipher #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass( + { + block: [ + [0xf0, 0xf4, 0xf8, 0xfc], + [0xf1, 0xf5, 0xf9, 0xfd], + [0xf2, 0xf6, 0xfa, 0xfe], + [0xf3, 0xf7, 0xfb, 0xff], + ], + key: [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c], + }, + { + cipher: [ + [0xec, 0x98, 0xf2, 0xea], + [0x8c, 0x60, 0xd2, 0x9e], + [0xdf, 0x7c, 0x16, 0xa1], + [0x73, 0xb0, 0x75, 0xe4], + ], + } + ); + }); +}); diff --git a/circuits/test/ctr.test.ts b/circuits/test/ctr.test.ts new file mode 100644 index 0000000..eac56fd --- /dev/null +++ b/circuits/test/ctr.test.ts @@ -0,0 +1,306 @@ +import { WitnessTester } from "circomkit"; +import { circomkit } from "./common"; + +// todo: should debug cipher +describe("ToBlocks", () => { + let circuit: WitnessTester<["stream"], ["blocks"]>; + it("should convert stream to block", async () => { + circuit = await circomkit.WitnessTester(`ToBlocks`, { + file: "aes-ctr/ctr", + template: "ToBlocks", + params: [16], + }); + console.log("@ToBlocks #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass( + { + stream: [0x32, 0x88, 0x31, 0xe0, 0x43, 0x5a, 0x31, 0x37, 0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d, 0xa2, 0x34], + }, + { + blocks: [ + [ + [0x32, 0x43, 0xf6, 0xa8], + [0x88, 0x5a, 0x30, 0x8d], + [0x31, 0x31, 0x98, 0xa2], + [0xe0, 0x37, 0x07, 0x34], + ], + ], + } + ); + }); + it("should pad 1 in block", async () => { + circuit = await circomkit.WitnessTester(`ToBlocks`, { + file: "aes-ctr/ctr", + template: "ToBlocks", + params: [15], + }); + console.log("@EncryptCTR #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass( + { + stream: [0x32, 0x88, 0x31, 0xe0, 0x43, 0x5a, 0x31, 0x37, 0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d, 0xa2], + }, + { + blocks: [ + [ + [0x32, 0x43, 0xf6, 0xa8], + [0x88, 0x5a, 0x30, 0x8d], + [0x31, 0x31, 0x98, 0xa2], + [0xe0, 0x37, 0x07, 0x01], + ], + ], + } + ); + }); + it("should pad 0's in block", async () => { + circuit = await circomkit.WitnessTester(`ToBlocks`, { + file: "aes-ctr/ctr", + template: "ToBlocks", + params: [14], + }); + console.log("@ToBLocks #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass( + { + stream: [0x32, 0x88, 0x31, 0xe0, 0x43, 0x5a, 0x31, 0x37, 0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d], + }, + { + blocks: [ + [ + [0x32, 0x43, 0xf6, 0xa8], + [0x88, 0x5a, 0x30, 0x8d], + [0x31, 0x31, 0x98, 0x01], + [0xe0, 0x37, 0x07, 0x00], + ], + ], + } + ); + }); + it("should generate enough blocks", async () => { + circuit = await circomkit.WitnessTester(`ToBlocks`, { + file: "aes-ctr/ctr", + template: "ToBlocks", + params: [17], + }); + console.log("@ToBLocks #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass( + { + stream: [0x32, 0x88, 0x31, 0xe0, 0x42, 0x5a, 0x31, 0x37, 0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d, 0xa2, 0x34, 0x12], + }, + { + blocks: [ + [ + [0x32, 0x42, 0xf6, 0xa8], + [0x88, 0x5a, 0x30, 0x8d], + [0x31, 0x31, 0x98, 0xa2], + [0xe0, 0x37, 0x07, 0x34], + ], + [ + [0x12, 0x00, 0x00, 0x00], + [0x01, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00], + ], + ], + } + ); + }); +}); + +describe("EncryptCTR", () => { + let circuit: WitnessTester<["plainText", "iv", "key"], ["cipher"]>; + it("should encrypt 1 block correctly", async () => { + circuit = await circomkit.WitnessTester(`EncryptCTR`, { + file: "aes-ctr/ctr", + template: "EncryptCTR", + params: [16, 4], + }); + console.log("@ToBLocks #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass( + { + plainText: [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a], + iv: [0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff], + key: [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c], + }, + { + cipher: [0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce], + } + ); + }); + + // test vectors borrowed from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CTR.pdf + // Key is + // 2B7E1516 28AED2A6 ABF71588 09CF4F3C + // Plaintext is + // 6BC1BEE2 2E409F96 E93D7E11 7393172A + // AE2D8A57 1E03AC9C 9EB76FAC 45AF8E51 + // 30C81C46 A35CE411 E5FBC119 1A0A52EF + // F69F2445 DF4F9B17 AD2B417B E66C3710 + + // Cipher text is + // 874D6191 B620E326 1BEF6864 990DB6CE + // 9806F66B 7970FDFF 8617187B B9FFFDFF + // 5AE4DF3E DBD5D35E 5B4F0902 0DB03EAB + // 1E031DDA 2FBE03D1 792170A0 F3009CEE + it("should encrypt multiple blocks correctly", async () => { + circuit = await circomkit.WitnessTester(`EncryptCTR`, { + file: "aes-ctr/ctr", + template: "EncryptCTR", + params: [64, 4], + }); + console.log("@EncryptCTR #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass( + { + plainText: [ + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, + 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, + 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, + 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, + ], + iv: [0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff], + key: [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c], + }, + { + cipher: [ + 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce, 0x98, 0x06, + 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff, 0x5a, 0xe4, 0xdf, 0x3e, + 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab, 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, + 0x03, 0xd1, 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee, + ], + } + ); + }); +}); + +describe("ToStream", () => { + let circuit: WitnessTester<["blocks"], ["stream"]>; + it("should convert blocks to stream#1", async () => { + circuit = await circomkit.WitnessTester(`ToStream`, { + file: "aes-ctr/ctr", + template: "ToStream", + params: [1, 16], + }); + console.log("@ToStream #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass( + { + blocks: [ + [ + [0x32, 0x43, 0xf6, 0xa8], + [0x88, 0x5a, 0x30, 0x8d], + [0x31, 0x31, 0x98, 0xa2], + [0xe0, 0x37, 0x07, 0x34], + ], + ], + }, + { + stream: [0x32, 0x88, 0x31, 0xe0, 0x43, 0x5a, 0x31, 0x37, 0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d, 0xa2, 0x34], + } + ); + }); + it("should convert blocks to stream#2", async () => { + circuit = await circomkit.WitnessTester(`ToStream`, { + file: "aes-ctr/ctr", + template: "ToStream", + params: [1, 15], + }); + console.log("@ToStream #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass( + { + blocks: [ + [ + [0x32, 0x43, 0xf6, 0xa8], + [0x88, 0x5a, 0x30, 0x8d], + [0x31, 0x31, 0x98, 0xa2], + [0xe0, 0x37, 0x07, 0x01], + ], + ], + }, + { + stream: [0x32, 0x88, 0x31, 0xe0, 0x43, 0x5a, 0x31, 0x37, 0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d, 0xa2], + } + ); + }); + it("should convert multiple blocks to stream", async () => { + circuit = await circomkit.WitnessTester(`ToStream`, { + file: "aes-ctr/ctr", + template: "ToStream", + params: [2, 18], + }); + console.log("@ToStream #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass( + { + blocks: [ + [ + [0x32, 0x43, 0xf6, 0xa8], + [0x88, 0x5a, 0x30, 0x8d], + [0x31, 0x31, 0x98, 0xa2], + [0xe0, 0x37, 0x07, 0x01], + ], + [ + [0x32, 0x43, 0xf6, 0xa8], + [0x88, 0x5a, 0x30, 0x8d], + [0x31, 0x31, 0x98, 0xa2], + [0xe0, 0x37, 0x07, 0x01], + ], + ], + }, + { + stream: [ + 0x32, 0x88, 0x31, 0xe0, 0x43, 0x5a, 0x31, 0x37, 0xf6, 0x30, 0x98, 0x07, 0xa8, 0x8d, 0xa2, 0x01, 0x32, 0x88, + ], + } + ); + }); +}); + +describe("GenerateCounterBlocks", async () => { + let circuit: WitnessTester<["iv"], ["counterBlocks"]>; + it("should generate counter blocks correctly", async () => { + circuit = await circomkit.WitnessTester(`GenerateCounterBlocks`, { + file: "aes-ctr/ctr", + template: "GenerateCounterBlocks", + params: [4], + }); + console.log("@GenerateCounterBlocks #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass( + { + iv: [0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff], + }, + { + counterBlocks: [ + [ + [0xf0, 0xf4, 0xf8, 0xfc], + [0xf1, 0xf5, 0xf9, 0xfd], + [0xf2, 0xf6, 0xfa, 0xfe], + [0xf3, 0xf7, 0xfb, 0xff], + ], + [ + [0xf0, 0xf4, 0xf8, 0xfc], + [0xf1, 0xf5, 0xf9, 0xfd], + [0xf2, 0xf6, 0xfa, 0xff], + [0xf3, 0xf7, 0xfb, 0x00], + ], + [ + [0xf0, 0xf4, 0xf8, 0xfc], + [0xf1, 0xf5, 0xf9, 0xfd], + [0xf2, 0xf6, 0xfa, 0xff], + [0xf3, 0xf7, 0xfb, 0x01], + ], + [ + [0xf0, 0xf4, 0xf8, 0xfc], + [0xf1, 0xf5, 0xf9, 0xfd], + [0xf2, 0xf6, 0xfa, 0xff], + [0xf3, 0xf7, 0xfb, 0x02], + ], + ], + } + ); + }); +}); diff --git a/circuits/test/key_expansion.test.ts b/circuits/test/key_expansion.test.ts new file mode 100644 index 0000000..d2e329d --- /dev/null +++ b/circuits/test/key_expansion.test.ts @@ -0,0 +1,208 @@ +import { WitnessTester } from "circomkit"; +import { circomkit } from "./common"; + +describe("KeyExpansion", () => { + it("should compute correctly for aes128", async () => { + const circuit: WitnessTester<["key"], ["keyExpanded"]> = await circomkit.WitnessTester(`SubBytes`, { + file: "aes-ctr/key_expansion", + template: "KeyExpansion", + params: [4, 10], + }); + console.log("#constraints:", await circuit.getConstraintCount()); + const key = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c]; + const keyExpanded = [ + [0x2b, 0x7e, 0x15, 0x16], + [0x28, 0xae, 0xd2, 0xa6], + [0xab, 0xf7, 0x15, 0x88], + [0x09, 0xcf, 0x4f, 0x3c], + [0xa0, 0xfa, 0xfe, 0x17], + [0x88, 0x54, 0x2c, 0xb1], + [0x23, 0xa3, 0x39, 0x39], + [0x2a, 0x6c, 0x76, 0x05], + [0xf2, 0xc2, 0x95, 0xf2], + [0x7a, 0x96, 0xb9, 0x43], + [0x59, 0x35, 0x80, 0x7a], + [0x73, 0x59, 0xf6, 0x7f], + [0x3d, 0x80, 0x47, 0x7d], + [0x47, 0x16, 0xfe, 0x3e], + [0x1e, 0x23, 0x7e, 0x44], + [0x6d, 0x7a, 0x88, 0x3b], + [0xef, 0x44, 0xa5, 0x41], + [0xa8, 0x52, 0x5b, 0x7f], + [0xb6, 0x71, 0x25, 0x3b], + [0xdb, 0x0b, 0xad, 0x00], + [0xd4, 0xd1, 0xc6, 0xf8], + [0x7c, 0x83, 0x9d, 0x87], + [0xca, 0xf2, 0xb8, 0xbc], + [0x11, 0xf9, 0x15, 0xbc], + [0x6d, 0x88, 0xa3, 0x7a], + [0x11, 0x0b, 0x3e, 0xfd], + [0xdb, 0xf9, 0x86, 0x41], + [0xca, 0x00, 0x93, 0xfd], + [0x4e, 0x54, 0xf7, 0x0e], + [0x5f, 0x5f, 0xc9, 0xf3], + [0x84, 0xa6, 0x4f, 0xb2], + [0x4e, 0xa6, 0xdc, 0x4f], + [0xea, 0xd2, 0x73, 0x21], + [0xb5, 0x8d, 0xba, 0xd2], + [0x31, 0x2b, 0xf5, 0x60], + [0x7f, 0x8d, 0x29, 0x2f], + [0xac, 0x77, 0x66, 0xf3], + [0x19, 0xfa, 0xdc, 0x21], + [0x28, 0xd1, 0x29, 0x41], + [0x57, 0x5c, 0x00, 0x6e], + [0xd0, 0x14, 0xf9, 0xa8], + [0xc9, 0xee, 0x25, 0x89], + [0xe1, 0x3f, 0x0c, 0xc8], + [0xb6, 0x63, 0x0c, 0xa6], + ]; + await circuit.expectPass({ key }, { keyExpanded }); + }); + it("should compute correctly for aes 192", async () => { + const circuit: WitnessTester<["key"], ["keyExpanded"]> = await circomkit.WitnessTester(`SubBytes`, { + file: "aes-ctr/key_expansion", + template: "KeyExpansion", + params: [6, 12], + }); + console.log("#constraints:", await circuit.getConstraintCount()); + const key = [ + 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, 0x62, 0xf8, 0xea, + 0xd2, 0x52, 0x2c, 0x6b, 0x7b, + ]; + + const keyExpanded = [ + [0x8e, 0x73, 0xb0, 0xf7], + [0xda, 0x0e, 0x64, 0x52], + [0xc8, 0x10, 0xf3, 0x2b], + [0x80, 0x90, 0x79, 0xe5], + [0x62, 0xf8, 0xea, 0xd2], + [0x52, 0x2c, 0x6b, 0x7b], + [0xfe, 0x0c, 0x91, 0xf7], + [0x24, 0x02, 0xf5, 0xa5], + [0xec, 0x12, 0x06, 0x8e], + [0x6c, 0x82, 0x7f, 0x6b], + [0x0e, 0x7a, 0x95, 0xb9], + [0x5c, 0x56, 0xfe, 0xc2], + [0x4d, 0xb7, 0xb4, 0xbd], + [0x69, 0xb5, 0x41, 0x18], + [0x85, 0xa7, 0x47, 0x96], + [0xe9, 0x25, 0x38, 0xfd], + [0xe7, 0x5f, 0xad, 0x44], + [0xbb, 0x09, 0x53, 0x86], + [0x48, 0x5a, 0xf0, 0x57], + [0x21, 0xef, 0xb1, 0x4f], + [0xa4, 0x48, 0xf6, 0xd9], + [0x4d, 0x6d, 0xce, 0x24], + [0xaa, 0x32, 0x63, 0x60], + [0x11, 0x3b, 0x30, 0xe6], + [0xa2, 0x5e, 0x7e, 0xd5], + [0x83, 0xb1, 0xcf, 0x9a], + [0x27, 0xf9, 0x39, 0x43], + [0x6a, 0x94, 0xf7, 0x67], + [0xc0, 0xa6, 0x94, 0x07], + [0xd1, 0x9d, 0xa4, 0xe1], + [0xec, 0x17, 0x86, 0xeb], + [0x6f, 0xa6, 0x49, 0x71], + [0x48, 0x5f, 0x70, 0x32], + [0x22, 0xcb, 0x87, 0x55], + [0xe2, 0x6d, 0x13, 0x52], + [0x33, 0xf0, 0xb7, 0xb3], + [0x40, 0xbe, 0xeb, 0x28], + [0x2f, 0x18, 0xa2, 0x59], + [0x67, 0x47, 0xd2, 0x6b], + [0x45, 0x8c, 0x55, 0x3e], + [0xa7, 0xe1, 0x46, 0x6c], + [0x94, 0x11, 0xf1, 0xdf], + [0x82, 0x1f, 0x75, 0x0a], + [0xad, 0x07, 0xd7, 0x53], + [0xca, 0x40, 0x05, 0x38], + [0x8f, 0xcc, 0x50, 0x06], + [0x28, 0x2d, 0x16, 0x6a], + [0xbc, 0x3c, 0xe7, 0xb5], + [0xe9, 0x8b, 0xa0, 0x6f], + [0x44, 0x8c, 0x77, 0x3c], + [0x8e, 0xcc, 0x72, 0x04], + [0x01, 0x00, 0x22, 0x02], + ]; + + await circuit.expectPass({ key }, { keyExpanded }); + }); + + it("should compute correctly for aes256", async () => { + const circuit: WitnessTester<["key"], ["keyExpanded"]> = await circomkit.WitnessTester(`SubBytes`, { + file: "aes-ctr/key_expansion", + template: "KeyExpansion", + params: [8, 14], + }); + console.log("#constraints:", await circuit.getConstraintCount()); + const key = [ + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, + 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4, + ]; + + const keyExpanded = [ + [0x60, 0x3d, 0xeb, 0x10], + [0x15, 0xca, 0x71, 0xbe], + [0x2b, 0x73, 0xae, 0xf0], + [0x85, 0x7d, 0x77, 0x81], + [0x1f, 0x35, 0x2c, 0x07], + [0x3b, 0x61, 0x08, 0xd7], + [0x2d, 0x98, 0x10, 0xa3], + [0x09, 0x14, 0xdf, 0xf4], + [0x9b, 0xa3, 0x54, 0x11], + [0x8e, 0x69, 0x25, 0xaf], + [0xa5, 0x1a, 0x8b, 0x5f], + [0x20, 0x67, 0xfc, 0xde], + [0xa8, 0xb0, 0x9c, 0x1a], + [0x93, 0xd1, 0x94, 0xcd], + [0xbe, 0x49, 0x84, 0x6e], + [0xb7, 0x5d, 0x5b, 0x9a], + [0xd5, 0x9a, 0xec, 0xb8], + [0x5b, 0xf3, 0xc9, 0x17], + [0xfe, 0xe9, 0x42, 0x48], + [0xde, 0x8e, 0xbe, 0x96], + [0xb5, 0xa9, 0x32, 0x8a], + [0x26, 0x78, 0xa6, 0x47], + [0x98, 0x31, 0x22, 0x29], + [0x2f, 0x6c, 0x79, 0xb3], + [0x81, 0x2c, 0x81, 0xad], + [0xda, 0xdf, 0x48, 0xba], + [0x24, 0x36, 0x0a, 0xf2], + [0xfa, 0xb8, 0xb4, 0x64], + [0x98, 0xc5, 0xbf, 0xc9], + [0xbe, 0xbd, 0x19, 0x8e], + [0x26, 0x8c, 0x3b, 0xa7], + [0x09, 0xe0, 0x42, 0x14], + [0x68, 0x00, 0x7b, 0xac], + [0xb2, 0xdf, 0x33, 0x16], + [0x96, 0xe9, 0x39, 0xe4], + [0x6c, 0x51, 0x8d, 0x80], + [0xc8, 0x14, 0xe2, 0x04], + [0x76, 0xa9, 0xfb, 0x8a], + [0x50, 0x25, 0xc0, 0x2d], + [0x59, 0xc5, 0x82, 0x39], + [0xde, 0x13, 0x69, 0x67], + [0x6c, 0xcc, 0x5a, 0x71], + [0xfa, 0x25, 0x63, 0x95], + [0x96, 0x74, 0xee, 0x15], + [0x58, 0x86, 0xca, 0x5d], + [0x2e, 0x2f, 0x31, 0xd7], + [0x7e, 0x0a, 0xf1, 0xfa], + [0x27, 0xcf, 0x73, 0xc3], + [0x74, 0x9c, 0x47, 0xab], + [0x18, 0x50, 0x1d, 0xda], + [0xe2, 0x75, 0x7e, 0x4f], + [0x74, 0x01, 0x90, 0x5a], + [0xca, 0xfa, 0xaa, 0xe3], + [0xe4, 0xd5, 0x9b, 0x34], + [0x9a, 0xdf, 0x6a, 0xce], + [0xbd, 0x10, 0x19, 0x0d], + [0xfe, 0x48, 0x90, 0xd1], + [0xe6, 0x18, 0x8d, 0x0b], + [0x04, 0x6d, 0xf3, 0x44], + [0x70, 0x6c, 0x63, 0x1e], + ]; + + await circuit.expectPass({ key }, { keyExpanded }); + }); +}); diff --git a/circuits/test/next_round.test.ts b/circuits/test/next_round.test.ts new file mode 100644 index 0000000..3e298ef --- /dev/null +++ b/circuits/test/next_round.test.ts @@ -0,0 +1,64 @@ +import { WitnessTester } from "circomkit"; +import { circomkit } from "./common"; + +describe("NextRound", () => { + let circuit: WitnessTester<["key", "round"], ["nextKey"]>; + + describe("NextRound", () => { + before(async () => { + circuit = await circomkit.WitnessTester(`NextRound_${4}_${4}`, { + file: "aes-ctr/key_expansion", + template: "NextRound", + params: [4, 4], + }); + console.log("#constraints:", await circuit.getConstraintCount()); + }); + + it("should compute correctly", async () => { + const key = [ + [0x2b, 0x7e, 0x15, 0x16], + [0x28, 0xae, 0xd2, 0xa6], + [0xab, 0xf7, 0x15, 0x88], + [0x09, 0xcf, 0x4f, 0x3c], + ]; + + const expectedNextKey = [ + [0xa0, 0xfa, 0xfe, 0x17], + [0x88, 0x54, 0x2c, 0xb1], + [0x23, 0xa3, 0x39, 0x39], + [0x2a, 0x6c, 0x76, 0x05], + ]; + + await circuit.expectPass({ key, round: 1 }, { nextKey: expectedNextKey }); + }); + }); + + // describe("NextRound", () => { + // before(async () => { + // circuit = await circomkit.WitnessTester(`NextRound_${6}_${6}`, { + // file: "key_expansion", + // template: "NextRound", + // params: [6, 6], + // }); + // console.log("#constraints:", await circuit.getConstraintCount()); + // }); + + // it("should compute correctly for AES-192", async () => { + // const key = [ + // [0x8e, 0x73, 0xb0, 0xf7], + // [0xda, 0x0e, 0x64, 0x52], + // [0xc8, 0x10, 0xf3, 0x2b], + // [0x80, 0x90, 0x79, 0xe5], + // ]; + + // const expectedNextKey = [ + // [0x62, 0xf8, 0xea, 0xd2], + // [0x52, 0x2c, 0x6b, 0x7b], + // [0xfe, 0x0c, 0x91, 0xf7], + // [0x24, 0x02, 0xf5, 0xa5], + // ]; + + // await circuit.expectPass({ key, round: 1 }, { nextKey: expectedNextKey }); + // }); + // }); +}); diff --git a/circuits/test/sbox128.test.ts b/circuits/test/sbox128.test.ts new file mode 100644 index 0000000..18c586d --- /dev/null +++ b/circuits/test/sbox128.test.ts @@ -0,0 +1,21 @@ +import { WitnessTester } from "circomkit"; +import { circomkit } from "./common"; + +describe("SBox128", () => { + let circuit: WitnessTester<["in"], ["out"]>; + + describe("SubBox", () => { + before(async () => { + circuit = await circomkit.WitnessTester(`SubBytes`, { + file: "aes-ctr/sbox128", + template: "SBox128", + }); + console.log("#constraints:", await circuit.getConstraintCount()); + }); + + it("should compute correctly", async () => { + await circuit.expectPass({ in: 0x53 }, { out: 0xed }); + await circuit.expectPass({ in: 0x00 }, { out: 0x63 }); + }); + }); +}); diff --git a/circuits/test/transformations.test.ts b/circuits/test/transformations.test.ts new file mode 100644 index 0000000..72568d5 --- /dev/null +++ b/circuits/test/transformations.test.ts @@ -0,0 +1,360 @@ +import { WitnessTester } from "circomkit"; +import { circomkit } from "./common"; + +describe("AES Key Expansion Components", () => { + describe("BytesToWords", () => { + let circuit: WitnessTester<["bytes"], ["words"]>; + before(async () => { + circuit = await circomkit.WitnessTester(`BytesToWords`, { + file: "aes-ctr/key_expansion", + template: "BytesToWords", + params: [4], + }); + console.log("BytesToWords #constraints:", await circuit.getConstraintCount()); + }); + + it("should compute correctly", async () => { + await circuit.expectPass({ bytes: [0x01, 0x12, 0x02, 0x30] }, { words: [[0x01, 0x12, 0x02, 0x30]] }); + }); + }); + + describe("Rotate", () => { + let circuit: WitnessTester<["bytes"], ["rotated"]>; + + it("should rotate correctly", async () => { + circuit = await circomkit.WitnessTester(`Rotate`, { + file: "aes-ctr/key_expansion", + template: "Rotate", + params: [1, 4], + }); + console.log("RotateWord #constraints:", await circuit.getConstraintCount()); + await circuit.expectPass({ bytes: [0x01, 0x12, 0x02, 0x30] }, { rotated: [0x12, 0x02, 0x30, 0x01] }); + }); + }); + + describe("SubstituteWord", () => { + let circuit: WitnessTester<["bytes"], ["substituted"]>; + before(async () => { + circuit = await circomkit.WitnessTester(`SubstituteWord`, { + file: "aes-ctr/key_expansion", + template: "SubstituteWord", + }); + console.log("SubstituteWord #constraints:", await circuit.getConstraintCount()); + }); + + it("should substitute correctly", async () => { + await circuit.expectPass({ bytes: [0x00, 0x10, 0x20, 0x30] }, { substituted: [0x63, 0xca, 0xb7, 0x04] }); + }); + }); + + describe("RCon", () => { + let circuit: WitnessTester<["round"], ["out"]>; + before(async () => { + circuit = await circomkit.WitnessTester(`RCon`, { + file: "aes-ctr/key_expansion", + template: "RCon", + }); + console.log("RCon #constraints:", await circuit.getConstraintCount()); + }); + + it("should compute round constant correctly", async () => { + await circuit.expectPass({ round: 1 }, { out: [0x01, 0x00, 0x00, 0x00] }); + await circuit.expectPass({ round: 2 }, { out: [0x02, 0x00, 0x00, 0x00] }); + await circuit.expectPass({ round: 10 }, { out: [0x36, 0x00, 0x00, 0x00] }); + }); + }); + + describe("XorWord", () => { + let circuit: WitnessTester<["bytes1", "bytes2"], ["out"]>; + before(async () => { + circuit = await circomkit.WitnessTester(`XorWord`, { + file: "aes-ctr/key_expansion", + template: "XorWord", + }); + console.log("XorWord #constraints:", await circuit.getConstraintCount()); + }); + + it("should XOR correctly", async () => { + await circuit.expectPass( + { bytes1: [0x0a, 0x0b, 0x0c, 0x0d], bytes2: [0x01, 0x02, 0x03, 0x04] }, + { out: [0x0b, 0x09, 0x0f, 0x09] } + ); + }); + }); + + describe("WordSelector", () => { + let circuit: WitnessTester<["condition", "bytes1", "bytes2"], ["out"]>; + before(async () => { + circuit = await circomkit.WitnessTester(`WordSelector`, { + file: "aes-ctr/key_expansion", + template: "WordSelector", + }); + console.log("WordSelector #constraints:", await circuit.getConstraintCount()); + }); + + it("should select first word when condition is 1", async () => { + await circuit.expectPass( + { condition: 1, bytes1: [0x0a, 0x0b, 0x0c, 0x0d], bytes2: [0x01, 0x02, 0x03, 0x04] }, + { out: [0x0a, 0x0b, 0x0c, 0x0d] } + ); + }); + + it("should select second word when condition is 0", async () => { + await circuit.expectPass( + { condition: 0, bytes1: [0x0a, 0x0b, 0x0c, 0x0d], bytes2: [0x01, 0x02, 0x03, 0x04] }, + { out: [0x01, 0x02, 0x03, 0x04] } + ); + }); + }); +}); + +describe("XTimes2", () => { + let circuit: WitnessTester<["in"], ["out"]>; + it("should perform 2 times", async () => { + circuit = await circomkit.WitnessTester(`XTimes2`, { + file: "aes-ctr/cipher", + template: "XTimes2", + }); + console.log("@XTimes2 #constraints:", await circuit.getConstraintCount()); + + // 0x57 . 2 = 0xae + await circuit.expectPass({ in: [1, 1, 1, 0, 1, 0, 1, 0] }, { out: [0, 1, 1, 1, 0, 1, 0, 1] }); + // 0x54 . 2 = 0xa8 + await circuit.expectPass({ in: [0, 0, 1, 0, 1, 0, 1, 0] }, { out: [0, 0, 0, 1, 0, 1, 0, 1] }); + // 0xae . 2 = 0x47 + await circuit.expectPass({ in: [0, 1, 1, 1, 0, 1, 0, 1] }, { out: [1, 1, 1, 0, 0, 0, 1, 0] }); + // 0x47 . 2 = 0x8e + await circuit.expectPass({ in: [1, 1, 1, 0, 0, 0, 1, 0] }, { out: [0, 1, 1, 1, 0, 0, 0, 1] }); + }); +}); +describe("XTimes", () => { + let circuit: WitnessTester<["in"], ["out"]>; + it("should perform xtimes", async () => { + circuit = await circomkit.WitnessTester(`XTimes`, { + file: "aes-ctr/cipher", + template: "XTimes", + params: [0x13], + }); + console.log("@XTimes2 #constraints:", await circuit.getConstraintCount()); + + // 0x57 . 0x13 = 0xfe + await circuit.expectPass({ in: [1, 1, 1, 0, 1, 0, 1, 0] }, { out: [0, 1, 1, 1, 1, 1, 1, 1] }); + }); +}); + +describe("XTimes2 with XTimes", () => { + let circuit: WitnessTester<["in"], ["out"]>; + it("should perform 2 times with XTERMS", async () => { + circuit = await circomkit.WitnessTester(`XTimes`, { + file: "aes-ctr/cipher", + template: "XTimes", + params: [0x2], + }); + console.log("@XTimes2 #constraints:", await circuit.getConstraintCount()); + + // 0x57 . 2 = 0xae + await circuit.expectPass({ in: [1, 1, 1, 0, 1, 0, 1, 0] }, { out: [0, 1, 1, 1, 0, 1, 0, 1] }); + // 0x54 . 2 = 0xa8 + await circuit.expectPass({ in: [0, 0, 1, 0, 1, 0, 1, 0] }, { out: [0, 0, 0, 1, 0, 1, 0, 1] }); + // 0xae . 2 = 0x47 + await circuit.expectPass({ in: [0, 1, 1, 1, 0, 1, 0, 1] }, { out: [1, 1, 1, 0, 0, 0, 1, 0] }); + // 0x47 . 2 = 0x8e + await circuit.expectPass({ in: [1, 1, 1, 0, 0, 0, 1, 0] }, { out: [0, 1, 1, 1, 0, 0, 0, 1] }); + }); +}); + +describe("XTimes1 with XTimes", () => { + let circuit: WitnessTester<["in"], ["out"]>; + it("should perform 1 times with XTERMS", async () => { + circuit = await circomkit.WitnessTester(`XTimes`, { + file: "aes-ctr/cipher", + template: "XTimes", + params: [0x1], + }); + console.log("@XTimes2 #constraints:", await circuit.getConstraintCount()); + + // 0x57 . 2 = 0xae + await circuit.expectPass({ in: [1, 1, 1, 0, 1, 0, 1, 0] }, { out: [1, 1, 1, 0, 1, 0, 1, 0] }); + // 0x54 . 2 = 0xa8 + await circuit.expectPass({ in: [0, 0, 1, 0, 1, 0, 1, 0] }, { out: [0, 0, 1, 0, 1, 0, 1, 0] }); + // 0xae . 2 = 0x47 + await circuit.expectPass({ in: [0, 1, 1, 1, 0, 1, 0, 1] }, { out: [0, 1, 1, 1, 0, 1, 0, 1] }); + // 0x47 . 2 = 0x8e + await circuit.expectPass({ in: [1, 1, 1, 0, 1, 0, 1, 0] }, { out: [1, 1, 1, 0, 1, 0, 1, 0] }); + }); +}); + +describe("MixColumns", () => { + it("s0 should compute correctly", async () => { + let circuit: WitnessTester<["in"], ["out"]>; + circuit = await circomkit.WitnessTester(`s0`, { + file: "aes-ctr/cipher", + template: "S0", + params: [], + }); + console.log("@S0 #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass({ in: [0xd4, 0xbf, 0x5d, 0x30] }, { out: 0x04 }); + }); + + it("s1 should compute correctly", async () => { + let circuit: WitnessTester<["in"], ["out"]>; + circuit = await circomkit.WitnessTester(`s1`, { + file: "aes-ctr/cipher", + template: "S1", + params: [], + }); + console.log("@S1 #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass({ in: [0xd4, 0xbf, 0x5d, 0x30] }, { out: 0x66 }); + }); + + it("s2 should compute correctly", async () => { + let circuit: WitnessTester<["in"], ["out"]>; + circuit = await circomkit.WitnessTester(`s2`, { + file: "aes-ctr/cipher", + template: "S2", + params: [], + }); + console.log("@S2 #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass({ in: [0xd4, 0xbf, 0x5d, 0x30] }, { out: 0x81 }); + }); + + it("s3 should compute correctly", async () => { + let circuit: WitnessTester<["in"], ["out"]>; + circuit = await circomkit.WitnessTester(`s3`, { + file: "aes-ctr/cipher", + template: "S3", + params: [], + }); + console.log("@S3 #constraints:", await circuit.getConstraintCount()); + + await circuit.expectPass({ in: [0xd4, 0xbf, 0x5d, 0x30] }, { out: 0xe5 }); + }); + + it("s4 should compute correctly", async () => { + let circuit: WitnessTester<["state"], ["out"]>; + circuit = await circomkit.WitnessTester(`MixColumns`, { + file: "aes-ctr/cipher", + template: "MixColumns", + params: [], + }); + console.log("@MixColumns #constraints:", await circuit.getConstraintCount()); + const state = [ + [0xd4, 0xe0, 0xb8, 0x1e], + [0xbf, 0xb4, 0x41, 0x27], + [0x5d, 0x52, 0x11, 0x98], + [0x30, 0xae, 0xf1, 0xe5], + ]; + + const out = [ + [0x04, 0xe0, 0x48, 0x28], + [0x66, 0xcb, 0xf8, 0x06], + [0x81, 0x19, 0xd3, 0x26], + [0xe5, 0x9a, 0x7a, 0x4c], + ]; + + await circuit.expectPass({ state }, { out }); + }); +}); + +describe("AddRoundKey", () => { + let circuit: WitnessTester<["state", "roundKey"], ["newState"]>; + it("should perform AddRoundKey", async () => { + circuit = await circomkit.WitnessTester(`AddRoundKey`, { + file: "aes-ctr/cipher", + template: "AddRoundKey", + }); + console.log("@AddRoundKey #constraints:", await circuit.getConstraintCount()); + + // 0x57 . 2 = 0xae + await circuit.expectPass( + { + state: [ + [4, 224, 72, 40], + [102, 203, 248, 6], + [129, 25, 211, 38], + [229, 154, 122, 76], + ], + roundKey: [ + [160, 250, 254, 23], + [136, 84, 44, 177], + [35, 163, 57, 57], + [42, 108, 118, 5], + ], + }, + { + newState: [ + [164, 104, 107, 2], + [156, 159, 91, 106], + [127, 53, 234, 80], + [242, 43, 67, 73], + ], + } + ); + }); +}); + +describe("SubBlock", () => { + let circuit: WitnessTester<["state"], ["newState"]>; + it("should perform SubBlock", async () => { + circuit = await circomkit.WitnessTester(`SubBlock`, { + file: "aes-ctr/cipher", + template: "SubBlock", + }); + console.log("@SubBlock #constraints:", await circuit.getConstraintCount()); + + // 0x57 . 2 = 0xae + await circuit.expectPass( + { + state: [ + [25, 160, 154, 233], + [61, 244, 198, 248], + [227, 226, 141, 72], + [190, 43, 42, 8], + ], + }, + { + newState: [ + [212, 224, 184, 30], + [39, 191, 180, 65], + [17, 152, 93, 82], + [174, 241, 229, 48], + ], + } + ); + }); +}); + +describe("ShiftRows", () => { + let circuit: WitnessTester<["state"], ["newState"]>; + it("should perform ShiftRows", async () => { + circuit = await circomkit.WitnessTester(`ShiftRows`, { + file: "aes-ctr/cipher", + template: "ShiftRows", + params: [], + }); + console.log("@ShiftRows #constraints:", await circuit.getConstraintCount()); + + // 0x57 . 2 = 0xae + await circuit.expectPass( + { + state: [ + [212, 224, 184, 30], + [39, 191, 180, 65], + [17, 152, 93, 82], + [174, 241, 229, 48], + ], + }, + { + newState: [ + [212, 224, 184, 30], + [191, 180, 65, 39], + [93, 82, 17, 152], + [48, 174, 241, 229], + ], + } + ); + }); +}); diff --git a/inputs/cipher_4/default.json b/inputs/cipher_4/default.json new file mode 100644 index 0000000..15a48e1 --- /dev/null +++ b/inputs/cipher_4/default.json @@ -0,0 +1,10 @@ +{ + "block": [ + [50, 136, 49, 224], + [67, 90, 49, 55], + [246, 48, 152, 7], + [168, 141, 162, 52] + ], + "key": [43, 126, 21, 22, 40, 174, 210, 166, 171, 247, 21, 136, 9, 207, 79, 60] + } + \ No newline at end of file diff --git a/inputs/multiplier_3/default.json b/inputs/multiplier_3/default.json deleted file mode 100644 index 6ae4485..0000000 --- a/inputs/multiplier_3/default.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "in": [2, 4, 10] - } \ No newline at end of file From 30f0129858504d5c70a0c6715bce94fca3ece70b Mon Sep 17 00:00:00 2001 From: Waylon Jepsen Date: Sat, 10 Aug 2024 21:05:42 -0400 Subject: [PATCH 8/8] fix key size --- src/consts.rs | 14 ++------------ src/utils.rs | 22 ++++++++++------------ src/witness.rs | 8 ++++---- 3 files changed, 16 insertions(+), 28 deletions(-) diff --git a/src/consts.rs b/src/consts.rs index 9b99eb0..8630724 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -3,18 +3,8 @@ pub(crate) const KEY_ASCII: &str = "1111111111111111"; // 16 bytes pub(crate) const IV_ASCII: &str = "111111111111"; // 12 bytes pub(crate) const MESSAGE: &str = "test000000000000"; -pub(crate) const KEY_BYTES_176: [u8; 176] = [ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, - 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, - 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, - 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, - 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, - 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, - 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, - 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, +pub(crate) const KEY_BYTES_156: [u8; 16] = [ + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, ]; pub(crate) const KEY_BYTES_256: [u8; 32] = [ 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00, 0x0, diff --git a/src/utils.rs b/src/utils.rs index eeffc34..648b14f 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -77,9 +77,9 @@ pub(crate) fn parse_bit_from_field(j: &Fr) -> u8 { } #[derive(Serialize)] pub(crate) struct AESInputs { - k1: Vec, + k1: Vec, r#in: Vec, - out: Vec, + out: Vec, } /// Input signals for the AES-GCM-SIV circuit: /// signal input K1[256]; @@ -110,24 +110,22 @@ pub(crate) fn make_json_witness(witness: &Witness, mode: CipherMode) -> Result<( assert_eq!(data.CT.len(), 256, "CT must be 256 bits"); let mut file = std::fs::File::create("inputs/aes_gcm_siv_witness.json").unwrap(); file.write_all(serde_json::to_string_pretty(&data).unwrap().as_bytes()).unwrap(); - - } - CipherMode::Ctr256 => { } + }, + CipherMode::Ctr256 => {}, CipherMode::Vanilla => { let data = AESInputs { - k1: bytes_to_bits(&witness.key), - r#in: bytes_to_bits(&witness.pt), - out: bytes_to_bits(&witness.ct), + k1: bytes_to_bits(&witness.key), + r#in: bytes_to_bits(&witness.pt), + out: bytes_to_bits(&witness.ct), }; assert_eq!(data.k1.len(), 1408, "k1 must be 1408 bits"); let mut file = std::fs::File::create("inputs/aes_128_enc_witness.json").unwrap(); file.write_all(serde_json::to_string_pretty(&data).unwrap().as_bytes()).unwrap(); - }, - CipherMode::GCM256 => { }, - CipherMode::Ctr128 => { }, - CipherMode::GCM128 => { }, + CipherMode::GCM256 => {}, + CipherMode::Ctr128 => {}, + CipherMode::GCM128 => {}, } Ok(()) diff --git a/src/witness.rs b/src/witness.rs index bc23d21..dbf569e 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -11,7 +11,7 @@ use aes::{ cipher::{BlockEncrypt, InnerIvInit, KeyInit, KeyIvInit, StreamCipher, StreamCipherCore}, - Aes128 + Aes128, }; use aes_gcm::{ aead::{generic_array::GenericArray, Aead, NewAead, Payload}, @@ -95,7 +95,7 @@ pub fn aes_witnesses(cipher_mode: CipherMode) -> Result { let ct = encrypt_tls(MESSAGE.as_bytes(), KEY_ASCII.as_bytes(), IV_ASCII.as_bytes(), 1).unwrap(); println!("ENC: cipher_text={:?}, cipher_len={:?}", hex::encode(ct.clone()), ct.len()); - let key = GenericArray::from(KEY_BYTES_176); + let key = GenericArray::from(KEY_BYTES_156); let key_256 = GenericArray::from(KEY_BYTES_256); let iv = GenericArray::from(IV_BYTES); let mut block = GenericArray::from(MESSAGE_BYTES); @@ -173,7 +173,7 @@ pub fn aes_witnesses(cipher_mode: CipherMode) -> Result { apply_keystream(ctr, &mut buffer); // WORKING! The aes-ctr and aes-gcm now match. - println!("INPUT iv={:?}, key={:?}", hex::encode(IV_BYTES), hex::encode(KEY_BYTES_176)); + println!("INPUT iv={:?}, key={:?}", hex::encode(IV_BYTES), hex::encode(KEY_BYTES_156)); println!( "AES GCM IV={:?}, tm={:?}, ct={:?}", hex::encode(ghash_iv), @@ -184,5 +184,5 @@ pub fn aes_witnesses(cipher_mode: CipherMode) -> Result { println!("AES CTR 256, 96 IV: ct={:?}", hex::encode(block)); println!("AES GCM 256: ct={:?}", hex::encode(ct.clone())); - Ok(Witness::new(&KEY_BYTES_176, &IV_BYTES_SHORT_256, &ct, &ZERO_MESSAGE_BYTES_256)) + Ok(Witness::new(&KEY_BYTES_156, &IV_BYTES_SHORT_256, &ct, &ZERO_MESSAGE_BYTES_256)) }