summaryrefslogtreecommitdiff
path: root/patches/gmp/5.1.1/120-fix-mpn_sbpi1_div_qr_sec.patch
blob: 13a50ad43e57248c123546d8ad5204c4edb62827 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# HG changeset patch
# User Torbjorn Granlund <tege@gmplib.org>
# Date 1373624469 -7200
# Node ID a447c0c537891ed23edf180594a89616364ee633
# Parent  6540e0b2925ead29f7158bb182e4fabfb9441433
Partial rewrite.

diff -r 6540e0b2925e -r a447c0c53789 mpn/generic/sbpi1_div_sec.c
--- a/mpn/generic/sbpi1_div_sec.c	Mon Jul 01 19:16:32 2013 +0200
+++ b/mpn/generic/sbpi1_div_sec.c	Fri Jul 12 12:21:09 2013 +0200
@@ -8,7 +8,7 @@
    SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
    GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
 
-Copyright 2011, 2012 Free Software Foundation, Inc.
+Copyright 2011, 2012, 2013 Free Software Foundation, Inc.
 
 This file is part of the GNU MP Library.
 
@@ -29,6 +29,28 @@
 #include "gmp-impl.h"
 #include "longlong.h"
 
+/* This side-channel silent division algorithm reduces the partial remainder by
+   GMP_NUMB_BITS/2 bits at a time, compared to GMP_NUMB_BITS for the main
+   division algorithm.  We do not insists on reducing by exactly
+   GMP_NUMB_BITS/2, but may leave a partial remainder that is D*B^i to 3D*B^i
+   too large (B is the limb base, D is the divisor, and i is the induction
+   variable); the subsequent step will handle the extra partial remainder bits.
+
+   WIth that partial remainder reduction, each step generates a quotient "half
+   limb".  The outer loop generates two quotient half limbs, an upper (q1h) and
+   a lower (q0h) which are stored sparsely in separate limb arrays.  These
+   arrays are added at the end; using separate arrays avoids data-dependent
+   carry propagation which could else pose a side-channel leakage problem.
+
+   The quotient half limbs may be between -3 to 0 from the accurate value
+   ("accurate" being the one which corresponds to a reduction to a principal
+   partial remainder).  Too small quotient half limbs correspond to too large
+   remainders, which we reduce later, as described above.
+
+   In order to keep quotients from getting too big, corresponding to a negative
+   partial remainder, we use an inverse which is sligtly smaller than usually.
+*/
+
 #if OPERATION_sbpi1_div_qr_sec
 /* Needs (dn + 1) + (nn - dn) + (nn - dn) = 2nn - dn + 1 limbs at tp. */
 #define FNAME mpn_sbpi1_div_qr_sec
@@ -49,7 +71,7 @@
        mp_limb_t dinv,
        mp_ptr tp)
 {
-  mp_limb_t nh, cy, q1h, q0h, dummy, h;
+  mp_limb_t nh, cy, q1h, q0h, dummy, cnd;
   mp_size_t i;
   mp_ptr hp;
 #if OPERATION_sbpi1_div_qr_sec
@@ -72,77 +94,69 @@
 #endif
     }
 
+  /* Decremenet inverse to keep quotient half limbs from being too large.  */
+  dinv -= dinv != 0;				/* FIXME: cmp-to-int */
+
   /* Create a divisor copy shifted half a limb.  */
   hp = tp;					/* (dn + 1) limbs */
-  cy = mpn_lshift (hp, dp, dn, GMP_NUMB_BITS / 2);
-  hp[dn] = dp[dn - 1] >> GMP_NUMB_BITS / 2;
+  hp[dn] = mpn_lshift (hp, dp, dn, GMP_NUMB_BITS / 2);
 
 #if OPERATION_sbpi1_div_qr_sec
   qlp = tp + (dn + 1);				/* (nn - dn) limbs */
   qhp = tp + (nn + 1);				/* (nn - dn) limbs */
 #endif
 
