Skip to content
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

implement polyval #79

Merged
merged 16 commits into from
Sep 20, 2024
Merged
56 changes: 43 additions & 13 deletions circuits/aes-gcm/ghash.circom
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,21 @@ include "nistgmul.circom";
//
// X1 X2 ... XM
// │ │ │
// ▼ ▼
// ┌────────────────┐ ┌──────────┐ ┌──────────┐
// │ multiply by H │ ┌─────▶│ XOR │ ┌─────▶│ XOR │
// └────────┬───────┘ | └────┬─────┘ | └────┬─────┘
// │ │ │ | |
// │ ▼ |
// ┌────────────────┐ | ┌────────────────┐
// │ │ multiply by H │ | │ multiply by H │
// └───────┬────────┘ | └───────┬────────┘
// │ │ │ | |
// ▼ │ ▼ |
// ┌─────────┐ │ ┌─────────┐ | ┌─────────┐
// ▼ ▼
// ┌──────────┐ ┌──────────┐
// ┌─────▶│ XOR │ ┌─────▶│ XOR │
// │ │ └────┬─────┘ └────┬─────┘
// │ │ │ |
// │ ▼
// ┌────────────────┐ │ ┌────────────────┐ ┌────────────────┐
// │ multiply by H │ │ │ multiply by H │ │ multiply by H │
// └────────┬───────┘ │ └───────┬────────┘ └───────┬────────┘
// │ │ │ |
// ▼ │ ▼
// ┌─────────┐ │ ┌─────────┐ ┌─────────┐
// │ TAG1 │ ─────┘ │ TAG2 │ ──────┘ │ TAGM │
// └─────────┘ └─────────┘ └─────────┘
//

