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

Import AES-CTR32 modules from pnmadelaine_aes branch and add NI proofs #919

Open
wants to merge 26 commits into
base: main
Choose a base branch
from

Conversation

mamonet
Copy link
Member

@mamonet mamonet commented Mar 9, 2024

This PR imports AES-CTR32 modules from pnmadelaine_aes branch and adds proofs for NI functions.

Copy link

github-actions bot commented Mar 9, 2024

[CI] Important!
The code in dist/gcc-compatible, dist/msvc-compatible, and dist/wasm
is tested on cryspen/hacl-packages.
dist is not automatically re-generated, be sure to do it manually.
(A fresh snapshot can also be downloaded from CI by going to the "artifacts" section of your run.)
Then check the following tests before merging this PR.
Always check the latest run, it corresponds to the most recent version of this branch.
All jobs are expected to be successful.
In some cases manual intervention is needed. Please ping the hacl-packages maintainers.

  • Build, Test, Benchmark: Build on Linux (x86, x64), Windows (x86, x64), MacOS (x64, arm64), s390x, Android (arm64) and test on Linux (x86, x64), Windows (x86, x64), MacOS (x64).
  • Performance Regression Tests: Navigate to the terminal output in “Run benchmarks”. The comparison with the main branch will be at the bottom. The run fails if the performance regresses too much.
  • OCaml bindings: Build & Tests
  • JS bindings: Build & Tests
  • Rust bindings: Build & Tests

@mamonet mamonet marked this pull request as ready for review March 16, 2024 17:21
@mamonet mamonet requested a review from a team as a code owner March 16, 2024 17:21
Copy link
Contributor

@msprotz msprotz left a comment

Choose a reason for hiding this comment

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

Can you show us the C code, too?

This is only when the CPU has NI support, correct?

Makefile.common Show resolved Hide resolved
dist/Makefile.tmpl Outdated Show resolved Hide resolved
Copy link
Contributor

@msprotz msprotz left a comment

Choose a reason for hiding this comment

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

Various tidbits to be fixed. I would really like some thorough testing to make sure this is producing the correct results, with a variety of test cases, on arm and x64. The fact that the arguments to the (unverified) macro glue were in the wrong order makes me... slightly nervous

I would also like to see the incremental API being tested out in the C file.

let skey = skey Spec.AES128

[@ CInline ]
val create_ctx: unit ->
Copy link
Contributor

Choose a reason for hiding this comment

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

if this is stackinline, it needs to be marked inline_for_extraction noextract

Copy link
Contributor

Choose a reason for hiding this comment

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

and as a corollary, it can only be used by verified clients; you might want to consider adding a malloc function to allocate a context on the heap

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, I replaced create_ctx with functions that allocate and free buffer on the heap.

Copy link
Contributor

Choose a reason for hiding this comment

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

you'll still need the variant that allocates on the stack when you write aes-gcm and want to allocate aes state on the caller's stack

Copy link
Member Author

Choose a reason for hiding this comment

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

Restored and marked as inline_for_extraction noextract.

Copy link
Contributor

Choose a reason for hiding this comment

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

great, FYI, we've been calling the functions alloca in other modules, so please use that name for consistency

Copy link
Contributor

Choose a reason for hiding this comment

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

(when it allocates state on the stack)

code/aes/Hacl.AES_128.CTR32.NI.fst Outdated Show resolved Hide resolved
code/aes/Hacl.AES_128.CTR32.NI.fst Outdated Show resolved Hide resolved
code/aes/Hacl.AES_128.CTR32.NI.fst Show resolved Hide resolved
code/aes/Hacl.Impl.AES.Core.fst Show resolved Hide resolved
nonce_to_bytes m n == state.block /\
keyx_to_bytes m a kex == state.key_ex)))

let aes_init #m #a ctx key nonce =
Copy link
Contributor

Choose a reason for hiding this comment

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

I take it that a toolchain supports either building both variants, or none at all?

code/aes/Makefile Show resolved Hide resolved
dist/configure Show resolved Hide resolved
st0.block ctr0 msg

let aes_ctr32_decrypt_bytes_LE v key nonce ctr0 msg =
aes_ctr32_encrypt_bytes_LE v key nonce ctr0 msg
Copy link
Contributor

Choose a reason for hiding this comment

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

where is the proof that encrypt (decrypt x) == x?

Copy link
Member Author

Choose a reason for hiding this comment

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

that proof should be applied for aes_ctr32_decrypt_bytes_LE function?

Copy link
Contributor

Choose a reason for hiding this comment

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

yes -- it should be pretty trivial in this case but it's a good "sanity check" to make sure you can prove that?

Copy link
Member Author

Choose a reason for hiding this comment

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

Vale has no such lemma, in fact Vale doesn't have decryption function for AES/GCTR spec. See https://github.com/hacl-star/hacl-star/blob/main/vale/specs/crypto/Vale.AES.AES_s.fst
https://github.com/hacl-star/hacl-star/blob/main/vale/specs/crypto/Vale.AES.GCTR_s.fst
GCM uses the forward version of AES cipher for encryption and decryption, so I think it's good to have aes_ctr32_decrypt unlike Vale but a lemma for encrypt (decrypt x) == x is to verify the spec itself and not the implementation.