-  np += nn;
+  np += nn - dn;
+  nh = 0;
 
-  /* Main loop.  Develop one full limb per iteration, but do it in two steps in
-     order to avoid conditionals.  Quotient bits will be either correct or
-     underestimates.  When a quotient is underestimated, the next quotient will
-     compensate, since quotients are to be added at consecutive weight distance
-     GMP_NUMB_BITS/2.  We make two quotient arrays, each with GMP_NUMB_BITS/2+2
-     bits per entry.  The arrays are added late after the loop.  Separate
-     arrays avoid data-dependent carry propagation.  */
-  nh = 0;
   for (i = nn - dn - 1; i >= 0; i--)
     {
       np--;
 
-      nh = (nh << GMP_NUMB_BITS/2) + (np[0] >> GMP_NUMB_BITS/2);
+      nh = (nh << GMP_NUMB_BITS/2) + (np[dn] >> GMP_NUMB_BITS/2);
       umul_ppmm (q1h, dummy, nh, dinv);
       q1h += nh;
 #if OPERATION_sbpi1_div_qr_sec
       qhp[i] = q1h;
 #endif
-      cy = mpn_submul_1 (np - dn, hp, dn + 1, q1h);
+      mpn_submul_1 (np, hp, dn + 1, q1h);
 
-      nh = np[0];
+      nh = np[dn];
       umul_ppmm (q0h, dummy, nh, dinv);
       q0h += nh;
 #if OPERATION_sbpi1_div_qr_sec
       qlp[i] = q0h;
 #endif
-      cy = mpn_submul_1 (np - dn, dp, dn, q0h);
-
-      nh -= cy;
+      nh -= mpn_submul_1 (np, dp, dn, q0h);
     }
 
-  np[0] = nh;
-
-  np -= dn;
-
   /* 1st adjustment depends on extra high remainder limb.  */
-  h = np[dn];
+  cnd = nh != 0;				/* FIXME: cmp-to-int */
 #if OPERATION_sbpi1_div_qr_sec
-  qlp[0] += h;
+  qlp[0] += cnd;
 #endif
-  h -= mpn_subcnd_n (np, np, dp, dn, h);
+  nh -= mpn_subcnd_n (np, np, dp, dn, cnd);
 
-  /* 2nd adjustment depends on remainder/divisor comparision as well as whether
+  /* 2nd adjustment depends on remainder/divisor comparison as well as whether
      extra remainder limb was nullified by previous subtract.  */
   cy = mpn_sub_n (np, np, dp, dn);
-  cy = cy == h;				/* FIXME: might leak on some archs */
+  cy = cy - nh;
 #if OPERATION_sbpi1_div_qr_sec
-  qlp[0] += cy;
+  qlp[0] += 1 - cy;
 #endif
-  mpn_addcnd_n (np, np, dp, dn, 1 - cy);
+  mpn_addcnd_n (np, np, dp, dn, cy);
 
+  /* 3rd adjustment depends on remainder/divisor comparison.  */
+  cy = mpn_sub_n (np, np, dp, dn);
+#if OPERATION_sbpi1_div_qr_sec
+  qlp[0] += 1 - cy;
+#endif
+  mpn_addcnd_n (np, np, dp, dn, cy);
+
+#if OPERATION_sbpi1_div_qr_sec
   /* Combine quotient halves into final quotient.  */
-#if OPERATION_sbpi1_div_qr_sec
-  qh = 0;
-  if (nn - dn != 0)
-    {
-      qh = mpn_lshift (qhp, qhp, nn - dn, GMP_NUMB_BITS/2);
-      qh += mpn_add_n (qp, qhp, qlp, nn - dn);
-    }
+  qh = mpn_lshift (qhp, qhp, nn - dn, GMP_NUMB_BITS/2);
+  qh += mpn_add_n (qp, qhp, qlp, nn - dn);
 
   return qh;
 #else