Skip to content

Commit

Permalink
feat: chacha20 (#51)
Browse files Browse the repository at this point in the history
* Revert "Revert "Chacha20" (#50)"

This reverts commit 8aa8b08.

* Update circuits/test/chacha20/chacha20-nivc.test.ts

Co-authored-by: Colin Roberts <colin@autoparallel.xyz>

* add back aes artifacts

* put aes back in full test

* artifact path and docs

* refactor tests to be more explicit

---------

Co-authored-by: Colin Roberts <colin@autoparallel.xyz>
  • Loading branch information
0xJepsen and Autoparallel authored Nov 22, 2024
1 parent ed6b61f commit cabfa34
Show file tree
Hide file tree
Showing 21 changed files with 1,087 additions and 69 deletions.
5 changes: 5 additions & 0 deletions builds/target_1024b/chacha20_nivc_1024.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma circom 2.1.9;

include "../../circuits/chacha20/nivc/chacha20_nivc.circom";

component main = ChaCha20_NIVC(256);
6 changes: 0 additions & 6 deletions builds/target_1024b/http_body_mask_1024b.circom

This file was deleted.

5 changes: 0 additions & 5 deletions builds/target_1024b/http_lock_header_1024b.circom

This file was deleted.

This file was deleted.

5 changes: 5 additions & 0 deletions builds/target_512b/chacha20_nivc_512b.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma circom 2.1.9;

include "../../circuits/chacha20/nivc/chacha20_nivc.circom";

component main = ChaCha20_NIVC(128);
6 changes: 0 additions & 6 deletions builds/target_512b/http_body_mask_512b.circom

This file was deleted.

5 changes: 0 additions & 5 deletions builds/target_512b/http_lock_header_512b.circom

This file was deleted.

5 changes: 0 additions & 5 deletions builds/target_512b/http_parse_and_lock_start_line_512b.circom

This file was deleted.

88 changes: 88 additions & 0 deletions circuits/chacha20/chacha-qr.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// initially from https://github.com/reclaimprotocol/zk-symmetric-crypto
// modified for our needs
pragma circom 2.1.9;

include "../utils/generics-bits.circom";

/**
* Perform ChaCha Quarter Round
* Assume 4 words of 32 bits each
* Each word must be little endian
*/
template QR() {
signal input in[4][32];
signal output out[4][32];

var tmp[4][32] = in;

// a += b
component add1 = AddBits(32);
add1.a <== tmp[0];
add1.b <== tmp[1];

tmp[0] = add1.out;

// d ^= a
component xor1 = XorBits(32);
xor1.a <== tmp[3];
xor1.b <== tmp[0];
tmp[3] = xor1.out;

// d = RotateLeft32BitsUnsafe(d, 16)
component rot1 = RotateLeftBits(32, 16);
rot1.in <== tmp[3];
tmp[3] = rot1.out;

// c += d
component add2 = AddBits(32);
add2.a <== tmp[2];
add2.b <== tmp[3];
tmp[2] = add2.out;

// b ^= c
component xor2 = XorBits(32);
xor2.a <== tmp[1];
xor2.b <== tmp[2];
tmp[1] = xor2.out;

// b = RotateLeft32BitsUnsafe(b, 12)
component rot2 = RotateLeftBits(32, 12);
rot2.in <== tmp[1];
tmp[1] = rot2.out;

// a += b
component add3 = AddBits(32);
add3.a <== tmp[0];
add3.b <== tmp[1];
tmp[0] = add3.out;

// d ^= a
component xor3 = XorBits(32);
xor3.a <== tmp[3];
xor3.b <== tmp[0];
tmp[3] = xor3.out;

// d = RotateLeft32BitsUnsafe(d, 8)
component rot3 = RotateLeftBits(32, 8);
rot3.in <== tmp[3];
tmp[3] = rot3.out;

// c += d
component add4 = AddBits(32);
add4.a <== tmp[2];
add4.b <== tmp[3];
tmp[2] = add4.out;

// b ^= c
component xor4 = XorBits(32);
xor4.a <== tmp[1];
xor4.b <== tmp[2];
tmp[1] = xor4.out;

// b = RotateLeft32BitsUnsafe(b, 7)
component rot4 = RotateLeftBits(32, 7);
rot4.in <== tmp[1];
tmp[1] = rot4.out;

out <== tmp;
}
112 changes: 112 additions & 0 deletions circuits/chacha20/chacha-round.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// initially from https://github.com/reclaimprotocol/zk-symmetric-crypto
// modified for our needs
pragma circom 2.1.9;

include "./chacha-qr.circom";
include "../utils/generics-bits.circom";

template Round() {
// in => 16 32-bit words
signal input in[16][32];
// out => 16 32-bit words
signal output out[16][32];

var tmp[16][32] = in;

component rounds[10 * 8];
component finalAdd[16];
// i-th round
var i = 0;
// col loop counter
var j = 0;
// counter for the rounds array
var k = 0;
for(i = 0; i < 10; i++) {
// columns of the matrix in a loop
// 0, 4, 8, 12
// 1, 5, 9, 13
// 2, 6, 10, 14
// 3, 7, 11, 15
for(j = 0; j < 4; j++) {
rounds[k] = QR();
rounds[k].in[0] <== tmp[j];
rounds[k].in[1] <== tmp[j + 4];
rounds[k].in[2] <== tmp[j + 8];
rounds[k].in[3] <== tmp[j + 12];

tmp[j] = rounds[k].out[0];
tmp[j + 4] = rounds[k].out[1];
tmp[j + 8] = rounds[k].out[2];
tmp[j + 12] = rounds[k].out[3];

k ++;
}

// 4 diagnals
// 0, 5, 10, 15
rounds[k] = QR();
rounds[k].in[0] <== tmp[0];
rounds[k].in[1] <== tmp[5];
rounds[k].in[2] <== tmp[10];
rounds[k].in[3] <== tmp[15];

tmp[0] = rounds[k].out[0];
tmp[5] = rounds[k].out[1];
tmp[10] = rounds[k].out[2];
tmp[15] = rounds[k].out[3];

k ++;

// 1, 6, 11, 12
rounds[k] = QR();
rounds[k].in[0] <== tmp[1];
rounds[k].in[1] <== tmp[6];
rounds[k].in[2] <== tmp[11];
rounds[k].in[3] <== tmp[12];

tmp[1] = rounds[k].out[0];
tmp[6] = rounds[k].out[1];
tmp[11] = rounds[k].out[2];
tmp[12] = rounds[k].out[3];

k ++;

// 2, 7, 8, 13
rounds[k] = QR();
rounds[k].in[0] <== tmp[2];
rounds[k].in[1] <== tmp[7];
rounds[k].in[2] <== tmp[8];
rounds[k].in[3] <== tmp[13];

tmp[2] = rounds[k].out[0];
tmp[7] = rounds[k].out[1];
tmp[8] = rounds[k].out[2];
tmp[13] = rounds[k].out[3];

k ++;

// 3, 4, 9, 14
rounds[k] = QR();
rounds[k].in[0] <== tmp[3];
rounds[k].in[1] <== tmp[4];
rounds[k].in[2] <== tmp[9];
rounds[k].in[3] <== tmp[14];

tmp[3] = rounds[k].out[0];
tmp[4] = rounds[k].out[1];
tmp[9] = rounds[k].out[2];
tmp[14] = rounds[k].out[3];

k ++;
}

// add the result to the input
for(i = 0; i < 16; i++) {
finalAdd[i] = AddBits(32);
finalAdd[i].a <== tmp[i];
finalAdd[i].b <== in[i];
tmp[i] = finalAdd[i].out;
}

out <== tmp;
}
108 changes: 108 additions & 0 deletions circuits/chacha20/chacha20.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// initially from https://github.com/reclaimprotocol/zk-symmetric-crypto
// modified for our needs
pragma circom 2.1.9;

include "./chacha-round.circom";
include "./chacha-qr.circom";
include "../utils/generics-bits.circom";

/** ChaCha20 in counter mode */
// Chacha20 opperates a 4x4 matrix of 32-bit words where the first 4 words are constants: C
// and the next 8 words are the 256 bit key: K. The next 2 words are the block counter: #
// and the last 2 words are the nonce: N.
// +---+---+---+---+
// | C | C | C | C |
// +---+---+---+---+
// | K | K | K | K |
// +---+---+---+---+
// | K | K | K | K |
// +---+---+---+---+
// | # | N | N | N |
// +---+---+---+---+
// paramaterized by n which is the number of 32-bit words to encrypt
template ChaCha20(N) {
// key => 8 32-bit words = 32 bytes
signal input key[8][32];
// nonce => 3 32-bit words = 12 bytes
signal input nonce[3][32];
// counter => 32-bit word to apply w nonce
signal input counter[32];

// the below can be both ciphertext or plaintext depending on the direction
// in => N 32-bit words => N 4 byte words
signal input in[N][32];
// out => N 32-bit words => N 4 byte words
signal output out[N][32];

var tmp[16][32] = [
[
// constant 0x61707865
0, 1, 1, 0, 0, 0, 0, 1, 0,
1, 1, 1, 0, 0, 0, 0, 0, 1,
1, 1, 1, 0, 0, 0, 0, 1, 1,
0, 0, 1, 0, 1
],
[
// constant 0x3320646e
0, 0, 1, 1, 0, 0, 1, 1, 0,
0, 1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 1, 0, 0, 0, 1, 1,
0, 1, 1, 1, 0
],
[
// constant 0x79622d32
0, 1, 1, 1, 1, 0, 0, 1, 0,
1, 1, 0, 0, 0, 1, 0, 0, 0,
1, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0
],
[
// constant 0x6b206574
0, 1, 1, 0, 1, 0, 1, 1, 0,
0, 1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 1, 0, 1, 0, 1, 1,
1, 0, 1, 0, 0
],
key[0], key[1], key[2], key[3],
key[4], key[5], key[6], key[7],
counter, nonce[0], nonce[1], nonce[2]
];

// 1 in 32-bit words
signal one[32];
one <== [
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, 1
];

var i = 0;
var j = 0;

// do the ChaCha20 rounds
component rounds[N/16];
component xors[N];
component counter_adder[N/16 - 1];

for(i = 0; i < N/16; i++) {
rounds[i] = Round();
rounds[i].in <== tmp;
// XOR block with input
for(j = 0; j < 16; j++) {
xors[i*16 + j] = XorBits(32);
xors[i*16 + j].a <== in[i*16 + j];
xors[i*16 + j].b <== rounds[i].out[j];
out[i*16 + j] <== xors[i*16 + j].out;
}

if(i < N/16 - 1) {
counter_adder[i] = AddBits(32);
counter_adder[i].a <== tmp[12];
counter_adder[i].b <== one;

// increment the counter
tmp[12] = counter_adder[i].out;
}
}
}
Loading

0 comments on commit cabfa34

Please sign in to comment.