-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: foldable chacha20 #51
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
pragma circom 2.1.9; | ||
|
||
include "../../circuits/chacha20/chacha20.circom"; | ||
|
||
component main = ChaCha20_NIVC(256); |
This file was deleted.
This file was deleted.
This file was deleted.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't remove this either. |
This file was deleted.
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); |
This file was deleted.
This file was deleted.
This file was deleted.
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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like surely we can do this 32 bit add more efficiently, right? |
||
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; | ||
} |
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; | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment for the future: I think we may be able to byte pack all of this. Expanding 32 field elements for 32 bits is likely not necessary. We can fit that amount of data into 2 field elements! I'm not sure if this would help given we have to do bitwise XOR, but I do think there are probably tricks to do bitwise XOR on bytes or, say, 128bit numbers. Maybe not. Food for thought! This circuit already seems wildly more efficient, so I'm not really worried about it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This also goes for all the chacha circuits we use. |
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 | | ||
// +---+---+---+---+ | ||
// 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; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't remove this please! No harm in keeping it in here for now.