tests/aes128-ctr32-ni-test.c Outdated Show resolved Hide resolved
@mamonet
Copy link
Member Author

mamonet commented Apr 17, 2024

The fact that the arguments to the (unverified) macro glue were in the wrong order makes me... slightly nervous

The order of arguments were flipped in the implementation side of F* code, but it doesn't meet the argument order in spec. To make the order consistent, I could either change the order for impl and spec or in libintvector.h I went for the later.

code/aes/.gitignore Outdated Show resolved Hide resolved
code/aes/AUTHORS.md Outdated Show resolved Hide resolved
@franziskuskiefer franziskuskiefer linked an issue Apr 30, 2024 that may be closed by this pull request
2 tasks
@franziskuskiefer franziskuskiefer requested a review from msprotz May 6, 2024 07:52
Copy link
Contributor

@msprotz msprotz left a comment

Choose a reason for hiding this comment

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

Overall this looks good, and I think we're nearly there!

My final requests before we merge this.

  • Please refresh the C code.
  • Please fix the naming convention -- @pnmadelaine spent a great deal of time making sure we have something consistent, so let's keep it neat and tidy.
  • Please write API documentation using CComment syntax (see the bignum files for an example of how to do that, and what would be considered a good style)
  • Please fix any merge conflicts with main so that we can merge this soon.

Congrats on another good PR and looking forward to merging soon.

(BV.logxor_vec (to_vec128 (to_elem x)) (to_vec128 (to_elem y)))
(Seq.append (Seq.append (Seq.append (Seq.append (Seq.append
(Seq.append (Seq.append (Seq.append (Seq.append (Seq.append
(Seq.append (Seq.append (Seq.append (Seq.append (Seq.append
Copy link
Contributor

Choose a reason for hiding this comment

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

would any of these benefit from using FStar.BigOps for readability? this is quite extreme



[@ CInline ]
val aes128_ctr_decrypt:
Copy link
Contributor

Choose a reason for hiding this comment

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

@pnmadelaine can you review this naming convention? I thought with your big PR, we were now trying to avoid redundant prefixes, such as aes128_ or state_

Copy link
Member

Choose a reason for hiding this comment

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

indeed, this should be named ctr_decrypt


#include "libintvector.h"

typedef Lib_IntVector_Intrinsics_vec128 *Hacl_AES_128_CTR32_NI_aes_ctx;
Copy link
Contributor

Choose a reason for hiding this comment

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

I do not see state_malloc?

Copy link
Member Author

Choose a reason for hiding this comment

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

I updated C files in gcc-compatible/
I also renamed state_malloc/free to context_malloc/free


typedef uint8_t *Hacl_AES_256_CTR32_NI_skey;

void
Copy link
Contributor

Choose a reason for hiding this comment

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

same here, where is malloc/free?

Copy link
Member Author

Choose a reason for hiding this comment

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

Likewise.

@franziskuskiefer
Copy link
Member

@msprotz @karthikbhargavan what's the state here?

*/
void
Hacl_AES_128_CTR32_NI_ctr_encrypt(
uint32_t len,
Copy link
Contributor

Choose a reason for hiding this comment

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

please avoid one-letter argument names here

Copy link
Member Author

Choose a reason for hiding this comment

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

Done!

*/
void
Hacl_AES_128_CTR32_NI_ctr_decrypt(
uint32_t len,
Copy link
Contributor

Choose a reason for hiding this comment

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

same

Copy link
Member Author

Choose a reason for hiding this comment

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

Done!

Copy link
Contributor

@msprotz msprotz left a comment

Choose a reason for hiding this comment

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

Good to me once the comments, parameter names, and the little tidbit in the test file are fixed.

I want @pnmadelaine to look closely at the refreshed C header files and confirm whether the naming convention is correct or not. Let's merge only after PNM confirms we're good. Thank you.

Initiate AES-128 context buffer with key expansion and nonce
*/
void
Hacl_AES_128_CTR32_NI_init(Lib_IntVector_Intrinsics_vec128 *ctx, uint8_t *key, uint8_t *nonce);
Copy link
Contributor

Choose a reason for hiding this comment

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

It's good to have a comment, but it's rephrasing what's already visible from the name of the function and the arguments. The questions that should be answered by the comment are:

  • can I call this after encryption?
  • does it reset the state to an initial state? should it be called reset? @pnmadelaine
  • does it reset the nonce to zero?

Copy link
Member Author

Choose a reason for hiding this comment

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

AES-CTR32 API doesn't maintain the state of the counter, that state is supposed to be handled by the caller who is supposed to pass the counter though parameters for Encrypt/Decrypt functions (Proper doc is added to describe that) and this is by design. TBH I don't see what's the point since GCM is the only spec that utilizes this algorithm AES-CTR32, and basically it's implemented after GCM spec.

tests/Makefile Outdated
ifneq ($(COMPILE_AESNI),)
CFLAGS += -DHACL_CAN_COMPILE_AESNI
else
TARGETS := $(filter-out aes128-ctr32-ni-test.exe, $(TARGETS))
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: just put %-ni-test.exe here so that future tests are filtered out too

Copy link
Member Author

Choose a reason for hiding this comment

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

Done!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Merge AES-CTR32 into HACL*
5 participants