Skip to content

Commit 6941218

Browse files
committed
Performance improvements: no division in mkword
1 parent c5f91db commit 6941218

File tree

3 files changed

+97
-13
lines changed

3 files changed

+97
-13
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Changed
6+
7+
- The performance of `mkword` has been improved as it no longer uses Euclidean division.
8+
59
### Added
610

711
- Lemma `sub_wordE` relates `sub_word` to `add_word` and `opp_word`.

src/word.v

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,9 @@ Context (n : nat).
118118
Notation isword z := (0 <= z < modulus n)%R.
119119

120120
(* -------------------------------------------------------------------- *)
121-
Lemma mkword_proof (z : Z) : isword (z mod (modulus n))%Z.
121+
Lemma mkword_proof (z : Z) : isword (zmod_pow2 z n)%Z.
122122
Proof.
123+
rewrite zmod_pow2E // -modulusZE.
123124
apply/andP; rewrite -(rwP ltzP) -(rwP lezP).
124125
by apply/Z_mod_lt/Z.lt_gt/ltzP/modulus_gt0.
125126
Qed.
@@ -149,17 +150,17 @@ Proof. by []. Qed.
149150
(* -------------------------------------------------------------------- *)
150151
Lemma ureprK : cancel urepr mkword.
151152
Proof.
152-
move=> w; rewrite (rwP eqP) -val_eqE /=; rewrite Z.mod_small //.
153+
move=> w; rewrite (rwP eqP) -val_eqE /=; rewrite zmod_pow2E Z.mod_small // -modulusZE.
153154
by rewrite !(rwP lezP, rwP ltzP) (rwP andP) urepr_isword.
154155
Qed.
155156

156157
(* -------------------------------------------------------------------- *)
157158
Lemma mkwordK (z : Z) : urepr (mkword z) = (z mod modulus n)%Z.
158-
Proof. by []. Qed.
159+
Proof. by rewrite modulusZE -zmod_pow2E. Qed.
159160

160161
(* -------------------------------------------------------------------- *)
161162
Lemma mkword_valK (z : Z) : mkword z = (z mod modulus n)%Z :> Z.
162-
Proof. by []. Qed.
163+
Proof. by rewrite modulusZE -zmod_pow2E. Qed.
163164

164165
(* -------------------------------------------------------------------- *)
165166
Lemma isword_ofnatZP (k : nat) :
@@ -252,7 +253,7 @@ Lemma sub_wordE (w1 w2 : n.-word) :
252253
sub_word w1 w2 = add_word w1 (opp_word w2).
253254
Proof.
254255
apply: val_inj.
255-
by rewrite /= /opp_word mkwordK !urepr_word -Z.add_opp_r Zplus_mod_idemp_r.
256+
by rewrite /= /opp_word !zmod_pow2E -modulusZE mkwordK !urepr_word -Z.add_opp_r Zplus_mod_idemp_r.
256257
Qed.
257258

258259
Definition mul_word (w1 w2 : n.-word) :=
@@ -276,15 +277,15 @@ rewrite (rwP eqP) -val_eqE /= modn_small.
276277
rewrite Z2Nat.id //; case/andP: h => _ /ltzP.
277278
by rewrite /modulus two_power_nat_equiv Nat2Z.n2zX expZE.
278279
+ rewrite Z2Nat.id; first by case/andP: h => /lezP.
279-
by rewrite Zmod_small // !(rwP lezP, rwP ltzP) (rwP andP).
280+
by rewrite zmod_pow2E -modulusZE Zmod_small // !(rwP lezP, rwP ltzP) (rwP andP).
280281
Qed.
281282

282283
(* -------------------------------------------------------------------- *)
283284
Lemma word_of_ordK : cancel word_of_ord ord_of_word.
284285
Proof.
285286
rewrite /ord_of_word /word_of_ord => -[k /= lt].
286287
apply/eqP; rewrite -val_eqE /= prednK_modulus.
287-
rewrite prednK_modulus in lt; rewrite Zmod_small.
288+
rewrite prednK_modulus in lt; rewrite zmod_pow2E -modulusZE Zmod_small.
288289
+ by apply/isword_ofnatZP.
289290
+ by rewrite modn_small Nat2Z.id.
290291
Qed.
@@ -303,6 +304,7 @@ rewrite [Z.to_nat x %% _]modn_small 1?[Z.to_nat y %% _]modn_small.
303304
+ by apply/isword_tonatZP/iswordZP.
304305
+ by apply/isword_tonatZP/iswordZP.
305306
rewrite modnZE ?expn_eq0 // -Zofnat_modulus.
307+
rewrite !zmod_pow2E -modulusZE.
306308
by rewrite Zmod_mod Nat2Z.n2zD !Z2Nat.id.
307309
Qed.
308310

