Skip to content

Commit b10421a

Browse files
jakemasclaude
andcommitted
Add per-coefficient bound to SUBROUTINE_CORRECT postcondition
Strengthen the postcondition of MLDSA_REJ_UNIFORM_CORRECT and MLDSA_REJ_UNIFORM_(NOIBT_)SUBROUTINE_CORRECT to include the per-coefficient bound !i. i < outlen ==> val(read(memory :> bytes32 (word_add res (word(4 * i)))) s) < 8380417 matching the CBMC contract ensures(array_bound(buf, 0, len, 0, 8380417)) in arith_native_x86_64.h. Uses the same layering pattern as poly_use_hint_32_aarch64_asm (ENSURES_STRENGTHEN_POST): introduces ENSURES_STRENGTHEN_POST_X86, a memory->list-element bridge VAL_READ_BYTES32_FROM_WORDLIST, and the combinatorial lemma REJ_SAMPLE_COEFF_BOUND, then derives MLDSA_REJ_UNIFORM_CORRECT_BOUND by showing the old num_of_wordlist-based postcondition implies the new per-index bound. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Jake Massimo <jakemas@amazon.com>
1 parent 5f9e38b commit b10421a

1 file changed

Lines changed: 119 additions & 3 deletions

File tree

proofs/hol_light/x86_64/proofs/rej_uniform_avx2_asm.ml

Lines changed: 119 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4003,6 +4003,116 @@ let REJ_SAMPLE_COEFF_BOUND = prove
40034003
ASM_REWRITE_TAC[MEM_APPEND];
40044004
REWRITE_TAC[REJ_SAMPLE; MEM_FILTER] THEN MESON_TAC[]]);;
40054005

