@@ -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
40474160let 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