diff --git a/circuits/Nargo.toml b/circuits/Nargo.toml index 5082c6e..473dcc3 100644 --- a/circuits/Nargo.toml +++ b/circuits/Nargo.toml @@ -3,3 +3,4 @@ authors = [""] compiler_version = "0.1" [dependencies] +keccak = { path = "../lib" } diff --git a/circuits/src/main.nr b/circuits/src/main.nr index 1adae7e..8b43a34 100644 --- a/circuits/src/main.nr +++ b/circuits/src/main.nr @@ -1,4 +1,4 @@ -mod padding; +use dep::keccak; global INPUT_SIZE: Field = 10; @@ -7,5 +7,5 @@ global BLOCK_SIZE: Field = 10; // Blocks are 136 bytes. 138 * 8 = 1088 bits. // This is a simplified implementation of the Keccak256 hash function. // In particular we assume that the `input_length` will be less than the size of the absorb step's block size. fn main(input: [u1; INPUT_SIZE], input_length: u64) -> pub [u1; BLOCK_SIZE] { - padding::pad(input, input_length) + dep::keccak::padding::pad(input, input_length) } diff --git a/lib/Nargo.toml b/lib/Nargo.toml new file mode 100644 index 0000000..e0b467c --- /dev/null +++ b/lib/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/lib/src/lib.nr b/lib/src/lib.nr new file mode 100644 index 0000000..a67df03 --- /dev/null +++ b/lib/src/lib.nr @@ -0,0 +1,2 @@ +mod padding; +mod permutations; diff --git a/circuits/src/padding.nr b/lib/src/padding.nr similarity index 100% rename from circuits/src/padding.nr rename to lib/src/padding.nr diff --git a/circuits/src/permutations.nr b/lib/src/permutations.nr similarity index 100% rename from circuits/src/permutations.nr rename to lib/src/permutations.nr diff --git a/circuits/src/permutations/chi.nr b/lib/src/permutations/chi.nr similarity index 100% rename from circuits/src/permutations/chi.nr rename to lib/src/permutations/chi.nr diff --git a/circuits/src/permutations/iota.nr b/lib/src/permutations/iota.nr similarity index 100% rename from circuits/src/permutations/iota.nr rename to lib/src/permutations/iota.nr diff --git a/circuits/src/permutations/rhoPi.nr b/lib/src/permutations/rhoPi.nr similarity index 100% rename from circuits/src/permutations/rhoPi.nr rename to lib/src/permutations/rhoPi.nr diff --git a/circuits/src/permutations/theta.nr b/lib/src/permutations/theta.nr similarity index 100% rename from circuits/src/permutations/theta.nr rename to lib/src/permutations/theta.nr diff --git a/test/inequality.test.ts b/test/inequality.test.ts deleted file mode 100644 index 0533762..0000000 --- a/test/inequality.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { compile } from '@noir-lang/noir_wasm'; -import { - setup_generic_prover_and_verifier, - create_proof, - verify_proof, - StandardExampleProver, - StandardExampleVerifier, -} from '@noir-lang/barretenberg/dest/client_proofs'; -import { resolve } from 'path'; -import { expect } from 'chai'; - -type ProofInput = { - x: number; - y: number; -}; - -describe('Tests using typescript wrapper', function () { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let acir: any; - let prover: StandardExampleProver; - let verifier: StandardExampleVerifier; - - before(async () => { - const compiled_program = compile(resolve(__dirname, '../circuits/src/main.nr')); - acir = compiled_program.circuit; - [prover, verifier] = await setup_generic_prover_and_verifier(acir); - }); - - async function createAndVerifyProof(abi: ProofInput): Promise { - const proof = await create_proof(prover, acir, abi); - - return verify_proof(verifier, proof); - } - - context('when inputs are equal', () => { - it('rejects the proof', async () => { - const abi: ProofInput = { x: 3, y: 3 }; - const verified = await createAndVerifyProof(abi); - - expect(verified).to.be.false; - }); - }); - - context('when inputs are unequal', () => { - it('accepts the proof', async () => { - const abi: ProofInput = { x: 3, y: 4 }; - const verified = await createAndVerifyProof(abi); - - expect(verified).to.be.true; - }); - }); -}); diff --git a/test/padding.test.ts b/test/padding.test.ts new file mode 100644 index 0000000..5b13722 --- /dev/null +++ b/test/padding.test.ts @@ -0,0 +1,91 @@ +import { acir_from_bytes } from '@noir-lang/noir_wasm'; +import { + setup_generic_prover_and_verifier, + create_proof, + verify_proof, + StandardExampleProver, + StandardExampleVerifier, +} from '@noir-lang/barretenberg/dest/client_proofs'; +import { resolve } from 'path'; +import { expect } from 'chai'; +import { readFileSync } from 'fs'; + +const INPUT_SIZE = 10; +const BLOCK_SIZE = 10; + +type ProofInput = { + input: number[]; + input_length: number; + return: number[]; +}; + +describe('pad10*1', function () { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let acir: any; + let prover: StandardExampleProver; + let verifier: StandardExampleVerifier; + + before(async () => { + const acirByteArray = path_to_uint8array(resolve(__dirname, './test-circuits/padding/build/test.acir')); + acir = acir_from_bytes(acirByteArray); + [prover, verifier] = await setup_generic_prover_and_verifier(acir); + }); + + async function createAndVerifyProof(abi: ProofInput): Promise { + const proof = await create_proof(prover, acir, abi); + return verify_proof(verifier, proof); + } + + const padMessage = (input: number[], input_length: number, padded_length: number) => { + if (input.slice(input_length).some((x) => x !== 0)) + throw new Error('input_length greater than actual input length'); + if (input_length > padded_length - 2) throw new Error('input_length greater than max allowed'); + + const paddingArrayLength = padded_length - input_length; + const paddingArray = Array(paddingArrayLength).fill(0); + paddingArray[0] = 1; + paddingArray[paddingArrayLength - 1] = 1; + + const paddedInput = [...input.slice(0, input_length), ...paddingArray]; + + return paddedInput; + }; + + context('when input is longer than reported length', () => { + it('rejects the proof', async () => { + const input_length = 2; + + const input = Array.from({ length: INPUT_SIZE }, () => 0); + + const paddedInput = padMessage(input, input_length, BLOCK_SIZE); + + // We now write a 1 in the position after where the message should end to invalidate it. + input[input_length] = 1; + + const abi: ProofInput = { input, input_length, return: paddedInput }; + const verified = await createAndVerifyProof(abi); + + expect(verified).to.be.false; + }); + }); + + context('when input matches expected input length', () => { + it('pads the input correctly', async () => { + const input_length = 2; + + // const input = Array.from({ length: INPUT_SIZE }, (_, i) => (i < input_length && i % 3 == 0 ? 1 : 0)); + const input = Array(INPUT_SIZE).fill(0); + const paddedInput = padMessage(input, input_length, BLOCK_SIZE); + + const abi: ProofInput = { input, input_length, return: paddedInput }; + const verified = await createAndVerifyProof(abi); + + expect(verified).to.be.true; + }); + }); +}); + +function path_to_uint8array(path: string) { + const buffer = readFileSync(path); + return new Uint8Array(buffer); +} diff --git a/test/test-circuits/padding/Nargo.toml b/test/test-circuits/padding/Nargo.toml new file mode 100644 index 0000000..91a59d5 --- /dev/null +++ b/test/test-circuits/padding/Nargo.toml @@ -0,0 +1,6 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] +keccak = { path = "../../../lib"} diff --git a/test/test-circuits/padding/Prover.toml b/test/test-circuits/padding/Prover.toml new file mode 100644 index 0000000..5a60a4d --- /dev/null +++ b/test/test-circuits/padding/Prover.toml @@ -0,0 +1,3 @@ +input = [] +input_length = "" +return = [] diff --git a/test/test-circuits/padding/src/main.nr b/test/test-circuits/padding/src/main.nr new file mode 100644 index 0000000..a63cd4a --- /dev/null +++ b/test/test-circuits/padding/src/main.nr @@ -0,0 +1,8 @@ +use dep::keccak::padding::pad as pad; + +global INPUT_SIZE: Field = 10; +global BLOCK_SIZE: Field = 10; // Blocks are 136 bytes. 138 * 8 = 1088 bits. + +fn main(input: [u1; INPUT_SIZE], input_length: u64) -> pub [u1; BLOCK_SIZE] { + pad(input, input_length) +}