diff options
author | Jade Philipoom <jadep@google.com> | 2018-02-20 18:02:47 +0100 |
---|---|---|
committer | Jason Gross <jasongross9@gmail.com> | 2018-02-23 13:06:33 -0500 |
commit | 2e972b36db6e2f425d36141750fda67ac9ae849f (patch) | |
tree | a4c06f87ffb3bee4a31eff3876f36749cda842dc /src | |
parent | 0c62a62f81f349dcafa37b38fabb5beac5432a89 (diff) |
Get bounds analysis working
Diffstat (limited to 'src')
-rw-r--r-- | src/Experiments/SimplyTypedArithmetic.v | 697 |
1 files changed, 490 insertions, 207 deletions
diff --git a/src/Experiments/SimplyTypedArithmetic.v b/src/Experiments/SimplyTypedArithmetic.v index 0761b653c..016e16cda 100644 --- a/src/Experiments/SimplyTypedArithmetic.v +++ b/src/Experiments/SimplyTypedArithmetic.v @@ -1378,9 +1378,13 @@ Module Compilers. | Z_leb : ident (Z * Z) bool | Z_of_nat : ident nat Z | Z_mul_split : ident (Z * Z * Z) (Z * Z) + | Z_mul_split_concrete (s:BinInt.Z) : ident (Z * Z) (Z * Z) | Z_add_get_carry : ident (Z * Z * Z) (Z * Z) + | Z_add_get_carry_concrete (s:BinInt.Z) : ident (Z * Z) (Z * Z) | Z_add_with_get_carry : ident (Z * Z * Z * Z) (Z * Z) + | Z_add_with_get_carry_concrete (s:BinInt.Z) : ident (Z * Z * Z) (Z * Z) | Z_sub_get_borrow : ident (Z * Z * Z) (Z * Z) + | Z_sub_get_borrow_concrete (s:BinInt.Z) : ident (Z * Z) (Z * Z) | Z_zselect : ident (Z * Z * Z) Z | Z_add_modulo : ident (Z * Z * Z) Z . @@ -1429,9 +1433,13 @@ Module Compilers. | Z_leb => curry2 Z.leb | Z_of_nat => Z.of_nat | Z_mul_split => curry3 Z.mul_split + | Z_mul_split_concrete s => curry2 (Z.mul_split s) | Z_add_get_carry => curry3 Z.add_get_carry_full + | Z_add_get_carry_concrete s => curry2 (Z.add_get_carry s) | Z_add_with_get_carry => curry4 Z.add_with_get_carry_full + | Z_add_with_get_carry_concrete s => curry3 (Z.add_with_get_carry s) | Z_sub_get_borrow => curry3 Z.sub_get_borrow_full + | Z_sub_get_borrow_concrete s => curry2 (Z.sub_get_borrow s) | Z_zselect => curry3 Z.zselect | Z_add_modulo => curry3 Z.add_modulo end. @@ -1508,9 +1516,9 @@ Module Compilers. | Z.leb ?x ?y => mkAppIdent ident.Z_leb (x, y) | Z.of_nat ?x => mkAppIdent ident.Z_of_nat x | Z.mul_split ?x ?y ?z => mkAppIdent ident.Z_mul_split (x, y, z) - | Z.add_get_carry ?x ?y ?z => mkAppIdent ident.Z_add_get_carry (x, y, z) - | Z.add_with_get_carry ?x ?y ?z ?a => mkAppIdent ident.Z_add_with_get_carry (x, y, z, a) - | Z.sub_get_borrow ?x ?y ?z => mkAppIdent ident.Z_sub_get_borrow (x, y, z) + | Z.add_get_carry_full ?x ?y ?z => mkAppIdent ident.Z_add_get_carry (x, y, z) + | Z.add_with_get_carry_full ?x ?y ?z ?a => mkAppIdent ident.Z_add_with_get_carry (x, y, z, a) + | Z.sub_get_borrow_full ?x ?y ?z => mkAppIdent ident.Z_sub_get_borrow (x, y, z) | Z.zselect ?x ?y ?z => mkAppIdent ident.Z_zselect (x, y, z) | Z.add_modulo ?x ?y ?z => mkAppIdent ident.Z_add_modulo (x,y,z) | _ @@ -1545,9 +1553,13 @@ Module Compilers. Notation leb := Z_leb. Notation of_nat := Z_of_nat. Notation mul_split := Z_mul_split. + Notation mul_split_concrete := Z_mul_split_concrete. Notation add_get_carry := Z_add_get_carry. + Notation add_get_carry_concrete := Z_add_get_carry_concrete. Notation add_with_get_carry := Z_add_with_get_carry. + Notation add_with_get_carry_concrete := Z_add_with_get_carry_concrete. Notation sub_get_borrow := Z_sub_get_borrow. + Notation sub_get_borrow_concrete := Z_sub_get_borrow_concrete. Notation zselect := Z_zselect. Notation add_modulo := Z_add_modulo. End Z. @@ -2428,6 +2440,14 @@ Module Compilers. | ident.Z_zselect as idc | ident.Z_add_modulo as idc => cps_of (Uncurried.expr.default.ident.interp idc) + | ident.Z_mul_split_concrete s + => cps_of (curry2 (Z.mul_split s)) + | ident.Z_add_get_carry_concrete s + => cps_of (curry2 (Z.add_get_carry s)) + | ident.Z_add_with_get_carry_concrete s + => cps_of (curry3 (Z.add_with_get_carry s)) + | ident.Z_sub_get_borrow_concrete s + => cps_of (curry2 (Z.sub_get_borrow s)) | ident.Let_In tx tC => fun '((x, f) : (interp R (type.translate tx) * (interp R (type.translate tx) * (interp R (type.translate tC) -> R) -> R))) @@ -2618,11 +2638,20 @@ Module Compilers. | ident.Z_mul_split as idc | ident.Z_add_get_carry as idc | ident.Z_sub_get_borrow as idc + | ident.Z_add_with_get_carry_concrete _ as idc => λ (xyk : (* ignore this line; it's to work around lack of fixpoint refolding in type inference *) var (type.Z * type.Z * type.Z * ((type.Z * type.Z) -> R))%ctype) , (ident.snd @@ (Var xyk)) @ ((idc : default.ident _ (type.Z * type.Z)) @@ (ident.fst @@ (Var xyk))) + | ident.Z_mul_split_concrete _ as idc + | ident.Z_add_get_carry_concrete _ as idc + | ident.Z_sub_get_borrow_concrete _ as idc + => λ (xyk : + (* ignore this line; it's to work around lack of fixpoint refolding in type inference *) var (type.Z * type.Z * ((type.Z * type.Z) -> R))%ctype) , + (ident.snd @@ (Var xyk)) + @ ((idc : default.ident _ (type.Z * type.Z)) + @@ (ident.fst @@ (Var xyk))) | ident.Z_zselect as idc | ident.Z_add_modulo as idc => λ (xyk : @@ -3137,6 +3166,7 @@ Module Compilers. | inr v => f (inr v) (* FIXME: do not substitute [S (big stuck term)] *) end end. + Definition interp {s d} (idc : ident s d) : value var (s -> d) := match idc in ident s d return value var (s -> d) with | ident.Let_In tx tC as idc @@ -3219,6 +3249,71 @@ Module Compilers. => List.nth_default (expr.reflect (t:=A) (AppIdent (ident.primitive default) TT)) ls idx | _ => expr.reflect (AppIdent idc (expr.reify (t:=type.list A) ls)) end + | ident.Z_mul_split as idc + => fun (x_y_z : (expr (type.Z * type.Z * type.Z) + + (expr (type.Z * type.Z) + (expr type.Z + Z) * (expr type.Z + Z)) * (expr type.Z + Z))%type) + => match x_y_z return (expr _ + (expr _ + type.interp _) * (expr _ + type.interp _)) with + | inr (inr (inr x, inr y), inr z) => + let result := ident.interp idc (x, y, z) in + inr (inr (fst result), inr (snd result)) + | inr (inr (inr x, y), z) + => expr.reflect (AppIdent (ident.Z.mul_split_concrete x) (expr.reify (t:=type.Z*type.Z) (inr (y, z)))) + | _ => expr.reflect (AppIdent idc (expr.reify (t:=_*_*_) x_y_z)) + end + | ident.Z_add_get_carry as idc + => fun (x_y_z : (expr (type.Z * type.Z * type.Z) + + (expr (type.Z * type.Z) + (expr type.Z + Z) * (expr type.Z + Z)) * (expr type.Z + Z))%type) + => match x_y_z return (expr _ + (expr _ + type.interp _) * (expr _ + type.interp _)) with + | inr (inr (inr x, inr y), inr z) => + let result := ident.interp idc (x, y, z) in + inr (inr (fst result), inr (snd result)) + | inr (inr (inr x, y), z) + => expr.reflect (AppIdent (ident.Z.add_get_carry_concrete x) (expr.reify (t:=type.Z*type.Z) (inr (y, z)))) + | _ => expr.reflect (AppIdent idc (expr.reify (t:=_*_*_) x_y_z)) + end + | ident.Z_add_with_get_carry as idc + => fun (x_y_z_a : (expr (_ * _ * _ * _) + + (expr (_ * _ * _) + + (expr (_ * _) + (expr _ + type.interp _) * (expr _ + type.interp _)) * + (expr _ + type.interp _)) * (expr _ + type.interp _))%type) + => match x_y_z_a return (expr _ + (expr _ + type.interp _) * (expr _ + type.interp _)) with + | inr (inr (inr (inr x, inr y), inr z), inr a) => + let result := ident.interp idc (x, y, z, a) in + inr (inr (fst result), inr (snd result)) + | inr (inr (inr (inr x, y), z), a) + => expr.reflect (AppIdent (ident.Z.add_with_get_carry_concrete x) (expr.reify (t:=type.Z*type.Z*type.Z) (inr (inr (y, z), a)))) + | _ => expr.reflect (AppIdent idc (expr.reify (t:=_*_*_*_) x_y_z_a)) + end + | ident.Z_sub_get_borrow as idc + => fun (x_y_z : (expr (type.Z * type.Z * type.Z) + + (expr (type.Z * type.Z) + (expr type.Z + Z) * (expr type.Z + Z)) * (expr type.Z + Z))%type) + => match x_y_z return (expr _ + (expr _ + type.interp _) * (expr _ + type.interp _)) with + | inr (inr (inr x, inr y), inr z) => + let result := ident.interp idc (x, y, z) in + inr (inr (fst result), inr (snd result)) + | inr (inr (inr x, y), z) + => expr.reflect (AppIdent (ident.Z.sub_get_borrow_concrete x) (expr.reify (t:=type.Z*type.Z) (inr (y, z)))) + | _ => expr.reflect (AppIdent idc (expr.reify (t:=_*_*_) x_y_z)) + end + | ident.Z_mul_split_concrete _ as idc + | ident.Z.add_get_carry_concrete _ as idc + | ident.Z.sub_get_borrow_concrete _ as idc + => fun (x_y : expr (_ * _) + (expr _ + type.interp _) * (expr _ + type.interp _)) + => match x_y return (expr _ + (expr _ + type.interp _) * (expr _ + type.interp _)) with + | inr (inr x, inr y) => + let result := ident.interp idc (x, y) in + inr (inr (fst result), inr (snd result)) + | _ => expr.reflect (AppIdent idc (expr.reify (t:=_*_) x_y)) + end + | ident.Z.add_with_get_carry_concrete _ as idc + => fun (x_y_z : (expr (type.Z * type.Z * type.Z) + + (expr (type.Z * type.Z) + (expr type.Z + Z) * (expr type.Z + Z)) * (expr type.Z + Z))%type) + => match x_y_z return (expr _ + (expr _ + type.interp _) * (expr _ + type.interp _)) with + | inr (inr (inr x, inr y), inr z) => + let result := ident.interp idc (x, y, z) in + inr (inr (fst result), inr (snd result)) + | _ => expr.reflect (AppIdent idc (expr.reify (t:=_*_*_) x_y_z)) + end | ident.pred as idc | ident.Nat_succ as idc | ident.Z_of_nat as idc @@ -3286,37 +3381,15 @@ Module Compilers. else default | inr (inl _, inl _) | inl _ => default end - | ident.Z_mul_split as idc - | ident.Z_add_get_carry as idc - | ident.Z_sub_get_borrow as idc - => fun (x_y_z : (expr (type.Z * type.Z * type.Z) + - (expr (type.Z * type.Z) + (expr type.Z + Z) * (expr type.Z + Z)) * (expr type.Z + Z))%type) - => match x_y_z return (expr _ + (expr _ + type.interp _) * (expr _ + type.interp _)) with - | inr (inr (inr x, inr y), inr z) => - let result := ident.interp idc (x, y, z) in - inr (inr (fst result), inr (snd result)) - | _ => expr.reflect (AppIdent idc (expr.reify (t:=_*_*_) x_y_z)) - end - | ident.Z_zselect as idc - | ident.Z_add_modulo as idc - => fun (x_y_z : (expr (_ * _ * _) + - (expr (_ * _) + (expr _ + type.interp _) * (expr _ + type.interp _)) * (expr _ + type.interp _))%type) - => match x_y_z return expr _ + type.interp _ with - | inr (inr (inr x, inr y), inr z) => inr (ident.interp idc (x, y, z)) - | _ => expr.reflect (AppIdent idc (expr.reify (t:=_*_*_) x_y_z)) - end - | ident.Z_add_with_get_carry as idc - => fun (x_y_z_a : (expr (_ * _ * _ * _) + - (expr (_ * _ * _) + - (expr (_ * _) + (expr _ + type.interp _) * (expr _ + type.interp _)) * - (expr _ + type.interp _)) * (expr _ + type.interp _))%type) - => match x_y_z_a return (expr _ + (expr _ + type.interp _) * (expr _ + type.interp _)) with - | inr (inr (inr (inr x, inr y), inr z), inr a) => - let result := ident.interp idc (x, y, z, a) in - inr (inr (fst result), inr (snd result)) - | _ => expr.reflect (AppIdent idc (expr.reify (t:=_*_*_*_) x_y_z_a)) - end - end. + | ident.Z_zselect as idc + | ident.Z_add_modulo as idc + => fun (x_y_z : (expr (_ * _ * _) + + (expr (_ * _) + (expr _ + type.interp _) * (expr _ + type.interp _)) * (expr _ + type.interp _))%type) + => match x_y_z return expr _ + type.interp _ with + | inr (inr (inr x, inr y), inr z) => inr (ident.interp idc (x, y, z)) + | _ => expr.reflect (AppIdent idc (expr.reify (t:=_*_*_) x_y_z)) + end + end. End interp. End ident. End partial. @@ -3553,12 +3626,21 @@ Module Compilers. | add (T1 T2 Tout : type.primitive) : ident (T1 * T2) Tout | shiftr (T1 Tout : type.primitive) (offset : BinInt.Z) : ident T1 Tout | land (T1 Tout : type.primitive) (mask : BinInt.Z) : ident T1 Tout - | cast (T1 Tout : type.primitive) : ident T1 Tout. + | cast (T1 Tout : type.primitive) : ident T1 Tout + | mul_split_concrete (T1 T2 Tout1 Tout2 : type.primitive) (split_at : BinInt.Z) : ident (T1 * T2) (Tout1 * Tout2) + | add_get_carry_concrete (T1 T2 Tout1 Tout2 : type.primitive) (split_at : BinInt.Z) : ident (T1 * T2) (Tout1 * Tout2) + | add_with_get_carry_concrete (T1 T2 T3 Tout1 Tout2 : type.primitive) (split_at : BinInt.Z) : ident (T1 * T2 * T3) (Tout1 * Tout2) + | sub_get_borrow_concrete (T1 T2 Tout1 Tout2 : type.primitive) (split_at : BinInt.Z) : ident (T1 * T2) (Tout1 * Tout2) + | zselect (T1 T2 T3 Tout : type.primitive) : ident (T1 * T2 * T3) Tout + | add_modulo (T1 T2 T3 Tout : type.primitive) : ident (T1 * T2 * T3) Tout + . Notation curry0 f := (fun 'tt => f). Notation curry2 f := (fun '(a, b) => f a b). + Notation curry3 f + := (fun '(a, b, c) => f a b c). Axiom admit : forall {T}, T. @@ -3583,6 +3665,25 @@ Module Compilers. : (type.interp (T1 * T2) -> type.interp T3) -> (type.interp (T1' * T2') -> type.interp T3') := fun f '((x, y) : type.interp T1' * type.interp T2') => resize (f (resize x, resize y)). + Definition resize2uc2out {T1 T2 T3 T4 T1' T2' T3' T4' : type.primitive} + : (type.interp (T1 * T2) -> (type.interp T3 * type.interp T4)) -> + (type.interp (T1' * T2') -> (type.interp T3' * type.interp T4')) + := fun f '((x, y) : type.interp T1' * type.interp T2') + => (resize (Datatypes.fst (f (resize x, resize y))), + resize (Datatypes.snd (f (resize x, resize y)))). + Definition resize3uc {T1 T2 T3 T4 T1' T2' T3' T4' : type.primitive} + : (type.interp (T1 * T2 * T3) -> type.interp T4) -> + (type.interp (T1' * T2' * T3') -> type.interp T4') + := fun f '((x, y, z) : type.interp T1' * type.interp T2' * type.interp T3') + => (resize (f (resize x, resize y, resize z))). + Definition resize3uc2out {T1 T2 T3 T4 T5 T1' T2' T3' T4' T5' : type.primitive} + : (type.interp (T1 * T2 * T3) -> (type.interp T4 * type.interp T5)) -> + (type.interp (T1' * T2' * T3') -> (type.interp T4' * type.interp T5')) + := fun f '((x, y, z) : type.interp T1' * type.interp T2' * type.interp T3') + => (resize (Datatypes.fst (f (resize x, resize y, resize z))), + resize (Datatypes.snd (f (resize x, resize y, resize z)))). + + Fixpoint default {t : type} : type.interp t := match t with @@ -3606,6 +3707,17 @@ Module Compilers. | shiftr _ _ n => @resize1 type.Z type.Z _ _ (fun v => Z.shiftr v n) | land _ _ mask => @resize1 type.Z type.Z _ _ (fun v => Z.land v mask) | cast _ _ => resize + | mul_split_concrete _ _ _ _ n => @resize2uc2out type.Z type.Z type.Z type.Z _ _ _ _ (curry2 (Z.mul_split n)) + | add_get_carry_concrete _ _ _ _ n => + @resize2uc2out type.Z type.Z type.Z type.Z _ _ _ _ (curry2 (Z.add_get_carry n)) + | add_with_get_carry_concrete _ _ _ _ _ n => + @resize3uc2out type.Z type.Z type.Z type.Z type.Z _ _ _ _ _ (curry3 (Z.add_with_get_carry n)) + | sub_get_borrow_concrete _ _ _ _ n => + @resize2uc2out type.Z type.Z type.Z type.Z _ _ _ _ (curry2 (Z.sub_get_borrow n)) + | zselect _ _ _ _ => + @resize3uc type.Z type.Z type.Z type.Z _ _ _ _ (curry3 Z.zselect) + | add_modulo _ _ _ _ => + @resize3uc type.Z type.Z type.Z type.Z _ _ _ _ (curry3 Z.add_modulo) end. Module Z. @@ -3613,6 +3725,12 @@ Module Compilers. Notation add := (@add type.Z type.Z type.Z). Notation shiftr := (@shiftr type.Z type.Z). Notation land := (@land type.Z type.Z). + Notation mul_split_concrete := (@mul_split_concrete type.Z type.Z type.Z type.Z). + Notation add_get_carry_concrete := (@add_get_carry_concrete type.Z type.Z type.Z type.Z). + Notation add_with_get_carry_concrete := (@add_with_get_carry_concrete type.Z type.Z type.Z type.Z type.Z). + Notation sub_get_borrow_concrete := (@sub_get_borrow_concrete type.Z type.Z type.Z type.Z). + Notation zselect := (@zselect type.Z type.Z type.Z type.Z). + Notation add_modulo := (@add_modulo type.Z type.Z type.Z type.Z). End Z. Module List. @@ -3809,6 +3927,18 @@ Module Compilers. => Some (Z.shiftr n) | ident.Z_land mask => Some (Z.land mask) + | ident.Z_mul_split_concrete s + => Some (Z.mul_split_concrete s) + | ident.Z_add_get_carry_concrete s + => Some (Z.add_get_carry_concrete s) + | ident.Z_sub_get_borrow_concrete s + => Some (Z.sub_get_borrow_concrete s) + | ident.Z_add_with_get_carry_concrete s + => Some (Z.add_with_get_carry_concrete s) + | default.ident.Z.zselect + => Some Z.zselect + | default.ident.Z.add_modulo + => Some Z.add_modulo | ident.Z_pow | ident.Z_opp | ident.Z_div @@ -3816,12 +3946,10 @@ Module Compilers. | ident.Z_eqb | ident.Z_leb | ident.Z_of_nat - | ident.Z.mul_split (* TODO: is this the right thing? *) - | ident.Z.add_get_carry (* TODO: is this the right thing? *) - | ident.Z.add_with_get_carry (* TODO: is this the right thing? *) - | ident.Z.sub_get_borrow (* TODO: is this the right thing? *) - | ident.Z.zselect (* TODO: is this the right thing? *) - | ident.Z.add_modulo (* TODO: is this the right thing? *) + | ident.Z.mul_split + | ident.Z.add_get_carry + | ident.Z.add_with_get_carry + | ident.Z.sub_get_borrow => None end. End ident. @@ -3953,6 +4081,15 @@ Module Compilers. let (ly, uy) := y in {| lower := Z.min 0 (Z.min lx ly) ; upper := Z.max 0 (Z.min ux uy) |}). + Definition split_bounds (r : zrange) (split_at : BinInt.Z) : zrange * zrange := + if upper r <? split_at + then if 0 <=? lower r + then (r, {| lower := 0; upper := 0 |}) + else ( {| lower := 0; upper := split_at - 1 |}, + {| lower := 0; upper := Z.max ( -(lower r / split_at)) (upper r / split_at) |} ) + else ( {| lower := 0; upper := split_at - 1 |}, + {| lower := 0; upper := Z.max ( -(lower r / split_at)) (upper r / split_at) |} ). + (** TODO: Move me *) Definition smart_fst {A B} (e : @expr ident (A * B)) : @expr ident A := match e in @expr _ t @@ -4138,6 +4275,45 @@ Module Compilers. (AppIdent (cast _ _) args)) | cast _ _ => fun _ => None + | mul_split_concrete _ _ _ _ split_at + => option_map + (fun '(existT r args) + => existT _ (split_bounds (ZRange.four_corners (BinInt.Z.mul) (Datatypes.fst r) (Datatypes.snd r)) split_at) + (AppIdent (mul_split_concrete _ _ _ _ split_at) args)) + | add_get_carry_concrete _ _ _ _ split_at + => option_map + (fun '(existT r args) + => existT _ (split_bounds (ZRange.four_corners (BinInt.Z.add) (Datatypes.fst r) (Datatypes.snd r)) split_at) + (AppIdent (add_get_carry_concrete _ _ _ _ split_at) args)) + | add_with_get_carry_concrete _ _ _ _ _ split_at + => option_map + (fun '(existT r args) + => existT _ (split_bounds (ZRange.eight_corners (fun a b c => (a + b + c)%Z) + (Datatypes.fst (Datatypes.fst r)) + (Datatypes.snd (Datatypes.fst r)) + (Datatypes.snd r)) split_at) + (AppIdent (add_with_get_carry_concrete _ _ _ _ _ split_at) args)) + | sub_get_borrow_concrete _ _ _ _ split_at + => option_map + (fun '(existT r args) + => existT _ (split_bounds (ZRange.four_corners (BinInt.Z.sub) (Datatypes.fst r) (Datatypes.snd r)) split_at) + (AppIdent (sub_get_borrow_concrete _ _ _ _ split_at) args)) + | zselect _ _ _ _ + => option_map + (fun '(existT r args) + => existT _ (ZRange.union (Datatypes.snd (Datatypes.fst r)) (Datatypes.snd r)) + (AppIdent (zselect _ _ _ _) args)) + | add_modulo _ _ _ _ + => option_map + (fun '(existT r args) + => existT _ (ZRange.union (ZRange.four_corners BinInt.Z.add + (Datatypes.fst (Datatypes.fst r)) + (Datatypes.snd (Datatypes.fst r))) + (ZRange.eight_corners (fun x y m=> Z.max 0 (x + y - m)%Z) + (Datatypes.fst (Datatypes.fst r)) + (Datatypes.snd (Datatypes.fst r)) + (Datatypes.snd r))) + (AppIdent (add_modulo _ _ _ _) args)) end%zrange%option. End with_relax. End ident. @@ -4790,6 +4966,8 @@ Module PrintingNotations. Export BoundsAnalysis.ident. Export BoundsAnalysis.Notations. Open Scope btype_scope. + Notation "'uint256'" + := (r[0 ~> 115792089237316195423570985008687907853269984665640564039457584007913129639935]%btype) : btype_scope. Notation "'uint128'" := (r[0 ~> 340282366920938463463374607431768211455]%btype) : btype_scope. Notation "'uint64'" @@ -5083,193 +5261,298 @@ Require Import Crypto.Util.ZUtil.EquivModulo. Require Import Crypto.Util.ZUtil.Modulo Crypto.Util.ZUtil.Tactics. Require Import Crypto.Util.ZUtil.Zselect Crypto.Util.ZUtil.AddModulo. -Module Montgomery256. - - (* written in a way that is easier to reify *) - Definition montred' (N R N' lo hi : Z) := - dlet y := fst (Z.mul_split R lo N') in - dlet t1_t2 := Z.mul_split R y N in - dlet lo'_carry := Z.add_get_carry_full R lo (fst t1_t2) in - dlet hi'_carry := Z.add_with_get_carry_full R (snd lo'_carry) hi (snd t1_t2) in - dlet y' := Z.zselect (snd hi'_carry) 0 N in - dlet lo'' := fst (Z.sub_get_borrow_full R (fst hi'_carry) y') in - Z.add_modulo lo'' 0 N. - - Lemma montred'_eq N R N' lo hi T - (HN_range: 0 <= N < R) (HT_range: 0 <= T < R * N) (HN'_range: 0 <= N' < R) - (HN_nz: N <> 0) (Hlo: lo = T mod R) (Hhi: hi = T / R) - (HN': Z.equiv_modulo R (N*N') (-1)): - montred' N R N' lo hi = reduce_via_partial N R N' T. - Proof. - rewrite <-reduce_via_partial_alt_eq by nia. - cbv [montred' partial_reduce_alt reduce_via_partial_alt prereduce Let_In]. subst lo hi. - autorewrite with to_div_mod. rewrite ?Z.zselect_correct, ?Z.add_modulo_correct. - (* pull out value before last modular reduction *) - match goal with |- (if (?n <=? ?x)%Z then ?x - ?n else ?x) = (if (?n <=? ?y) then ?y - ?n else ?y)%Z => - let P := fresh "H" in assert (x = y) as P; [|rewrite P; reflexivity] end. - - match goal with - |- context [if R * R <=? ?x then _ else _] => - match goal with |- context [if dec (?xHigh / R = 0) then _ else _] => - assert (x / R = xHigh) as cond_equiv end end. - { apply Z.mul_cancel_r with (p:=R); [omega|]. autorewrite with push_Zmul zdiv_to_mod push_Zmod; ring. } - rewrite <-cond_equiv. rewrite ?Z.mod_pull_div, ?Z.div_div by omega. - assert (0 < R * R)%Z by Z.zero_bounds. - - break_match; try reflexivity; autorewrite with ltb_to_lt in *; rewrite Z.div_small_iff in * by omega; - repeat match goal with - | _ => progress autorewrite with zsimplify_fast - | |- context [?x mod (R * R)] => - unique pose proof (Z.mod_pos_bound x (R * R)); - try rewrite (Z.mod_small x (R * R)) in * by Z.rewrite_mod_small_solver - | _ => omega - | _ => progress Z.rewrite_mod_small - end. - Qed. - +Module MontgomeryReduction. + Section MontRed'. + Context (N R N' R' : Z). + Context (HN_range : 0 <= N < R) (HN'_range : 0 <= N' < R) (HN_nz : N <> 0) + (N'_good : Z.equiv_modulo R (N*N') (-1)) (R'_good: Z.equiv_modulo N (R*R') 1). + + (* simpler version using very wide multiplications (256x256) *) + Definition montred' (lo_hi : (Z * Z)) := + dlet_nd y := fst (Z.mul_split R (fst lo_hi)N') in + dlet_nd t1_t2 := Z.mul_split R y N in + dlet_nd lo'_carry := Z.add_get_carry_full R (fst lo_hi)(fst t1_t2) in + dlet_nd hi'_carry := Z.add_with_get_carry_full R (snd lo'_carry) (snd lo_hi) (snd t1_t2) in + dlet_nd y' := Z.zselect (snd hi'_carry) 0 N in + dlet_nd lo'' := fst (Z.sub_get_borrow_full R (fst hi'_carry) y') in + Z.add_modulo lo'' 0 N. + + Lemma montred'_eq lo_hi T (HT_range: 0 <= T < R * N) + (Hlo: fst lo_hi = T mod R) (Hhi: snd lo_hi = T / R): + montred' lo_hi = reduce_via_partial N R N' T. + Proof. + rewrite <-reduce_via_partial_alt_eq by nia. + cbv [montred' partial_reduce_alt reduce_via_partial_alt prereduce Let_In]. + rewrite Hlo, Hhi. + autorewrite with to_div_mod. rewrite ?Z.zselect_correct, ?Z.add_modulo_correct. + (* pull out value before last modular reduction *) + match goal with |- (if (?n <=? ?x)%Z then ?x - ?n else ?x) = (if (?n <=? ?y) then ?y - ?n else ?y)%Z => + let P := fresh "H" in assert (x = y) as P; [|rewrite P; reflexivity] end. + + match goal with + |- context [if R * R <=? ?x then _ else _] => + match goal with |- context [if dec (?xHigh / R = 0) then _ else _] => + assert (x / R = xHigh) as cond_equiv end end. + { apply Z.mul_cancel_r with (p:=R); [omega|]. autorewrite with push_Zmul zdiv_to_mod push_Zmod; ring. } + rewrite <-cond_equiv. rewrite ?Z.mod_pull_div, ?Z.div_div by omega. + assert (0 < R * R)%Z by Z.zero_bounds. + + break_match; try reflexivity; autorewrite with ltb_to_lt in *; rewrite Z.div_small_iff in * by omega; + repeat match goal with + | _ => progress autorewrite with zsimplify_fast + | |- context [?x mod (R * R)] => + unique pose proof (Z.mod_pos_bound x (R * R)); + try rewrite (Z.mod_small x (R * R)) in * by Z.rewrite_mod_small_solver + | _ => omega + | _ => progress Z.rewrite_mod_small + end. + Qed. - Lemma montred'_correct N R N' R' lo hi T - (R'_good: Z.equiv_modulo N (R * R') 1) - (N'_good: Z.equiv_modulo R (N * N') (-1)) - (HN_range: 0 <= N < R) (HT_range: 0 <= T < R * N) (HN'_range: 0 <= N' < R) - (HN_nz: N <> 0) (Hlo: lo = T mod R) (Hhi: hi = T / R) - (HN': Z.equiv_modulo R (N*N') (-1)): - montred' N R N' lo hi = (T * R') mod N. - Proof. - erewrite montred'_eq by eauto. - apply Z.equiv_modulo_mod_small; auto using reduce_via_partial_correct. - replace 0 with (Z.min 0 (R-N)) by (apply Z.min_l; omega). - apply reduce_via_partial_in_range; omega. - Qed. + Lemma montred'_correct lo_hi T (HT_range: 0 <= T < R * N) + (Hlo: fst lo_hi = T mod R) (Hhi: snd lo_hi = T / R): montred' lo_hi = (T * R') mod N. + Proof. + erewrite montred'_eq by eauto. + apply Z.equiv_modulo_mod_small; auto using reduce_via_partial_correct. + replace 0 with (Z.min 0 (R-N)) by (apply Z.min_l; omega). + apply reduce_via_partial_in_range; omega. + Qed. + End MontRed'. + Definition test := + (fun (N R N' : Z) (lo_hi : Z * Z) => + dlet_nd x := fst (Z.sub_get_borrow_full R (fst lo_hi) N) in + x). + Derive montred_gen - SuchThat (forall N R N' R' - (R'_good: Z.equiv_modulo N (R * R') 1) - (N'_good: Z.equiv_modulo R (N * N') (-1)) - (HN_range: 0 <= N < R) - (HN'_range: 0 <= N' < R) - (HN_nz: N <> 0) - T lo_hi (lo:=fst lo_hi) (hi:=snd lo_hi) - (HT_range: 0 <= T < R * N) - (Hlo : lo = T mod R) - (Hhi: hi = T / R) - (result := montred_gen R N N' lo_hi), - (result = (T * R') mod N)) + SuchThat (forall (N R N' : Z) + (lo_hi : Z * Z), + Interp (t:=type.reify_type_of montred') + montred_gen N R N' lo_hi + = montred' N R N' lo_hi) As montred_gen_correct. Proof. - intros; subst montred_gen. - erewrite <-montred'_correct by eassumption. - pose (N, R, N', lo_hi) as args. - subst lo hi. - change lo_hi with (snd args). - change N' with (snd (fst args)). - change R with (snd (fst (fst args))). - change N with (fst (fst (fst args))). - remember args as args' eqn:Heqargs'. + intros. etransitivity. Focus 2. - { subst result. - repeat match goal with H : _ |- _ => clear H end; revert args'. - lazymatch goal with - | [ |- forall args, ?ev = @?RHS args ] - => refine (fun args => f_equal (fun F => F args) (_ : _ = RHS)) - end. - change montgomeryZ with Z in *. - cbv beta delta [montred']. - Reify_rhs (). - reflexivity. - } Unfocus. + { repeat apply (f_equal (fun f => f _)). + Reify_rhs(). + reflexivity. } Unfocus. cbv beta. - let e := match goal with |- _ = expr.Interp _ ?e _ => e end in + let RHS := match goal with |- _ = ?RHS => RHS end in + let e := match RHS with context[expr.Interp _ ?e] => e end in set (E := e). - Time let E' := constr:(PartialReduce (CPS.CallFunWithIdContinuation (CPS.Translate (canonicalize_list_recursion E)))) in - let E' := (eval lazy in E') in + let E' := (eval vm_compute in E') in (* 0.131 for vm, about 0.6 for lazy, slower for native and cbv *) pose E' as E''. - - transitivity (Interp E'' args'); [|reflexivity]. - clear E. - subst args' args; cbn [fst snd]. - subst result. + let LHS := match goal with |- ?LHS = _ => LHS end in + lazymatch LHS with + | context LHS[expr.Interp _ _] + => let LHS := context LHS[Interp E''] in + transitivity LHS + end; + [ clear E | reflexivity ]. + subst montred_gen. reflexivity. Qed. + Section rmontred. + Context (N R N' : Z) + (machine_wordsize : Z). + + Let n : nat := Z.to_nat (Qceiling ((Z.log2_up N) / machine_wordsize)). + Let bound := r[0 ~> (2^machine_wordsize - 1)%Z]%zrange. + + Definition relax_zrange_of_machine_wordsize + := relax_zrange_gen [machine_wordsize; 2 * machine_wordsize; 4 * machine_wordsize]%Z. + Local Arguments relax_zrange_of_machine_wordsize / . + + Let rN := GallinaReify.Reify N. + Let rR := GallinaReify.Reify R. + Let rN' := GallinaReify.Reify N'. + Let relax_zrange := relax_zrange_of_machine_wordsize. + Let arg_bounds : BoundsAnalysis.Indexed.Range.range (BoundsAnalysis.Indexed.OfPHOAS.type.compile (type.Z * type.Z)) + := (bound, bound). + Let out_bounds : BoundsAnalysis.Indexed.Range.range (BoundsAnalysis.Indexed.OfPHOAS.type.compile (type.Z)) + := bound. + + Definition check_args {T} (res : Pipeline.ErrorT T) + : Pipeline.ErrorT T + := if (N =? 0)%Z + then Pipeline.Error (Pipeline.Values_not_provably_distinct "N ≠ 0" N 0) + else if (n =? 0)%Z + then Pipeline.Error (Pipeline.Values_not_provably_distinct "n ≠ 0" N 0) + else res. + + Lemma check_args_success_id {T} {rv : T} {res} + : check_args res = Pipeline.Success rv + -> res = Pipeline.Success rv. + Proof. + cbv [check_args]; break_innermost_match; congruence. + Qed. + + Definition rmontred + := let res := Pipeline.BoundsPipeline + (relax_zrange) + (s:=(type.Z * type.Z)%ctype) + (d:=(type.Z)%ctype) + (arg_bounds) + (out_bounds) + (fun var + => (montred_gen _) + @ (rN _) + @ (rR _) + @ (rN' _) + )%expr in + check_args res. + + Definition rmontred_correctT + rv + := forall arg + (arg' := @BoundsAnalysis.OfPHOAS.cast_back + _ + (relax_zrange) + (arg_bounds) + arg), + BoundsAnalysis.OfPHOAS.Interp + (relax_zrange) + (arg_bounds) + (bs:=out_bounds) + arg + rv + = Some (montred' (Interp rN) (Interp rR) (Interp rN') arg'). + + Lemma rmontred_correct + rv + (Hrv : rmontred = Pipeline.Success rv) + : rmontred_correctT rv. + Proof. + hnf; intros. + cbv [rmontred] in Hrv. + edestruct (Pipeline.BoundsPipeline _ _ _ _) as [rv'|] eqn:Hrv'; + [ | clear -Hrv; cbv [check_args] in Hrv; break_innermost_match_hyps; discriminate ]. + erewrite <- montred_gen_correct. + eapply Pipeline.BoundsPipeline_correct in Hrv'. + apply check_args_success_id in Hrv; inversion Hrv; subst rv. + rewrite Hrv'. + cbv [expr.Interp]. + cbn [expr.interp]. + apply f_equal; f_equal; + cbn -[reify_list]; + rewrite interp_reify_list, map_map; cbn; + erewrite map_ext with (g:=id), map_id; try reflexivity. + Qed. + End rmontred. +End MontgomeryReduction. + +Ltac solve_rmontred _ := + eapply MontgomeryReduction.rmontred_correct; + lazy; reflexivity. + +Module Montgomery256. + Definition N := (2^256-2^224+2^192+2^96-1). Definition N':= (115792089210356248768974548684794254293921932838497980611635986753331132366849). Definition R := (2^256). + Definition machine_wordsize := 256. Derive montred256 - SuchThat (forall - (lo_hi : Z * Z) - (lo := fst lo_hi) (hi := snd lo_hi) - R' (R'_good: Z.equiv_modulo N (R * R') 1) - T (Hlo: lo = T mod R) (Hhi: hi = T / R) - (HT_range: 0 <= T < R * N) - (result := montred256 lo_hi), - result = (T * R') mod N) + SuchThat (MontgomeryReduction.rmontred_correctT N R N' machine_wordsize montred256) As montred256_correct. - Proof. - intros. subst lo hi result. - erewrite <-montred_gen_correct with (N:=N) (N':=N') (R:=R) (R':=R') (lo_hi:=lo_hi) by exact admit. - (* - by (assumption || omega || reflexivity || cbv - [Z.le Z.lt]; omega). *) - cbv - [montred256 montred_gen]. (* simplify constants *) - cbv [montred_gen]. - lazymatch goal with - | [ |- ?ev = expr.Interp (@ident.interp) ?e (?args, lo_hi) ] - => let rargs := Reify args in - let rargs := constr:(canonicalize_list_recursion rargs) in - transitivity (expr.Interp - (@ident.interp) - (fun var - => λ (LOHI : var (type.Z * type.Z)%ctype), - (e var @ (rargs var, Var LOHI)))%expr lo_hi) - end. - (* this second goal is admitted in base_51_carry_mul, presumably because either lists are hard or it's slow *) - Focus 2. - { cbv [expr.interp expr.Interp ident.interp]. - cbv [canonicalize_list_recursion canonicalize_list_recursion.expr.transfer canonicalize_list_recursion.ident.transfer]. - reflexivity. } Unfocus. - let e := match goal with |- _ = expr.Interp _ ?e _ => e end in - set (E := e); - cbv [canonicalize_list_recursion canonicalize_list_recursion.expr.transfer canonicalize_list_recursion.ident.transfer] in E. - Time let E' := constr:(DeadCodeElimination.EliminateDead (PartialReduce E)) in - let E' := (eval lazy in E') in - pose E' as E''. - transitivity (Interp E'' lo_hi); [ clear E | subst E E''; reflexivity ]. (* again, second proof admitted in base_51_carry_mul *) - subst montred256; reflexivity. - Qed. -End Montgomery256. + Proof. Time solve_rmontred(). Time Qed. -Import ident. + Import PrintingNotations. + Print montred256. + (* +(expr_let 2 := fst @@ + (mul_split_concrete uint256 uint256 uint256 uint256 + 115792089237316195423570985008687907853269984665640564039457584007913129639936 @@ + (fst @@ x_1, (115792089210356248768974548684794254293921932838497980611635986753331132366849))) in + expr_let 3 := mul_split_concrete uint256 uint256 uint256 uint256 + 115792089237316195423570985008687907853269984665640564039457584007913129639936 @@ + (x_2, (115792089210356248762697446949407573530086143415290314195533631308867097853951)) in + expr_let 4 := add_get_carry_concrete uint256 uint256 uint256 uint256 + 115792089237316195423570985008687907853269984665640564039457584007913129639936 @@ (fst @@ x_1, fst @@ x_3) in + expr_let 5 := add_with_get_carry_concrete uint256 uint256 uint256 uint256 uint256 + 115792089237316195423570985008687907853269984665640564039457584007913129639936 @@ (snd @@ x_4, snd @@ x_1, snd @@ x_3) in + expr_let 6 := zselect uint256 uint256 uint256 uint256 @@ + (snd @@ x_5, (0), (115792089210356248762697446949407573530086143415290314195533631308867097853951)) in + expr_let 7 := fst @@ + (sub_get_borrow_concrete uint256 uint256 uint256 uint256 + 115792089237316195423570985008687907853269984665640564039457584007913129639936 @@ (fst @@ x_5, x_6)) in + add_modulo uint256 uint256 uint256 uint256 @@ + (x_7, (0), (115792089210356248762697446949407573530086143415290314195533631308867097853951)))%nexpr + : expr + (BoundsAnalysis.AdjustBounds.ident.type_for_range (MontgomeryReduction.relax_zrange_of_machine_wordsize machine_wordsize) + r[0 ~> 2 ^ machine_wordsize - 1]%zrange) + *) -Print Montgomery256.montred256. -(* expr.Interp (@interp) - (fun var : type -> Type => - (λ v : var (type.Z * type.Z)%ctype, - expr_let v0 := fst @@ - (Z.mul_split @@ - (115792089237316195423570985008687907853269984665640564039457584007913129639936, fst @@ v, - 115792089210356248768974548684794254293921932838497980611635986753331132366849)) in - expr_let v1 := Z.mul_split @@ - (115792089237316195423570985008687907853269984665640564039457584007913129639936, v0, - 115792089210356248762697446949407573530086143415290314195533631308867097853951) in - expr_let v2 := Z.add_get_carry @@ - (115792089237316195423570985008687907853269984665640564039457584007913129639936, fst @@ v, fst @@ v1) in - expr_let v3 := Z.add_with_get_carry @@ - (115792089237316195423570985008687907853269984665640564039457584007913129639936, snd @@ v2, snd @@ v, snd @@ v1) in - expr_let v4 := Z.zselect @@ (snd @@ v3, 0, 115792089210356248762697446949407573530086143415290314195533631308867097853951) in - expr_let v5 := fst @@ - (Z.sub_get_borrow @@ (115792089237316195423570985008687907853269984665640564039457584007913129639936, fst @@ v3, v4)) in - Z.add_modulo @@ (v5, 0, 115792089210356248762697446949407573530086143415290314195533631308867097853951))%expr) - : Z * Z -> Z -*) +End Montgomery256. -(* with named constants *) -Goal (Montgomery256.montred256 = Datatypes.fst). - cbv [Montgomery256.montred256]. - change (115792089210356248762697446949407573530086143415290314195533631308867097853951) with (Montgomery256.N). - change (115792089237316195423570985008687907853269984665640564039457584007913129639936) with (Montgomery256.R). - change (115792089210356248768974548684794254293921932838497980611635986753331132366849) with (Montgomery256.N'). +Module Montgomery256PrintingNotations. + Export ident. + Export BoundsAnalysis.ident. + Export BoundsAnalysis.type.Notations. + Export BoundsAnalysis.Indexed.expr.Notations. + Export BoundsAnalysis.ident.Notations. + Import BoundsAnalysis.type. + Import BoundsAnalysis.Indexed.expr. + Import BoundsAnalysis.ident. + Open Scope btype_scope. + Notation "'RegMod'" := + (BoundsAnalysis.Indexed.expr.AppIdent + (primitive {| BoundsAnalysis.type.value := 115792089210356248762697446949407573530086143415290314195533631308867097853951; BoundsAnalysis.type.value_bounded := _ |}) + BoundsAnalysis.Indexed.expr.TT) (only printing, at level 9) : nexpr_scope. + Notation "'RegPinv'" := + (BoundsAnalysis.Indexed.expr.AppIdent + (primitive {| BoundsAnalysis.type.value := 115792089210356248768974548684794254293921932838497980611635986753331132366849; BoundsAnalysis.type.value_bounded := _ |}) + BoundsAnalysis.Indexed.expr.TT) (only printing, at level 9) : nexpr_scope. + Notation "'RegZero'" := + (BoundsAnalysis.Indexed.expr.AppIdent + (primitive {| BoundsAnalysis.type.value := 0; BoundsAnalysis.type.value_bounded := _ |}) + BoundsAnalysis.Indexed.expr.TT) (only printing, at level 9) : nexpr_scope. + Notation "'$R'" := 115792089237316195423570985008687907853269984665640564039457584007913129639936 : nexpr_scope. + Notation "'uint256'" + := (BoundsAnalysis.type.ZBounded 0 115792089237316195423570985008687907853269984665640564039457584007913129639935) : btype_scope. + Notation "$r n" := (BoundsAnalysis.Indexed.expr.Var _ n) (at level 10, format "$r n") : nexpr_scope. + Notation "$r n '_lo'" := (fst @@ (BoundsAnalysis.Indexed.expr.Var (BoundsAnalysis.type.prod _ _) n))%nexpr (at level 10, format "$r n _lo") : nexpr_scope. + Notation "$r n '_hi'" := (snd @@ (BoundsAnalysis.Indexed.expr.Var (BoundsAnalysis.type.prod _ _) n))%nexpr (at level 10, format "$r n _hi") : nexpr_scope. + Notation "'c.Mul256(' '$r' n ',' x ',' y ');' f" := + (expr_let n := fst @@ (mul_split_concrete uint256 uint256 uint256 uint256 $R @@ (x, y)) in + (f))%nexpr (at level 49, format "'[' 'c.Mul256(' '$r' n ',' x ',' y ');' ']' '//' f" ) : nexpr_scope. + Notation "'c.Mul256x256(' '$r' n ',' x ',' y ');' f" := + (expr_let n := mul_split_concrete uint256 uint256 uint256 uint256 $R @@ (x, y) in + f)%nexpr (at level 48, format "'[' 'c.Mul256x256(' '$r' n ',' x ',' y ');' ']' '//' f") : nexpr_scope. + Notation "'c.Add(' '$r' n ',' x ',' y ');' f" := + (expr_let n := add_get_carry_concrete uint256 uint256 uint256 uint256 $R @@ (x, y) in + f)%nexpr (at level 47, format "'[' 'c.Add(' '$r' n ',' x ',' y ');' ']' '//' f") : nexpr_scope. + Notation "'c.Addc(' '$r' n ',' x ',' y ');' f" := + (expr_let n := add_with_get_carry_concrete uint256 uint256 uint256 uint256 uint256 $R @@ (_, x, y) in + f)%nexpr (at level 46, format "'[' 'c.Addc(' '$r' n ',' x ',' y ');' ']' '//' f") : nexpr_scope. + Notation "'c.Selc(' '$r' n ',' y ',' z ');' f" := + (expr_let n := zselect uint256 uint256 uint256 uint256 @@ (_, y, z) in + f)%nexpr (at level 45, format "'[' 'c.Selc(' '$r' n ',' y ',' z ');' ']' '//' f") : nexpr_scope. + Notation "'c.Sub(' '$r' n ',' x ',' y ');' f" := + (expr_let n := fst @@ (sub_get_borrow_concrete uint256 uint256 uint256 uint256 $R @@ (x, y)) in + f)%nexpr (at level 44, format "'c.Sub(' '$r' n ',' x ',' y ');' '//' f") : nexpr_scope. + Notation "'c.AddM(' '$ret' ',' x ',' y ',' z ');'" := + (add_modulo uint256 uint256 uint256 uint256 @@ (x, y, z))%nexpr (at level 40, format "'c.AddM(' '$ret' ',' x ',' y ',' z ');'") : nexpr_scope. +End Montgomery256PrintingNotations. + +Import Montgomery256PrintingNotations. +Local Open Scope nexpr_scope. -Abort. +Print Montgomery256.montred256. +(* +c.Mul256($r2, $r1_lo, RegPinv); +c.Mul256x256($r3, $r2, RegMod); +c.Add($r4, $r1_lo, $r3_lo); +c.Addc($r5, $r1_hi, $r3_hi); +c.Selc($r6,RegZero, RegMod); +c.Sub($r7, $r5_lo, $r6); +c.AddM($ret, $r7, RegZero, RegMod); + : expr + (BoundsAnalysis.AdjustBounds.ident.type_for_range + (MontgomeryReduction.relax_zrange_of_machine_wordsize + Montgomery256.machine_wordsize) + r[0 ~> 2 ^ Montgomery256.machine_wordsize - 1]%zrange) +*)
\ No newline at end of file |