template GHASH(NUM_BLOCKS) {
signal input HashKey[16]; // Hash subkey (128 bits)
signal input msg[NUM_BLOCKS][16]; // Input blocks (each 128 bits)
Expand Down Expand Up @@ -74,3 +73,34 @@ template GHASH(NUM_BLOCKS) {
tag <== intermediate[NUM_BLOCKS];

}


// Transform the GHASH hash key to a POLYVAL hash key
// reverse the bits of `in` and multiply `h` by x
//
// h.reverse();
// let mut h_polyval = polyval::mulx(&h);
// let result = GHash(Polyval::new_with_init_block(&h_polyval, init_block));
template TranslateHashkey() {
signal input in[128];
signal output out[128];

// signal mid[128];

// // reverse bytes
// for (i = 0; i < 16; i++) {
// for (j = 0; j < 8; j++){
// var IDX_FROM = 120-i*8+j;
// var IDX_TO = i*8+j;
// mid[IDX_TO] <== in[IDX_FROM];
// }
// }

// component MULX;
// MULX = polyval_GFMULX();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach on the surface seems dramatically more efficient than the one currently used in Waylon's PR, because it only does this GFMULX once at the end.

Would be good to put our heads together and find a potentially combined approach of these code paths that is less constraint consumptive.

// for (i = 0; i < 128; i++){
// MULX.in[i] <== mid[i];
// }

// out <== MULX.out;
// }
11 changes: 11 additions & 0 deletions circuits/aes-gcm/ghash_gfmul.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
pragma circom 2.1.9;
include "polyval_gfmul.circom";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete file, one will be merged with the other PR

include "gfmulx.circom";

template GHASH_GFMUL() {
signal input a[2][64];
signal input b[2][64];
signal output out[2][64];

// TODO(TK 2024-09-18): produce a ghash mul wrapper
}
85 changes: 73 additions & 12 deletions circuits/aes-gcm/helper_functions.circom
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/gates.circom";
include "circomlib/circuits/comparators.circom";

// parse LE bits to int
template ParseLEBytes64() {
signal input in[64];
signal output out;
Expand All @@ -22,6 +23,43 @@ template ParseLEBytes64() {
out <-- temp;
}

// parse BE bits as bytes and log them. Assumes that the number of bytes logged is a multiple of 8.
template ParseAndLogBitsAsBytes(N_BYTES){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

var N_BITS = N_BYTES * 8;
signal input in[N_BITS];
component Parser = ParseBEBitsToBytes(N_BYTES);
for (var i=0; i<N_BITS; i++){
Parser.in[i] <== in[i];
}
for (var i=0; i<N_BYTES / 8; i++){
log("in[", i, "]=",
Parser.out[i*8+0], Parser.out[i*8+1], Parser.out[i*8+2], Parser.out[i*8+3],
Parser.out[i*8+4], Parser.out[i*8+5], Parser.out[i*8+6], Parser.out[i*8+7]
);
}
}

// parse BE bits to bytes.
template ParseBEBitsToBytes(N_BYTES) {
var N_BITS = N_BYTES * 8;
signal input in[N_BITS];
signal output out[N_BYTES];
// var temp[8] = [0,0,0,0,0,0,0,0];

// Iterate through the input bits
var temp[N_BYTES];
for (var i = 0; i < N_BYTES; i++) {
temp[i] = 0;
for (var j = 7; j >= 0; j--) {
temp[i] += 2**j * in[i*8 + 7 - j];
}
}

for (var i=0; i< N_BYTES; i++) {
out[i] <-- temp[i];
}
}

// parse 64-bits to integer value
template ParseBEBytes64() {
signal input in[64];
Expand Down Expand Up @@ -334,18 +372,8 @@ template IndexSelector(total) {
out <== calcTotal.sum;
}

// reverse the order in an n-bit array
template ReverseArray(n) {
signal input in[n];
signal output out[n];

for (var i = 0; i < n; i++) {
out[i] <== in[n-i-1];
}
}

// reverse the byte order in a 16 byte array
template ReverseByteArray() {
template ReverseByteArray128() {
signal input in[128];
signal output out[128];

Expand All @@ -354,4 +382,37 @@ template ReverseByteArray() {
out[j + 8*i] <== in[(15-i)*8 +j];
}
}
}
}
// in a 128-bit array, reverse the byte order in the first 64 bits, and the second 64 bits
template ReverseByteArrayHalves128() {
signal input in[128];
signal output out[128];

for (var i=0; i<8; i++){
for (var j=0; j<8; j++){
var SWAP_IDX = 56-(i*8)+j;
out[i*8+j] <== in[SWAP_IDX];
}
}
for (var i=0; i<8; i++){
for (var j=0; j<8; j++){
var SWAP_IDX = 56-(i*8)+j+64;
out[i*8+j+64] <== in[SWAP_IDX];
}
}
}

// in a 128-bit array, reverse the halves.
template ReverseHalves128() {
signal input in[128];
signal output out[128];

for (var i=0; i<64; i++){
var SWAP_IDX = 64+i;
out[i] <== in[SWAP_IDX];
}
for (var i=64; i<128; i++){
var SWAP_IDX = i-64;
out[i] <== in[SWAP_IDX];
}
}
121 changes: 0 additions & 121 deletions circuits/aes-gcm/mul.circom

This file was deleted.

51 changes: 44 additions & 7 deletions circuits/aes-gcm/polyval.circom
Original file line number Diff line number Diff line change
@@ -1,12 +1,49 @@
template POLYVAL(n_msg_bits)
{
signal input msg[n_msg_bits];
pragma circom 2.1.9;

include "polyval_gfmul.circom";

template POLYVAL(BLOCKS) {
signal input msg[BLOCKS][128];
signal input H[128];
// signal input T[2][64]; // TODO
signal output out[128];

for (var i = 0; i < 128; i++) {
out[i] <== 1;
// LE adjustments: reverse msg and H, store in msg_ and H_
signal H_[128];
signal msg_[BLOCKS][128];
component ReverseByteHalves[BLOCKS+2];
for (var i=0; i<BLOCKS+2; i++){ ReverseByteHalves[i] = ReverseByteArrayHalves128();}
ReverseByteHalves[0].in <-- H; H_ <-- ReverseByteHalves[0].out;
for (var i=2; i<BLOCKS+2; i++){ ReverseByteHalves[i].in <-- msg[i-2]; msg_[i-2] <-- ReverseByteHalves[i].out; }

component XORS[BLOCKS]; component POLYVAL_GFMUL[BLOCKS];
for (var i=0; i<BLOCKS; i++){ XORS[i] = BitwiseXor(128); }
for (var i=0; i<BLOCKS; i++){ POLYVAL_GFMUL[i] = POLYVAL_GFMUL(); }

signal mids[BLOCKS+1][128];
for (var i=0; i<128; i++){ mids[0][i] <-- 0; }

// xor and multiply
for (var block=0; block<BLOCKS; block++){
// xor
XORS[block].a <== mids[block];
XORS[block].b <== msg_[block];

// multiply XORS[block].out * H_
for (var i=0; i<2; i++){ for (var j=0; j<64; j++){
POLYVAL_GFMUL[block].a[i][j] <== XORS[block].out[i*64+j];
POLYVAL_GFMUL[block].b[i][j] <== H_[i*64+j];
} }
for (var i=0; i<2; i++){ for (var j=0; j<64; j++){
mids[block+1][i*64+j] <== POLYVAL_GFMUL[block].out[i][j];
} }
}

}
// need to reverse for BE once more
signal _out[128]; _out <== mids[BLOCKS];
ReverseByteHalves[1].in <== _out;
out <-- ReverseByteHalves[1].out;

// component Logger3 = ParseAndLogBitsAsBytes(16);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

// log("out");
// Logger3.in <== out;
}
Loading