@@ -312,6 +314,7 @@ Lemma opp_word_ordE (x : n.-word) :
312314
Proof.
313315
rewrite (rwP eqP) word_eqE /=; case: x => [x hx].
314316
rewrite /opp_word /urepr /= prednK_modulus; apply/eqP.
317+
rewrite !zmod_pow2E -modulusZE.
315318
rewrite modnZE ?expn_eq0 // -Zofnat_modulus Zmod_mod.
316319
rewrite modn_small; first by apply/isword_tonatZP/iswordZP.
317320
rewrite Nat2Z.n2zB ?isword_tonatZWP //; first by apply/iswordZP.
@@ -422,7 +425,7 @@ Proof. by rewrite word0_ordE. Qed.
422425

423426
(* -------------------------------------------------------------------- *)
424427
Lemma word1_zmodE : word1 = word_of_zmod 1%R.
425-
Proof. by rewrite (rwP eqP) -val_eqE /= Zmod_small. Qed.
428+
Proof. by rewrite (rwP eqP) -val_eqE. Qed.
426429

427430
(* -------------------------------------------------------------------- *)
428431
Lemma add_word_zmodE (x y : n.+1.-word) :
@@ -450,6 +453,7 @@ rewrite [Z.to_nat x %% _]modn_small 1?[Z.to_nat y %% _]modn_small.
450453
+ by apply/isword_tonatZP/iswordZP.
451454
+ by apply/isword_tonatZP/iswordZP.
452455
rewrite -word_Fcast prednK_modulus modnZE ?expn_eq0 //.
456+
rewrite !zmod_pow2E -(modulusZE n.+1).
453457
by rewrite -Zofnat_modulus Zmod_mod Nat2Z.n2zM !Z2Nat.id.
454458
Qed.
455459

@@ -502,7 +506,7 @@ End WordRing.
502506
Lemma mkword_val_small {n : nat} (z : Z) :
503507
(0 <= z < 2%:R ^+ n.+1)%R -> mkword n.+1 z = z :> Z.
504508
Proof.
505-
move=> rg; rewrite /= Zmod_small // modulusE.
509+
move=> rg; rewrite /= zmod_pow2E -(modulusZE n.+1) Zmod_small // modulusE.
506510
by rewrite !(rwP lezP, rwP ltzP) (rwP andP).
507511
Qed.
508512

@@ -529,7 +533,7 @@ Proof. by apply/val_eqP. Qed.
529533
(* ==================================================================== *)
530534
Lemma addwE {n} (w1 w2 : n.-word) :
531535
urepr (w1 + w2)%R = ((urepr w1 + urepr w2)%R mod modulus n)%Z.
532-
Proof. by []. Qed.
536+
Proof. by rewrite /urepr /= zmod_pow2E -modulusZE. Qed.
533537

534538
Lemma subwE {n} (w1 w2 : n.-word) :
535539
urepr (w1 - w2)%R = ((urepr w1 - urepr w2)%R mod modulus n)%Z.
@@ -549,6 +553,7 @@ have /= {nz_w2} gt0_w2: (0%R < val w2)%R.
549553
apply/contra_neq: nz_w2; pose z : n.-word := 0%R.
550554
by rewrite [X in val _ = X](_ : _ = val z) // => /val_inj.
551555
rewrite /GRing.opp /GRing.add /= /add_word /opp_word /urepr /=.
556+
rewrite !zmod_pow2E -modulusZE.
552557
rewrite Zplus_mod_idemp_r !(oppZE, addZE).
553558
case: ltrP; rewrite (addr0, mulr1n); last first.
554559
+ move=> le_w2_w1; rewrite Z.mod_small //; split.
@@ -565,7 +570,7 @@ Qed.
565570

566571
Lemma mulwE {n} (w1 w2 : n.-word) :
567572
urepr (mul_word w1 w2)%R = ((urepr w1 * urepr w2)%R mod modulus n)%Z.
568-
Proof. by []. Qed.
573+
Proof. by rewrite /urepr /= zmod_pow2E -modulusZE. Qed.
569574

570575
(* -------------------------------------------------------------------- *)
571576
Lemma word_sz_eq0 {n} (w : n.-word) : n = 0 -> w = 0%R.
@@ -906,6 +911,7 @@ Lemma sreprK : cancel srepr (mkword n).
906911
Proof.
907912
rewrite /srepr => w; case: ifP => _; last exact/ureprK.
908913
apply/val_eqP/eqP; case: w => w /=.
914+
rewrite zmod_pow2E -modulusZE.
909915
rewrite -mulrN1 mulrC -mulZE -addZE Z_mod_plus_full.
910916
move/andP; rewrite -!(rwP ltzP, rwP lezP) => h.
911917
by rewrite Z.mod_small.
@@ -973,7 +979,11 @@ Qed.
973979

974980
Lemma wsplit2_subproof (w : n.*2.-word) :
975981
isword n (Z.div_eucl w (modulus n)).2.
976-
Proof. by rewrite [_.2](_ : _ = (w mod modulus n)%Z) ?mkword_proof. Qed.
982+
Proof.
983+
have := mkword_proof n w.
984+
rewrite zmod_pow2E modulusZE.
985+
exact.
986+
Qed.
977987