4006+
(* Helper: val of a memory-resident 32-bit word = read of its 4 bytes. *)
4007+
let VAL_READ_BYTES32 = prove
4008+
(`!(a:int64) (s:x86state).
4009+
val(read (memory :> bytes32 a) s) = read(memory :> bytes(a,4)) s`,
4010+
REPEAT GEN_TAC THEN
4011+
REWRITE_TAC[bytes32; READ_COMPONENT_COMPOSE; asword; through; read] THEN
4012+
REWRITE_TAC[VAL_WORD; DIMINDEX_32] THEN MATCH_MP_TAC MOD_LT THEN
4013+
MP_TAC (ISPECL [`a:int64`;
4014+
`4:num`;
4015+
`(read (memory:(x86state,int64->byte)component) s):int64->byte`]
4016+
READ_BYTES_BOUND) THEN
4017+
ARITH_TAC);;
4018+
4019+
(* x86 postcondition-strengthening lemma (analogue of aarch64/ENSURES_STRENGTHEN_POST) *)
4020+
let ENSURES_STRENGTHEN_POST_X86 = prove
4021+
(`!P (Q:x86state->bool) Q' R.
4022+
ensures x86 P Q' R /\ (!s. Q' s ==> Q s) ==> ensures x86 P Q R`,
4023+
REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
4024+
REWRITE_TAC[ensures] THEN MATCH_MP_TAC MONO_FORALL THEN
4025+
X_GEN_TAC `s0:x86state` THEN MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
4026+
MP_TAC(BETA_RULE(ISPECL [`x86`;
4027+
`\s':x86state. (Q':x86state->bool) s' /\ (R:x86state->x86state->bool) (s0:x86state) s'`;
4028+
`\s':x86state. (Q:x86state->bool) s' /\ (R:x86state->x86state->bool) (s0:x86state) s'`]
4029+
EVENTUALLY_MONO)) THEN
4030+
ANTS_TAC THENL [ASM_MESON_TAC[]; MESON_TAC[]]);;
4031+
4032+
(* Bridge: when a contiguous memory region equals num_of_wordlist of an *)
4033+
(* int32 list, the i-th 32-bit element read back equals the list's i-th *)
4034+
(* element (as num). *)
4035+
let VAL_READ_BYTES32_FROM_WORDLIST = prove
4036+
(`!(outlist:int32 list) (a:int64) (s:x86state) i.
4037+
i < LENGTH outlist /\
4038+
read(memory :> bytes(a, 4 * LENGTH outlist)) s = num_of_wordlist outlist
4039+
==> val(read(memory :> bytes32(word_add a (word(4 * i)))) s) =
4040+
val(EL i outlist)`,
4041+
REPEAT STRIP_TAC THEN REWRITE_TAC[VAL_READ_BYTES32] THEN
4042+
SUBGOAL_THEN
4043+
`read(memory :> bytes(word_add a (word (4 * i)),4)) s =
4044+
read(memory :> bytes(a:int64,4 * LENGTH(outlist:int32 list))) s
4045+
DIV 2 EXP (8 * (4 * i)) MOD 2 EXP (8 * 4)`
4046+
SUBST1_TAC THENL
4047+
[REWRITE_TAC[READ_COMPONENT_COMPOSE; READ_BYTES_MOD; READ_BYTES_DIV] THEN
4048+
SUBGOAL_THEN `MIN (4 * LENGTH(outlist:int32 list) - 4 * i) 4 = 4`
4049+
SUBST1_TAC THENL
4050+
[UNDISCH_TAC `i < LENGTH(outlist:int32 list)` THEN ARITH_TAC;
4051+
REFL_TAC];
4052+
ASM_REWRITE_TAC[] THEN
4053+
MP_TAC(ISPECL [`outlist:int32 list`; `i:num`]
4054+
(INST_TYPE [`:32`,`:N`] EL_NUM_OF_WORDLIST)) THEN
4055+
ASM_REWRITE_TAC[DIMINDEX_32] THEN DISCH_THEN SUBST1_TAC THEN
4056+
REWRITE_TAC[VAL_WORD; DIMINDEX_32;
4057+
ARITH_RULE `8 * 4 * i = 32 * i`;
4058+
ARITH_RULE `8 * 4 = 32`]]);;
4059+
4060+
(* Strengthened core correctness: adds per-coefficient bound, matching the *)
4061+
(* CBMC contract `ensures(array_bound(buf, 0, len, 0, 8380417))`. *)
4062+
let MLDSA_REJ_UNIFORM_CORRECT_BOUND = prove
4063+
(`!res buf table (inlist:(24 word)list) pc.
4064+
LENGTH inlist = 280 /\
4065+
nonoverlapping (word pc, 243) (res, 1024) /\
4066+
nonoverlapping (word pc, 243) (buf, 840) /\
4067+
nonoverlapping (word pc, 243) (table, 2048) /\
4068+
nonoverlapping (res, 1024) (buf, 840) /\
4069+
nonoverlapping (res, 1024) (table, 2048)
4070+
==> ensures x86
4071+
(\s. bytes_loaded s (word pc) (BUTLAST mldsa_rej_uniform_tmc) /\
4072+
read RIP s = word pc /\
4073+
C_ARGUMENTS [res; buf; table] s /\
4074+
read(memory :> bytes(buf,840)) s = num_of_wordlist inlist /\
4075+
read(memory :> bytes(table,2048)) s =
4076+
num_of_wordlist(mldsa_rej_uniform_table:byte list))
4077+
(\s. read RIP s = word(pc + 242) /\
4078+
let outlist = SUB_LIST(0,256) (REJ_SAMPLE inlist) in
4079+
let outlen = LENGTH outlist in
4080+
C_RETURN s = word outlen /\
4081+
read(memory :> bytes(res,4 * outlen)) s =
4082+
num_of_wordlist outlist /\
4083+
(!i. i < outlen
4084+
==> val(read(memory :> bytes32
4085+
(word_add res (word(4 * i)))) s) < 8380417))
4086+
(MAYCHANGE [RIP; RAX; RCX; R8; R9; R10] ,,
4087+
MAYCHANGE [ZMM0; ZMM1; ZMM2; ZMM3; ZMM4;
4088+
ZMM5; ZMM6; ZMM7; ZMM8; ZMM9; ZMM10; ZMM11;
4089+
ZMM12; ZMM13; ZMM14; ZMM15] ,,
4090+
MAYCHANGE SOME_FLAGS ,, MAYCHANGE [events] ,,
4091+
MAYCHANGE [memory :> bytes(res,1024)])`,
4092+
REPEAT GEN_TAC THEN STRIP_TAC THEN
4093+
MATCH_MP_TAC ENSURES_STRENGTHEN_POST_X86 THEN
4094+
EXISTS_TAC
4095+
`\s:x86state.
4096+
read RIP s = word(pc + 242) /\
4097+
(let outlist = SUB_LIST(0,256) (REJ_SAMPLE (inlist:(24 word)list)) in
4098+
let outlen = LENGTH outlist in
4099+
C_RETURN s = word outlen /\
4100+
read(memory :> bytes(res:int64,4 * outlen)) s =
4101+
num_of_wordlist outlist)` THEN
4102+
CONJ_TAC THENL
4103+
[MATCH_MP_TAC MLDSA_REJ_UNIFORM_CORRECT THEN ASM_REWRITE_TAC[];
4104+
BETA_TAC THEN GEN_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
4105+
STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
4106+
X_GEN_TAC `i:num` THEN DISCH_TAC THEN
4107+
MP_TAC(ISPECL
4108+
[`SUB_LIST(0,256) (REJ_SAMPLE (inlist:(24 word)list))`;
4109+
`res:int64`; `s:x86state`; `i:num`]
4110+
VAL_READ_BYTES32_FROM_WORDLIST) THEN
4111+
ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
4112+
MATCH_MP_TAC REJ_SAMPLE_COEFF_BOUND THEN
4113+
EXISTS_TAC `inlist:(24 word)list` THEN
4114+
MATCH_MP_TAC MEM_EL THEN ASM_REWRITE_TAC[]]);;
4115+
40064116
(* ========================================================================= *)
40074117
(* SUBROUTINE_CORRECT variants (standard x86_64 ABI). *)
40084118
(* *)
@@ -4038,11 +4148,14 @@ let MLDSA_REJ_UNIFORM_NOIBT_SUBROUTINE_CORRECT = prove
40384148
let outlen = LENGTH outlist in
40394149
C_RETURN s = word outlen /\
40404150
read(memory :> bytes(res,4 * outlen)) s =
4041-
num_of_wordlist outlist))
4151+
num_of_wordlist outlist /\
4152+
(!i. i < outlen
4153+
==> val(read(memory :> bytes32
4154+
(word_add res (word(4 * i)))) s) < 8380417)))
40424155
(MAYCHANGE [RSP] ,, MAYCHANGE_REGS_AND_FLAGS_PERMITTED_BY_ABI ,,
40434156
MAYCHANGE [memory :> bytes(res,1024)])`,
40444157
X86_PROMOTE_RETURN_NOSTACK_TAC mldsa_rej_uniform_tmc
4045-
MLDSA_REJ_UNIFORM_CORRECT);;
4158+
MLDSA_REJ_UNIFORM_CORRECT_BOUND);;
40464159

40474160
let MLDSA_REJ_UNIFORM_SUBROUTINE_CORRECT = prove
40484161
(`!res buf table (inlist:(24 word)list) pc stackpointer returnaddress.
@@ -4071,7 +4184,10 @@ let MLDSA_REJ_UNIFORM_SUBROUTINE_CORRECT = prove
40714184
let outlen = LENGTH outlist in
40724185
C_RETURN s = word outlen /\
40734186
read(memory :> bytes(res,4 * outlen)) s =
4074-
num_of_wordlist outlist))
4187+
num_of_wordlist outlist /\
4188+
(!i. i < outlen
4189+
==> val(read(memory :> bytes32
4190+
(word_add res (word(4 * i)))) s) < 8380417)))
40754191
(MAYCHANGE [RSP] ,, MAYCHANGE_REGS_AND_FLAGS_PERMITTED_BY_ABI ,,
40764192
MAYCHANGE [memory :> bytes(res,1024)])`,
40774193
MATCH_ACCEPT_TAC(ADD_IBT_RULE MLDSA_REJ_UNIFORM_NOIBT_SUBROUTINE_CORRECT));;

0 commit comments

Comments
 (0)