diff --git a/noir-projects/aztec-nr/aztec/src/oracle/encryption.nr b/noir-projects/aztec-nr/aztec/src/oracle/encryption.nr index cb655c756ce..c8084432437 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/encryption.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/encryption.nr @@ -1,7 +1,9 @@ #[oracle(aes128Encrypt)] -pub fn aes128_encrypt_oracle(input: [u8; N], iv: [u8; 16], key: [u8; 16]) -> [u8; N] {} +pub fn aes128_encrypt_oracle(input: [u8; N], iv: [u8; 16], key: [u8; 16]) -> [u8; M] {} -unconstrained pub fn aes128_encrypt(input: [u8; N], iv: [u8; 16], key: [u8; 16]) -> [u8; N] { +// AES 128 CBC with PKCS7 is padding to multiples of 16 bytes so M has to be a multiple of 16! +// (e.g. from 65 bytes long input you get 80 bytes long output and M has to be set to `80`) +unconstrained pub fn aes128_encrypt(input: [u8; N], iv: [u8; 16], key: [u8; 16]) -> [u8; M] { aes128_encrypt_oracle(input, iv, key) } diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index 107df25dc72..1c14b54c96a 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -310,9 +310,13 @@ contract Test { } #[aztec(private)] - fn encrypt(input: [u8; 64], iv: [u8; 16], key: [u8; 16]) { - let result = aes128_encrypt(input, iv, key); - context.emit_unencrypted_log(result); + fn encrypt(input: [u8; 64], iv: [u8; 16], key: [u8; 16]) -> [u8; 64] { + aes128_encrypt(input, iv, key) + } + + #[aztec(private)] + fn encrypt_with_padding(input: [u8; 65], iv: [u8; 16], key: [u8; 16]) -> [u8; 80] { + aes128_encrypt(input, iv, key) } #[aztec(public)] diff --git a/yarn-project/end-to-end/src/e2e_encryption.test.ts b/yarn-project/end-to-end/src/e2e_encryption.test.ts index 861a7c573c3..9206c566aea 100644 --- a/yarn-project/end-to-end/src/e2e_encryption.test.ts +++ b/yarn-project/end-to-end/src/e2e_encryption.test.ts @@ -21,21 +21,35 @@ describe('e2e_encryption', () => { afterAll(() => teardown()); - it('encrypts', async () => { + it('encrypts 🔒📄🔑💻', async () => { const input = randomBytes(64); const iv = randomBytes(16); const key = randomBytes(16); const expectedCiphertext = aes128.encryptBufferCBC(input, iv, key); - const logs = await contract.methods + const ciphertextAsBigInts = await contract.methods .encrypt(Array.from(input), Array.from(iv), Array.from(key)) - .send() - .getUnencryptedLogs(); - // Each byte of encrypted data is in its own field and it's all serialized into a long buffer so we simply extract - // each 32nd byte from the buffer to get the encrypted data - const recoveredCiphertext = logs.logs[0].log.data.filter((_, i) => (i + 1) % 32 === 0); + .simulate(); + const ciphertext = Buffer.from(ciphertextAsBigInts.map((x: bigint) => Number(x))); - expect(recoveredCiphertext).toEqual(expectedCiphertext); + expect(ciphertext).toEqual(expectedCiphertext); + }); + + it('encrypts with padding 🔒📄🔑💻 ➕ 📦', async () => { + const input = randomBytes(65); + const iv = randomBytes(16); + const key = randomBytes(16); + + const expectedCiphertext = aes128.encryptBufferCBC(input, iv, key); + // AES 128 CBC with PKCS7 is padding to multiples of 16 bytes so from 65 bytes long input we get 80 bytes long output + expect(expectedCiphertext.length).toBe(80); + + const ciphertextAsBigInts = await contract.methods + .encrypt_with_padding(Array.from(input), Array.from(iv), Array.from(key)) + .simulate(); + const ciphertext = Buffer.from(ciphertextAsBigInts.map((x: bigint) => Number(x))); + + expect(ciphertext).toEqual(expectedCiphertext); }); });