978988
Definition wsplit (w : n.*2.-word) :=
979989
let w' := Z.div_eucl w (modulus n) in
@@ -1089,7 +1099,7 @@ Proof. by rewrite /wbit Z.lxor_spec /=; do 2! case: Z.testbit. Qed.
10891099

10901100
Lemma wN1E i : wbit (mkword n (-1)) i = (i < n).
10911101
Proof.
1092-
rewrite /wbit /= /modulus two_power_nat_equiv.
1102+
rewrite /wbit /= zmod_pow2E.
10931103
have hi := Nat2Z.is_nonneg i.
10941104
have hn := Nat2Z.is_nonneg n.
10951105
have Hn : (0 < 2 ^ Z.of_nat n)%Z.

src/word_ssrZ.v

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,3 +427,73 @@ move=> ge0_z; have : injective nat_of_bool by move=> [] [].
427427
apply; rewrite -modn2; apply/Nat2Z.inj; rewrite modnZE //.
428428
by rewrite Z2Nat.id ?(rwP lezP) // Zmod_odd; case: ifP.
429429
Qed.
430+
431+
(* -------------------------------------------------------------------- *)
432+
(* Truncate a positive to its n least significant bits *)
433+
Fixpoint mod_pow2 (p: positive) (n: nat) {struct n} : N :=
434+
(if n is n.+1 then
435+
match p with
436+
| p~0 => Pos.Ndouble (mod_pow2 p n)
437+
| p~1 => Pos.Nsucc_double (mod_pow2 p n)
438+
| 1 => 1%N
439+
end%positive
440+
else 0)%N.
441+
442+
Definition zmod_pow2 (z: Z) (n: nat) : Z :=
443+
match z with
444+
| 0 => 0
445+
| Zpos p => Z.of_N (mod_pow2 p n)
446+
| Zneg p =>
447+
match mod_pow2 p n with
448+
| N0 => 0
449+
| Npos p => two_power_nat n - Zpos p
450+
end
451+
end.
452+
453+
Local Opaque Z.mul Z.sub.
454+
455+
Lemma pos_mod_double p m :
456+
(Npos p~0 mod Npos m~0 = 2 * (Npos p mod Npos m))%N.
457+
Proof.
458+
apply: N2Z.inj.
459+
by rewrite N2Z.inj_mul !N2Z.inj_mod /= (Pos2Z.inj_xO p) (Pos2Z.inj_xO m) Zmult_mod_distr_l.
460+
Qed.
461+
462+
Lemma pos_mod_succ_double p m :
463+
(Npos p~1 mod Npos m~0 = 2 * (Npos p mod Npos m) + 1)%N.
464+
Proof.
465+
apply: N2Z.inj.
466+
rewrite N2Z.inj_add N2Z.inj_mul !N2Z.inj_mod /= (Pos2Z.inj_xI p) (Pos2Z.inj_xO m).
467+
rewrite Zplus_mod Z.mod_1_l. 2: Lia.lia.
468+
rewrite Zmult_mod_distr_l.
469+
apply: Z.mod_small.
470+
have := Z.mod_pos_bound (Zpos p) (Zpos m).
471+
Lia.lia.
472+
Qed.
473+
474+
Lemma mod_pow2E p n :
475+
(mod_pow2 p n = Npos p mod Npos (shift_nat n 1))%N.
476+
Proof.
477+
elim: n p.
478+
+ by move => p; rewrite N.mod_1_r.
479+
move => n ih [ p | p | ] /=; last by rewrite N.mod_1_l.
480+
+ rewrite pos_mod_succ_double -ih; Lia.lia.
481+
rewrite pos_mod_double -ih; Lia.lia.
482+
Qed.
483+
484+
Lemma zmod_pow2E z n :
485+
zmod_pow2 z n = z mod 2 ^ Z.of_nat n.
486+
Proof.
487+
case: z => [ // | p | p ] /=.
488+
+ by rewrite mod_pow2E N2Z.inj_mod /= shift_nat_correct Z.mul_1_r Zpower_nat_Z.
489+
have ? : 2 ^ Z.of_nat n <> 0 by Lia.lia.
490+
case: mod_pow2 (mod_pow2E p n) => [ | q ] /N2Z.inj_iff h.
491+
+ rewrite (Z.mod_opp_l_z (Zpos p)) //.
492+
by move: h; rewrite N2Z.inj_mod /= shift_nat_correct Z.mul_1_r Zpower_nat_Z.
493+
rewrite /two_power_nat.
494+
move: h; rewrite N2Z.inj_mod /= shift_nat_correct Zpower_nat_Z Z.mul_1_r => h.
495+
rewrite (Z.mod_opp_l_nz (Zpos p)) //; last Lia.lia.
496+
by rewrite h.
497+
Qed.
498+
499+
Global Opaque zmod_pow2.

0 commit comments

Comments
 (0)