Repository navigation
AArch64 RSA: vg_rsa_check_crt_key, and PrivateKey::from_crt checks keys with it (11–22× faster loading) - #1403
Merged
Merged
Conversation
…ys with it `vg_rsa_check_key`'s code without the checks of `d`, with each remainder started from the product's words above its low `c` and run for `64 c` steps of bit-serial division (`c = 1` for `e dX`, `⌈q_len / 8⌉` for `q qInv`) rather than `64 W`. Proven against `Spec.Rsa.checkCrtKeyContract`. `from_crt` now checks the CRT values with it on both architectures, as x86-64 did; the AArch64-only check by a private-key operation on 0 is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PqW9NMssoiBx9i4PpksckL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This change comes from the rustls provider analysis in #991. It does on AArch64 what #1355 did on x86-64:
rsa::PrivateKey::from_crtchecks the key's CRT values withvg_rsa_check_crt_keyinstead of a private-key operation on 0.Guarantee, before and after
Before (AArch64):
from_crtran the constant-time private-key operation on 0. That checks:p q = nandqInv < p(the operation's own preconditions);e.It accepted keys whose
dP,dQorqInvdo not match: those failed later, at everyprivate_op, withError::Fault.After:
from_crtaccepts a key exactly whenSpec.Rsa.checkCrtKeydoes, as on x86-64. That is BoringSSL'sRSA_check_keyon(n, e, p, q, dP, dQ, qInv):p q = n;dP < p - 1ande dP ≡ 1 (mod p - 1);dQ < q - 1ande dQ ≡ 1 (mod q - 1);qInv < pandq qInv ≡ 1 (mod p).This implies what
private_opneeds (a valid modulus,p q = n,qInv < p).private_opkeeps its own check of each result againste.The Rust code no longer differs by architecture: the
#[cfg]split inprivatekey.rsand in the tests (rsa_guidance,wycheproof/rsa_keys,private_invalid,private_from_primes) is gone.The code
Impl/Rsa/AArch64/CheckCrtKey.leanisvg_rsa_check_key's code without the checks ofd, in its layout:pind's header slots too, so the proofs reuseCkIn,CkSand the phases ofvg_rsa_check_keywithpasd.eandnare checked first; those are the only branches on the key.Each remainder (
e dP mod (p - 1),e dQ mod (q - 1),q qInv mod p) is shorter thanvg_rsa_check_key'sdivmod, which runs64 Wsteps of bit-serial division over the layout'sW = 2 w + 2words.reduceTopinstead:c;cwords at the top of the quotient's register;64 csteps.Here
c = 1fore dX(e < 2^64) andc = ⌈q_len / 8⌉forq qInv. When the comparison before each remainder holds, the words fromcup are below the divisor, so the result is the full remainder (divIter_top,Proof/Rsa/KeyMath.lean). When it fails, the mask is already clear.Proofs
Proof/Rsa/KeyMath.lean:divIter_from,divIter_top(restoring division from a partial remainder).Proof/Rsa/AArch64/CrtKeyTop.lean:reduceTop_ok, throughblkHi_ok,blkLo_ok,blkCnt_okandstepsTop_ok.CrtKeyPhase.lean:ckReduceTop_ok,topE_ok,topQ_ok,ckModOneTop_ok,phModC_ok,phQIC_ok.CrtKeyMain.lean:ckcMain_ok; the mask iscrtKeyValid(ckc_final).CrtKeyCode.lean:ckcA, the shared contract on the registers and the stack, andckcCode_correct.CrtKeyCT.lean,CrtKeyCTCode.lean: constant time. EachreduceTopblock readswandcfrom the header; its output registers are pinned to the public data by the lemmas above.CrtKeyVerified.lean:ckc_implies,ckc_verified.Artifacts/Rsa/AArch64.lean: thecheckCrtKeyApiartifact.No change to
Spec/orTCB/(the spec is #1343's).Benchmark
bench.ymlon AArch64 (Neoverse N2, CPU part0xd49),base_commit= main, rsa module:rsa_from_crt/256rsa_from_crt/384rsa_from_crt/512rsa_from_primes/256rsa_from_primes/512rsa_from_components/256Every other RSA benchmark is within ±0.1%.
from_crtis now 1.1–1.2× of aws-lc-rs's key loading, which also checks the key.Checks run locally:
lake buildandEmit.lean;check_lean_imports,check_lean_speed,check_vectors,check_arch_gates,check_variants,check_mcdt,algorithms_table;cargo fmt, andclippy -D warningsfor x86-64 and--target aarch64-unknown-linux-gnu;This machine can't run AArch64 code, so CI runs the AArch64 tests. Running the code through the Lean model's interpreter caught one bug before the proofs reached it:
headinCheckCrtKeyresolved to the enclosing namespace'shead, which doesn't set the mask. The code now namesCheckKey.head.🤖 Generated with Claude Code
https://claude.ai/code/session_01PqW9NMssoiBx9i4PpksckL
Generated by Claude Code