diff --git a/circuits/aes-gcm/ghash.circom b/circuits/aes-gcm/ghash.circom index 6b4275d..7be2382 100644 --- a/circuits/aes-gcm/ghash.circom +++ b/circuits/aes-gcm/ghash.circom @@ -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) @@ -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(); +// for (i = 0; i < 128; i++){ +// MULX.in[i] <== mid[i]; +// } + +// out <== MULX.out; +// } diff --git a/circuits/aes-gcm/ghash_gfmul.circom b/circuits/aes-gcm/ghash_gfmul.circom new file mode 100644 index 0000000..8c78ce2 --- /dev/null +++ b/circuits/aes-gcm/ghash_gfmul.circom @@ -0,0 +1,11 @@ +pragma circom 2.1.9; +include "polyval_gfmul.circom"; +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 +} diff --git a/circuits/aes-gcm/helper_functions.circom b/circuits/aes-gcm/helper_functions.circom index 97e6bbb..6cfca08 100644 --- a/circuits/aes-gcm/helper_functions.circom +++ b/circuits/aes-gcm/helper_functions.circom @@ -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; @@ -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){ + var N_BITS = N_BYTES * 8; + signal input in[N_BITS]; + component Parser = ParseBEBitsToBytes(N_BYTES); + for (var i=0; i 1) { - sum[SUM_IDX] -= 2; - sum[SUM_IDX-1] += 1; - } - } - } - - // Perform modular reduction (keep only the lower 64 bits) - for (var i = 0; i < 64; i++) { - out[i] <-- sum[i+1]; - } -} - -// todo: deprecate -template Mul() -{ - signal input src1[64]; - signal input src2[64]; - signal output out[128]; - - var i, j, k; - - var dst_bytes[2][64]; - var src1_bytes[64], src2_bytes[64]; - - for(i=0; i<8; i++) - { - for(j=0; j<8; j++) - { - src1_bytes[i*8+j] = src1[i*8+7-j]; - src2_bytes[i*8+j] = src2[i*8+7-j]; - } - } - - component xor_1[64][2][64]; - - var const_bytes[64]; - for(i=0; i<64; i++) - { - dst_bytes[0][i] = 0; - dst_bytes[1][i] = 0; - const_bytes[i] = 0; - } - const_bytes[63] = 1; - - for(i=0; i<64; i++) - { - var src1_bytes_t[64]; - for(j=0; j<64; j++) - { - src1_bytes_t[j] = src1_bytes[j] * src2_bytes[i]; - xor_1[i][0][j] = XOR(); - - xor_1[i][0][j].a <== dst_bytes[1][j]; - xor_1[i][0][j].b <== src1_bytes_t[j]; - - dst_bytes[1][j] = xor_1[i][0][j].out; - } - for(j=0; j<63; j++) - { - dst_bytes[0][j] = dst_bytes[0][j+1]; - } - dst_bytes[0][63] = 0; - - var const_bytes_t[64]; - for(j=0; j<64; j++) - { - const_bytes_t[j] = const_bytes[j] * dst_bytes[1][0]; - xor_1[i][1][j] = XOR(); - - xor_1[i][1][j].a <== dst_bytes[0][j]; - xor_1[i][1][j].b <== const_bytes_t[j]; - - dst_bytes[0][j] = xor_1[i][1][j].out; - } - for(j=0; j<63; j++) - { - dst_bytes[1][j] = dst_bytes[1][j+1]; - } - dst_bytes[1][63] = 0; - } - - for(i=0; i<2; i++) - { - for(j=0; j<8; j++) - { - for(k=0; k<8; k++) out[i*64+j*8+k] <== dst_bytes[i][j*8+7-k]; - } - } - -} diff --git a/circuits/aes-gcm/polyval.circom b/circuits/aes-gcm/polyval.circom index 1b3ccc0..30c3001 100644 --- a/circuits/aes-gcm/polyval.circom +++ b/circuits/aes-gcm/polyval.circom @@ -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> 1; - // __z1h = rev64(z1h) >> 1; + // __z0h = rev64(_z0h) >> 1; + // __z1h = rev64(_z1h) >> 1; // __z2h = rev64(_z2h) >> 1; signal __zh[3][64]; component Revs_zh[3]; @@ -106,28 +121,33 @@ template MUL() { for (var i = 0; i < 3; i++) { Revs_zh[i] = REV64(); RightShifts_zh[i] = BitwiseRightShift(64, 1); - Revs_zh[i].in <== zh[i]; + Revs_zh[i].in <== _zh[i]; RightShifts_zh[i].in <== Revs_zh[i].out; __zh[i] <== RightShifts_zh[i].out; } - // let v0 = z0; - // let mut v1 = z0h ^ z2; - // let mut v2 = z1 ^ z2h; + // let v0 = _z0; + // let mut v1 = z0h ^ _z2; + // let mut v2 = _z1 ^ z2h; // let mut v3 = z1h; signal v[4][64]; component Xors_v[2]; - v[0] <== z[0]; + v[0] <== _z[0]; Xors_v[0] = BitwiseXor(64); Xors_v[0].a <== __zh[0]; - Xors_v[0].b <== _z2; + Xors_v[0].b <== _z[2]; v[1] <== Xors_v[0].out; Xors_v[1] = BitwiseXor(64); - Xors_v[1].a <== z[1]; + Xors_v[1].a <== _z[1]; Xors_v[1].b <== __zh[2]; v[2] <== Xors_v[1].out; v[3] <== __zh[1]; + // component Loggers_v[4]; + // for (var i=0; i<4; i++) { Loggers_v[i] = ParseAndLogBitsAsBytes(8);} + // log("v0"); Loggers_v[0].in <== v[0]; log("v1"); Loggers_v[1].in <== v[1]; + // log("v2"); Loggers_v[2].in <== v[2]; log("v3"); Loggers_v[3].in <== v[3]; + // _v2 = v2 ^ v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7); // _v1 = v1 ^ (v0 << 63) ^ (v0 << 62) ^ (v0 << 57); signal _v2[64]; @@ -161,6 +181,10 @@ template MUL() { XorMultiples_L[0].inputs <== [v[1], LS_v[0].out, LS_v[1].out, LS_v[2].out]; _v1 <== XorMultiples_L[0].out; + // component Loggers_v2[4]; + // for (var i=0; i<2; i++) { Loggers_v2[i] = ParseAndLogBitsAsBytes(8);} + // log("_v1"); Loggers_v2[0].in <== _v1; log("_v2"); Loggers_v2[1].in <== _v2; + // __v3 = v3 ^ _v1 ^ (_v1 >> 1) ^ (_v1 >> 2) ^ (_v1 >> 7); // __v2 = _v2 ^ (_v1 << 63) ^ (_v1 << 62) ^ (_v1 << 57); signal __v3[64]; @@ -184,6 +208,11 @@ template MUL() { XorMultiples_L[1].inputs <== [_v2, LS_v[3].out, LS_v[4].out, LS_v[5].out]; __v2 <== XorMultiples_L[1].out; + // component Loggers__v[2]; + // for (var i=0; i<2; i++) { Loggers__v[i] = ParseAndLogBitsAsBytes(8);} + // log("__v2"); Loggers__v[0].in <== __v2; + // log("__v3"); Loggers__v[1].in <== __v3; + out <== [__v2, __v3]; } diff --git a/circuits/aes-gcm/wrapping_mul.circom b/circuits/aes-gcm/wrapping_mul.circom new file mode 100644 index 0000000..d9dc8bb --- /dev/null +++ b/circuits/aes-gcm/wrapping_mul.circom @@ -0,0 +1,42 @@ +pragma circom 2.1.9; + +include "helper_functions.circom"; + +// 64-bit BE wrapping multiplication. +// Implements multiplication mod 2^{64}. +template WrappingMul64() { + signal input a[64]; + signal input b[64]; + signal output out[64]; + + // Intermediate signals for partial products + // partial[i,j corresponds to AND(a[i], b[j]) + signal partials[64][64]; + for (var i = 0; i < 64; i++) { + for (var j = 0; j < 64; j++) { + partials[i][j] <== a[i] * b[j]; + } + } + + // 65, not 64, to allow for an extra carry without having to fiddle with overflow + var sum[65]; + for (var i=0; i<65; i++) { sum[i]=0; } + + for (var i = 0; i<64; i++) { + for (var j = 0; i+j<64; j++) { + var SUM_IDX = 64-i-j; + sum[SUM_IDX] += partials[63-i][63-j]; + + // covers the case that sum[i+j]=3 or more, due to prior carries + while (sum[SUM_IDX] > 1) { + sum[SUM_IDX] -= 2; + sum[SUM_IDX-1] += 1; + } + } + } + + // Perform modular reduction (keep only the lower 64 bits) + for (var i = 0; i < 64; i++) { + out[i] <-- sum[i+1]; + } +} diff --git a/circuits/test/bitreversal.test.ts b/circuits/test/bitreversal.test.ts deleted file mode 100644 index 5fd7df6..0000000 --- a/circuits/test/bitreversal.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { assert } from "chai"; -import { WitnessTester } from "circomkit"; -import { circomkit } from "./common"; - -describe("bitreversal", () => { - let circuit: WitnessTester<["in"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`bitreversal`, { - file: "aes-gcm/helper_functions", - template: "ReverseBitsArray", - params: [8], - }); - }); - - let bit_array = [1,0,0,0,0,0,0,0]; - let expected_output = [0,0,0,0,0,0,0,1].map((x) => BigInt(x)); - it("should have correct output", async () => { - const witness = await circuit.compute({ in: bit_array }, ["out"]) - - assert.deepEqual(witness.out, expected_output) - }); - -}); \ No newline at end of file diff --git a/circuits/test/common/index.ts b/circuits/test/common/index.ts index 3a09508..3be5ea8 100644 --- a/circuits/test/common/index.ts +++ b/circuits/test/common/index.ts @@ -15,8 +15,8 @@ export function hexToBytes(hex: any) { export function hexBytesToBigInt(hexBytes: number[]): any[] { return hexBytes.map(byte => { - let n = BigInt(byte); - return n; + let n = BigInt(byte); + return n; }); } diff --git a/circuits/test/ghash_gfmul.test.ts b/circuits/test/ghash_gfmul.test.ts new file mode 100644 index 0000000..1463460 --- /dev/null +++ b/circuits/test/ghash_gfmul.test.ts @@ -0,0 +1,38 @@ +import { WitnessTester } from "circomkit"; +import { bitArrayToHex, circomkit, hexToBitArray } from "./common"; +import { assert } from "chai"; + +// https://datatracker.ietf.org/doc/html/rfc8452#appendix-A +const H = hexToBitArray("25629347589242761d31f826ba4b757b"); +const X1 = "4f4f95668c83dfb6401762bb2d01a262"; +const X2 = "d1a24ddd2721d006bbe45f20d3c9f362"; +const M = hexToBitArray(X1.concat(X2)); +const EXPECT = hexToBitArray("bd9b3997046731fb96251b91f9c99d7a"); + +describe("GHASH_GFMUL", () => { + let circuit: WitnessTester<["a", "b"], ["out"]>; + + before(async () => { + circuit = await circomkit.WitnessTester(`gfmul`, { + file: "aes-gcm/ghash_gfmul", + template: "GHASH_GFMUL", + }); + }); + + // these test vectors are from rust-crypto + // to reproduce run `cargo test ghash -- --nocapture` + // let hash_key = [0xaa, 0xe0, 0x69, 0x92, 0xac, 0xbf, 0x52, 0xa3, 0xe8, 0xf4, 0xa9, 0x6e, 0xc9, 0x30, 0x0b, 0xd7]; + // let ct = [0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41, 0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00]; + // let expected = [0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab,0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb]; + let lower_h = hexToBitArray("0xaae06992acbf52a3"); // little endian hex vectors + let upper_h = hexToBitArray("0xe8f4a96ec9300bd7"); + + let lower_x = hexToBitArray("0x98e7247c07f0fe41"); + let upper_x = hexToBitArray("0x1c267e4384b0f600"); + + + it("test gmul", async () => { + const input = { a: H, b: M }; + const _res = await circuit.expectPass(input, { out: EXPECT }); + }); +}); diff --git a/circuits/test/hashes/ghash.test.ts b/circuits/test/hashes/ghash.test.ts index 78fa45a..eb29984 100644 --- a/circuits/test/hashes/ghash.test.ts +++ b/circuits/test/hashes/ghash.test.ts @@ -4,7 +4,7 @@ import { assert } from "chai"; -describe("ghash-hash", () => { +describe("GHASH_HASH", () => { let circuit: WitnessTester<["HashKey", "msg"], ["tag"]>; before(async () => { @@ -27,24 +27,29 @@ describe("ghash-hash", () => { }); }); -describe("reverse_byte_array", () => { - let circuit: WitnessTester<["in"], ["out"]>; +describe("TranslateHashkey", () => { + let circuit: WitnessTester<["inp"], ["out"]>; before(async () => { circuit = await circomkit.WitnessTester(`ghash`, { - file: "aes-gcm/helper_functions", - template: "ReverseByteArray", + file: "aes-gcm/ghash", + template: "TranslateHashkey", }); + // console.log("#constraints:", await circuit.getConstraintCount()); }); - it("test reverse_byte_array", async () => { - let bits = hexToBitArray("0102030405060708091011121314151f"); - let expect = "1f151413121110090807060504030201"; - const _res = await circuit.compute({ in: bits }, ["out"]); - const result = bitArrayToHex( - (_res.out as number[]).map((bit) => Number(bit)) - ); - // console.log("expect: ", expect, "\nresult: ", result); - assert.equal(expect, result); + // initial hashkey: [37, 98, 147, 71, 88, 146, 66, 118, 29, 49, 248, 38, 186, 75, 117, 123] + //25629347589242761D31F826BA4B757B + // reversed hashkey: [123, 117, 75, 186, 38, 248, 49, 29, 118, 66, 146, 88, 71, 147, 98, 37] + //7B754BBA26F8311D7642925847936225 + // post-mul_x hashkey: [246, 234, 150, 116, 77, 240, 99, 58, 236, 132, 36, 177, 142, 38, 197, 74] + //F6EA96744DF0633AEC8424B18E26C54A + it("test TranslateHashkey", async () => { + const inp = hexToBitArray("25629347589242761d31f826ba4b757b"); + const out = hexToBitArray("F6EA96744DF0633AEC8424B18E26C54A"); + const _res = await circuit.expectPass({ inp: inp }, { out }); }); }); + + + diff --git a/circuits/test/hashes/polyval.test.ts b/circuits/test/hashes/polyval.test.ts index 8ada108..a6ea8f9 100644 --- a/circuits/test/hashes/polyval.test.ts +++ b/circuits/test/hashes/polyval.test.ts @@ -8,32 +8,53 @@ const X1 = "4f4f95668c83dfb6401762bb2d01a262"; const X2 = "d1a24ddd2721d006bbe45f20d3c9f362"; const M = hexToBitArray(X1.concat(X2)); const EXPECT = "f7a3b47b846119fae5b7866cf5e5b77e"; +// generated with rust-crypto +const EXPECT_2 = "cedac64537ff50989c16011551086d77"; -describe("polyval", () => { +describe("POLYVAL_HASH_1", () => { let circuit: WitnessTester<["msg", "H"], ["out"]>; before(async () => { circuit = await circomkit.WitnessTester(`polyval`, { file: "aes-gcm/polyval", template: "POLYVAL", - params: [128 * 2], + params: [2], }); - console.log("#constraints:", await circuit.getConstraintCount()); + // console.log("#constraints:", await circuit.getConstraintCount()); }); - it("should have correct number of constraints", async () => { - await circuit.expectConstraintCount(74754, true); - }); - - it("todo name polyval", async () => { + it("POLYVAL 1", async () => { const input = { msg: M, H: H }; const _res = await circuit.compute(input, ["out"]); - // TODO(TK 2024-08-15): bug, result returns 256 bits - // take the first 32 bytes const result = bitArrayToHex( - (_res.out as number[]).map((bit) => Number(bit)) - ).slice(0, 32); + (_res.out as number[][])[0].map((bit) => Number(bit)) + ) console.log("expect: ", EXPECT, "\nresult: ", result); assert.equal(result, EXPECT); }); -}); \ No newline at end of file +}); + +describe("POLYVAL_HASH_2", () => { + let circuit: WitnessTester<["msg", "H"], ["out"]>; + + before(async () => { + circuit = await circomkit.WitnessTester(`polyval`, { + file: "aes-gcm/polyval", + template: "POLYVAL", + params: [1], + }); + // console.log("#constraints:", await circuit.getConstraintCount()); + }); + + it("POLYVAL 2", async () => { + const M = hexToBitArray(X1); + const input = { msg: M, H: H }; + const _res = await circuit.compute(input, ["out"]); + // console.log(bitArrayToHex((_res.out as number[][])[0])); + const result = bitArrayToHex( + (_res.out as number[][])[0].map((bit) => Number(bit)) + ); + console.log("expect: ", EXPECT_2, "\nresult: ", result); + assert.equal(result, EXPECT_2); + }); +}); diff --git a/circuits/test/helper_functions.test.ts b/circuits/test/helper_functions.test.ts new file mode 100644 index 0000000..3db52aa --- /dev/null +++ b/circuits/test/helper_functions.test.ts @@ -0,0 +1,26 @@ +import { WitnessTester } from "circomkit"; +import { bitArrayToHex, circomkit, hexToBitArray } from "./common"; +import { assert } from "chai"; + +describe("reverse_byte_array", () => { + let circuit: WitnessTester<["in"], ["out"]>; + + before(async () => { + circuit = await circomkit.WitnessTester(`reverse_bytes`, { + file: "aes-gcm/helper_functions", + template: "ReverseByteArray", + }); + }); + + it("test reverse_byte_array", async () => { + let bits = hexToBitArray("0102030405060708091011121314151f"); + let expect = "1f151413121110090807060504030201"; + const _res = await circuit.compute({ in: bits }, ["out"]); + const result = bitArrayToHex( + (_res.out as number[]).map((bit) => Number(bit)) + ); + // console.log("expect: ", expect, "\nresult: ", result); + assert.equal(expect, result); + }); +}); + diff --git a/circuits/test/gfmul.test.ts b/circuits/test/polyval_gfmul.test.ts similarity index 81% rename from circuits/test/gfmul.test.ts rename to circuits/test/polyval_gfmul.test.ts index 6ccf9ea..cffb48e 100644 --- a/circuits/test/gfmul.test.ts +++ b/circuits/test/polyval_gfmul.test.ts @@ -6,17 +6,61 @@ const ZERO = hexToBitArray("0x000000000000000"); const BE_ONE = hexToBitArray("0x0000000000000001"); const MAX = hexToBitArray("0xFFFFFFFFFFFFFFFF"); -describe("BMUL64", () => { + +describe("POLYVAL GF_MUL", () => { + let circuit: WitnessTester<["a", "b"], ["out"]>; + + before(async () => { + circuit = await circomkit.WitnessTester(`POLYVAL_GFMUL`, { + file: "aes-gcm/polyval_gfmul", + template: "POLYVAL_GFMUL", + }); + }); + + it("POLYVAL_GF_MUL 0", async () => { + await circuit.expectPass({ a: [MAX, MAX], b: [ZERO, ZERO] }, { out: [ZERO, ZERO] }); + }); + + it("POLYVAL_GF_MUL 1", async () => { + await circuit.expectPass({ a: [ZERO, BE_ONE], b: [ZERO, BE_ONE] }, { out: [BE_ONE, ZERO] }); + }); + + it("POLYVAL_GF_MUL 2", async () => { + const E1 = hexToBitArray("C200000000000000"); + const E2 = hexToBitArray("0000000000000001"); + await circuit.expectPass({ a: [ZERO, BE_ONE], b: [BE_ONE, ZERO] }, { out: [E1, E2] }); + }); + + it("POLYVAL_GF_MUL 3", async () => { + const E1 = hexToBitArray("0x00000000006F2B00"); + await circuit.expectPass({ a: [ZERO, hexToBitArray("0x00000000000000F1")], b: [ZERO, hexToBitArray("0x000000000000BB00")] }, { out: [E1, ZERO] }); + }); + + it("POLYVAL_GF_MUL 4", async () => { + const E1 = hexToBitArray("0x000000000043AA16"); + const f1 = hexToBitArray("0x00000000000000F1"); + const bb = hexToBitArray("0x000000000000BB00"); + await circuit.expectPass({ a: [bb, ZERO], b: [ZERO, f1] }, { out: [ZERO, E1] }); + }); + + it("POLYVAL_GF_MUL 5", async () => { + const fives = hexToBitArray("0x5555555555555555"); + const rest = hexToBitArray("0x7A01555555555555"); + await circuit.expectPass({ a: [MAX, MAX], b: [MAX, MAX] }, { out: [fives, rest] }); + }); +}); + +describe("POLYVAL BMUL64", () => { let circuit: WitnessTester<["x", "y"], ["out"]>; before(async () => { circuit = await circomkit.WitnessTester(`BMUL64`, { - file: "aes-gcm/gfmul", + file: "aes-gcm/polyval_gfmul", template: "BMUL64", }); }); - it("bmul64 multiplies 1", async () => { + it("POLYVAL_bmul64 multiplies 1", async () => { const expected = "0000000000000001"; const _res = await circuit.compute({ x: BE_ONE, y: BE_ONE }, ["out"]); const result = bitArrayToHex( @@ -26,7 +70,7 @@ describe("BMUL64", () => { assert.equal(result, expected, "parse incorrect"); }); - it("bmul64 multiplies 0", async () => { + it("POLYVAL_bmul64 multiplies 0", async () => { const expected = "0000000000000000"; const _res = await circuit.compute({ x: ZERO, y: MAX }, ["out"]); const result = bitArrayToHex( @@ -36,7 +80,7 @@ describe("BMUL64", () => { assert.equal(result, expected, "parse incorrect"); }); - it("bmul64 multiplies large number", async () => { + it("POLYVAL_bmul64 multiplies large number", async () => { const X = hexToBitArray("0x1111111111111111"); const Y = hexToBitArray("0x1111111111111111"); const expected = "0101010101010101"; @@ -48,7 +92,7 @@ describe("BMUL64", () => { assert.equal(result, expected, "parse incorrect"); }); - it("bmul64 multiplies large number 2", async () => { + it("POLYVAL_bmul64 multiplies large number 2", async () => { const X = hexToBitArray("0x1111222211118888"); const Y = hexToBitArray("0x1111222211118888"); const expected = "0101010140404040"; @@ -60,7 +104,7 @@ describe("BMUL64", () => { assert.equal(result, expected, "parse incorrect"); }); - it("bmul64 multiplies large number 3", async () => { + it("POLYVAL_bmul64 multiplies large number 3", async () => { const X = hexToBitArray("0xCFAF222D1A198287"); const Y = hexToBitArray("0xFBFF2C2218118182"); const expected = "40468c9202c4418e"; @@ -72,46 +116,3 @@ describe("BMUL64", () => { assert.equal(result, expected, "parse incorrect"); }); }); - -describe("GF_MUL", () => { - let circuit: WitnessTester<["a", "b"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`MUL`, { - file: "aes-gcm/gfmul", - template: "MUL", - }); - }); - - it("GF_MUL 0", async () => { - await circuit.expectPass({ a: [MAX, MAX], b: [ZERO, ZERO] }, { out: [ZERO, ZERO] }); - }); - - it("GF_MUL 1", async () => { - await circuit.expectPass({ a: [ZERO, BE_ONE], b: [ZERO, BE_ONE] }, { out: [BE_ONE, ZERO] }); - }); - - it("GF_MUL 2", async () => { - const E1 = hexToBitArray("C200000000000000"); - const E2 = hexToBitArray("0000000000000001"); - await circuit.expectPass({ a: [ZERO, BE_ONE], b: [BE_ONE, ZERO] }, { out: [E1, E2] }); - }); - - it("GF_MUL 3", async () => { - const E1 = hexToBitArray("0x00000000006F2B00"); - await circuit.expectPass({ a: [ZERO, hexToBitArray("0x00000000000000F1")], b: [ZERO, hexToBitArray("0x000000000000BB00")] }, { out: [E1, ZERO] }); - }); - - it("GF_MUL 4", async () => { - const E1 = hexToBitArray("0x000000000043AA16"); - const f1 = hexToBitArray("0x00000000000000F1"); - const bb = hexToBitArray("0x000000000000BB00"); - await circuit.expectPass({ a: [bb, ZERO], b: [ZERO, f1] }, { out: [ZERO, E1] }); - }); - - it("GF_MUL 5", async () => { - const fives = hexToBitArray("0x5555555555555555"); - const rest = hexToBitArray("0x7A01555555555555"); - await circuit.expectPass({ a: [MAX, MAX], b: [MAX, MAX] }, { out: [fives, rest] }); - }); -}); diff --git a/circuits/test/wrapping_mul.test.ts b/circuits/test/wrapping_mul.test.ts index 9f0f42a..bdedd3e 100644 --- a/circuits/test/wrapping_mul.test.ts +++ b/circuits/test/wrapping_mul.test.ts @@ -7,7 +7,7 @@ describe("WRAPPING_BE", () => { before(async () => { circuit = await circomkit.WitnessTester(`WrappingMul64`, { - file: "aes-gcm/mul", + file: "aes-gcm/wrapping_mul", template: "WrappingMul64", }); }); diff --git a/src/main.rs b/src/main.rs index e275930..3f6c6d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -107,34 +107,34 @@ mod tests { }; use hex_literal::hex; - // first bit is 1 - const H: [u8; 16] = hex!("80000000000000000000000000000000"); - const X: [u8; 16] = hex!("80000000000000000000000000000000"); + const H: [u8; 16] = hex!("aae06992acbf52a3e8f4a96ec9300bd7"); + const X_1: [u8; 16] = hex!("98e7247c07f0fe411c267e4384b0f600"); let mut ghash = GHash::new(&H.into()); - ghash.update(&[X.into()]); + ghash.update(&[X_1.into()]); let result = ghash.finalize(); - // last bit is 1 - const H_1: [u8; 16] = hex!("00000000000000000000000000000001"); - const X_1: [u8; 16] = hex!("00000000000000000000000000000001"); + let hash_key = [ + 0xaa, 0xe0, 0x69, 0x92, 0xac, 0xbf, 0x52, 0xa3, 0xe8, 0xf4, 0xa9, 0x6e, 0xc9, 0x30, + 0x0b, 0xd7, + ]; + let ct = [ + 0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41, 0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, + 0xf6, 0x00, + ]; + let expected = [ + 0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab, 0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, + 0xf0, 0xfb, + ]; - let mut ghash2 = GHash::new(&H_1.into()); - ghash2.update(&[X_1.into()]); + // Alternative. + let mut ghash2 = GHash::new_with_init_block(&hash_key.into(), 0); + let ga_data = GenericArray::from_slice(&ct); + ghash2.update(&[*ga_data]); let result2 = ghash2.finalize(); - // test vector of pain - const H_2: [u8; 16] = hex!("aae06992acbf52a3e8f4a96ec9300bd7"); - const X_2: [u8; 16] = hex!("98e7247c07f0fe411c267e4384b0f600"); - - let mut ghash3 = GHash::new(&H_2.into()); - ghash3.update(&[X_2.into()]); - let result3 = ghash3.finalize(); - - println!("GHASH Test vector 1: {:?}", hex::encode(result.as_slice())); - println!("GHASH Test vector 2: {:?}", hex::encode(result2.as_slice())); - println!("GHASH Test vector 3: {:?}", hex::encode(result3.as_slice())); - - // println!("expected: {:?}", hex::encode(expected)); + println!("GHASH NEW result: {:?}", hex::encode(result.as_slice())); + println!("GHASH OLD result: {:?}", hex::encode(result2.as_slice())); + println!("expected: {:?}", hex::encode(expected)); } }