@@ -323,18 +323,6 @@ fn ntt_at_layer_2(re: &mut [Coefficients; SIMD_UNITS_IN_RING_ELEMENT]) {
323
323
}
324
324
325
325
#[ inline( always) ]
326
- #[ hax_lib:: fstar:: before(
327
- r#"
328
- let layer_bound_factor (step_by:usize) : n:nat{n <= 4} =
329
- match step_by with
330
- | MkInt 1 -> 4
331
- | MkInt 2 -> 3
332
- | MkInt 4 -> 2
333
- | MkInt 8 -> 1
334
- | MkInt 16 -> 0
335
- | _ -> 0
336
- "#
337
- ) ]
338
326
#[ hax_lib:: fstar:: options( "--z3rlimit 600 --split_queries always" ) ]
339
327
#[ hax_lib:: fstar:: before( r#"[@@ "opaque_to_smt"]"# ) ]
340
328
#[ hax_lib:: requires( fstar!( r#"
@@ -357,6 +345,61 @@ let layer_bound_factor (step_by:usize) : n:nat{n <= 4} =
357
345
fn outer_3_plus < const OFFSET : usize , const STEP_BY : usize , const ZETA : i32 > (
358
346
re : & mut [ Coefficients ; SIMD_UNITS_IN_RING_ELEMENT ] ,
359
347
) {
348
+ // Refactoring the code to have the loop body separately verified is good for proof performance.
349
+ // So we factor out the loop body in a `round` function similarly to the other NTT layers.
350
+ #[ inline( always) ]
351
+ #[ hax_lib:: fstar:: before(
352
+ r#"
353
+ let layer_bound_factor (step_by:usize) : n:nat{n <= 4} =
354
+ match step_by with
355
+ | MkInt 1 -> 4
356
+ | MkInt 2 -> 3
357
+ | MkInt 4 -> 2
358
+ | MkInt 8 -> 1
359
+ | MkInt 16 -> 0
360
+ | _ -> 0
361
+ "#
362
+ ) ]
363
+ #[ hax_lib:: fstar:: options( "--z3rlimit 300 --split_queries always" ) ]
364
+ #[ hax_lib:: fstar:: before( r#"[@@ "opaque_to_smt"]"# ) ]
365
+ #[ hax_lib:: requires( fstar!( r#"
366
+ v $step_by > 0 /\
367
+ v $index + v $step_by < v $SIMD_UNITS_IN_RING_ELEMENT /\
368
+ Spec.Utils.is_i32b_array_opaque
369
+ (v $NTT_BASE_BOUND + ((layer_bound_factor $step_by) * v $FIELD_MAX))
370
+ (Seq.index ${re} (v $index)).f_values /\
371
+ Spec.Utils.is_i32b_array_opaque
372
+ (v $NTT_BASE_BOUND + ((layer_bound_factor $step_by) * v $FIELD_MAX))
373
+ (Seq.index ${re} (v $index + v $step_by)).f_values /\
374
+ Spec.Utils.is_i32b 4190208 $zeta
375
+ "# ) ) ]
376
+ #[ hax_lib:: ensures( |_| fstar!( r#"
377
+ Spec.Utils.modifies2_32 ${re} ${re}_future $index (${index + step_by}) /\
378
+ Spec.Utils.is_i32b_array_opaque
379
+ (v $NTT_BASE_BOUND + ((layer_bound_factor $step_by + 1) * v $FIELD_MAX))
380
+ (Seq.index ${re}_future (v $index)).f_values /\
381
+ Spec.Utils.is_i32b_array_opaque
382
+ (v $NTT_BASE_BOUND + ((layer_bound_factor $step_by + 1) * v $FIELD_MAX))
383
+ (Seq.index ${re}_future (v $index + v step_by)).f_values
384
+ "# ) ) ]
385
+ fn round (
386
+ re : & mut [ Coefficients ; SIMD_UNITS_IN_RING_ELEMENT ] ,
387
+ index : usize ,
388
+ step_by : usize ,
389
+ zeta : i32 ,
390
+ ) {
391
+ hax_lib:: fstar!(
392
+ "reveal_opaque (`%Spec.Utils.is_i32b_array_opaque) (Spec.Utils.is_i32b_array_opaque)"
393
+ ) ;
394
+ let mut tmp = re[ index + step_by] ;
395
+ montgomery_multiply_by_constant ( & mut tmp, zeta) ;
396
+
397
+ re[ index + step_by] = re[ index] ;
398
+
399
+ arithmetic:: subtract ( & mut re[ index + step_by] , & tmp) ;
400
+ arithmetic:: add ( & mut re[ index] , & tmp) ;
401
+ }
402
+
360
403
#[ cfg( hax) ]
361
404
let orig_re = re. clone ( ) ;
362
405
@@ -372,20 +415,7 @@ fn outer_3_plus<const OFFSET: usize, const STEP_BY: usize, const ZETA: i32>(
372
415
(Seq.index ${re} i).f_values))
373
416
"#
374
417
) ) ;
375
-
376
- let mut tmp = re[ j + STEP_BY ] ;
377
- montgomery_multiply_by_constant ( & mut tmp, ZETA ) ;
378
-
379
- re[ j + STEP_BY ] = re[ j] ;
380
-
381
- arithmetic:: subtract ( & mut re[ j + STEP_BY ] , & tmp) ;
382
- arithmetic:: add ( & mut re[ j] , & tmp) ;
383
-
384
- hax_lib:: fstar!(
385
- r#"
386
- assert ((v ${NTT_BASE_BOUND} + ((layer_bound_factor v_STEP_BY) * v $FIELD_MAX)) + (v $FIELD_MAX)
387
- == (v ${NTT_BASE_BOUND} + ((layer_bound_factor v_STEP_BY + 1) * v $FIELD_MAX)))"#
388
- ) ;
418
+ round ( re, j, STEP_BY , ZETA ) ;
389
419
}
390
420
}
391
421
0 commit comments