1 /* Genus 2 divisor group law via explicit formulas.
3 Divisor addition: Algorithm 14.19 of "Handbook of EAHCC"
5 Divisor doubling: Algorithm 14.21 of "Handbook of EAHCC"
7 Special cases are handled by calling add_cantor()
16 #include <g2hec_Genus2_ops.h>
20 static bool_t add_diff(divisor& x, const divisor& a, const divisor& b)
21 // x = a + b where a != b via explicit formulas
22 // c.f. Algorithm 14.9 of HOEHCC
23 // Assumes upolys of a and b are both of degree 2 and have no common
27 We choose to use local variables for now to make the function thread safe.
28 Note that this may affect the performance of the program as opposed to
29 the method of passing along the temporary variables.
34 const field_t f4 = coeff(a.get_curve().get_f(), 4),
35 h1 = coeff(a.get_curve().get_h(), 1),
36 h2 = coeff(a.get_curve().get_h(), 2),
37 h0 = coeff(a.get_curve().get_h(), 0),
38 u11 = coeff(a.get_upoly(), 1), u10 = coeff(a.get_upoly(), 0),
39 u21 = coeff(b.get_upoly(), 1), u20 = coeff(b.get_upoly(), 0),
40 v11 = coeff(a.get_vpoly(), 1), v10 = coeff(a.get_vpoly(), 0),
41 v21 = coeff(b.get_vpoly(), 1), v20 = coeff(b.get_vpoly(), 0);
43 field_t z1, z2, z3, z4, r, inv1, inv0, w0, w1, w2, w3, s1p, s0p,
44 w4, w5, s0pp, l2p, l1p, l0p, u0p, u1p, v1p, v0p;
48 /* Explicit formulas */
51 Compute r = Res(u1, u2).
52 z1 = u11 - u21, z2 = u20 - u10, z3 = u11*z1 + z2, z4 = z1*u10,
61 assert(!IsZero(r)); // Res(u1, u2)<>0, i.e., GCD(u1, u2) = 1
70 w0 = v10 - v20, w1 = v11 - v21, w2 = inv0*w0, w3 = inv1*w1,
71 s1p = (inv0 + inv1)*(w0 + w1) - w2 - w3*(1 + u11), s0p = w2 - z4*w1
72 If s1p = 0, handled by Cantor's algorithm.
78 s1p = (inv0 + inv1)*(w0 + w1) - w2 - w3*(1 + u11);
82 return add_cantor(x, a, b);
88 w1 = 1/(r*s1p), w2 = r*w1, w3 = s1p^2*w1, w4 = r*w2, w5 = w4^2,
99 l2p = u21 + s0pp, l1p = u21*s0pp + u20, l0p = u20*s0pp
102 l1p = u21*s0pp + u20;
106 u0p = (s0pp - u11)*(s0pp - z1 + h2*w4) - u10,
107 u0p = u0p + l1p + (h1 + 2*v21)*w4 + (2*u21 + z1 - f4)*w5,
108 u1p = 2*s0pp - z1 + h2*w4 - w5
110 u0p = (s0pp - u11)*(s0pp - z1 + h2*w4) - u10;
111 u0p = u0p + l1p + (h1 + 2*v21)*w4 + (2*u21 + z1 - f4)*w5;
112 u1p = 2*s0pp - z1 + h2*w4 - w5;
115 w1 = l2p - u1p, w2 = u1p*w1 + u0p - l1p, v1p = w2*w3 - v21 - h1 + h2*u1p,
116 w2 = u0p*w1 - l0p, v0p = w2*w3 - v20 - h0 + h2*u0p
119 w2 = u1p*w1 + u0p - l1p;
120 v1p = w2*w3 - v21 - h1 + h2*u1p;
122 v0p = w2*w3 - v20 - h0 + h2*u0p;
125 return [up, vp] = [x^2 + u1p*x + u0p, v1p*x + v0p]
128 SetCoeff(up, 1, u1p);
129 SetCoeff(up, 0, u0p);
131 SetCoeff(vp, 1, v1p);
132 SetCoeff(vp, 0, v0p);
140 cout << "Entered add_diff()" << endl;
144 assert(OK = ( OK && x.is_valid_divisor()) );
149 static bool_t doubling(divisor& x, const divisor& a)
150 // x = a + a via explicit formulas
153 We choose to use local variables for now to make the function thread safe.
154 Note that this may affect the performance of the program as opposed to
155 the method of passing along the temporary variables.
161 const field_t f4 = coeff(a.get_curve().get_f(), 4),
162 f3 = coeff(a.get_curve().get_f(), 3),
163 f2 = coeff(a.get_curve().get_f(), 2),
164 h1 = coeff(a.get_curve().get_h(), 1),
165 h2 = coeff(a.get_curve().get_h(), 2),
166 h0 = coeff(a.get_curve().get_h(), 0),
167 u1 = coeff(a.get_upoly(), 1), u0 = coeff(a.get_upoly(), 0),
168 v1 = coeff(a.get_vpoly(), 1), v0 = coeff(a.get_vpoly(), 0);
170 field_t v1t, v0t, w0, w1, w2, w3, r, inv1p, inv0p, w4, t1p, t0p, s1p,
171 s0p, w5, s0pp, l2p, l1p, l0p, u0p, u1p, v1p, v0p;
175 /* Explicit formulas */
178 v1t = h1 + 2*v1 - h2*u1, v0t = h0 + 2*v0 - h2*u0
180 v1t = h1 + 2*v1 - h2*u1;
181 v0t = h0 + 2*v0 - h2*u0;
184 w0 = v1^2, w1 = u1^2, w2 = v1t^2, w3 = u1*v1t,
185 r = u0*w2 + v0t*(v0t - w3)
191 r = u0*w2 + v0t*(v0t - w3);
195 inv1p = -v1t, inv0p = v0t - w3
201 w3 = f3 + w1, w4 = 2*u0, t1p = 2*(w1 - f4*u1) + w3 - w4 - h2*v1,
202 t0p = u1*(2*w4 - w3 + f4*u1 + h2*v1) + f2 - w0 - 2*f4*u0 - h1*v1 - h2*v0
206 t1p = 2*(w1 - f4*u1) + w3 - w4 - h2*v1;
207 t0p = u1*(2*w4 - w3 + f4*u1 + h2*v1) + f2 - w0 - 2*f4*u0 - h1*v1 - h2*v0;
210 w0 = t0p*inv0p, w1 = t1p*inv1p,
211 s1p = (inv0p + inv1p)*(t0p + t1p) - w0 - w1*(1+u1),
214 If s1p = 0, call add_cantor().
218 s1p = (inv0p + inv1p)*(t0p + t1p) - w0 - w1*(1+u1);
221 cout << "r = " << r << endl;
222 cout << "s1p = " << s1p << endl;
227 return add_cantor(x, a, a);
232 w1 = 1/(r*s1p), w2 = r*w1, w3 = s1p^2*w1, w4 = r*w2, w5 = w4^2,
243 l2p = u1 + s0pp, l1p = u1*s0pp + u0, l0p = u0*s0pp
250 u0p = s0pp^2 + w4*(h2*(s0pp - u1) + 2*v1 + h1) + w5*(2*u1 - f4),
251 u1p = 2*s0pp + h2*w4 - w5
253 u0p = sqr(s0pp) + w4*(h2*(s0pp - u1) + 2*v1 + h1) + w5*(2*u1 - f4);
254 u1p = 2*s0pp + h2*w4 - w5;
257 w1 = l2p - u1p, w2 = u1p*w1 + u0p - l1p, v1p = w2*w3 - v1 - h1 + h2*u1p,
258 w2 = u0p*w1 - l0p, v0p = w2*w3 - v0 - h0 + h2*u0p
261 w2 = u1p*w1 + u0p - l1p;
262 v1p = w2*w3 - v1 - h1 + h2*u1p;
264 v0p = w2*w3 - v0 - h0 + h2*u0p;
270 SetCoeff(up, 1, u1p);
271 SetCoeff(up, 0, u0p);
273 SetCoeff(vp, 1, v1p);
274 SetCoeff(vp, 0, v0p);
282 cout << "Entered doubling(). " << endl;
283 // cout << x << endl;
286 assert(OK = OK && x.is_valid_divisor());
290 bool_t add(divisor& x, const divisor& a, const divisor& b)
291 // This subroutine wraps other functions that does the actual
292 // divisor arithmetic. It checks the validity of input divisors
293 // so that other subroutines it calls do not need to do so.
298 /* Reduce overhead of checking with NDEBUG flag */
299 assert(OK = OK && a.is_valid_divisor() && b.is_valid_divisor());
301 if (deg(a.get_upoly()) == genus && deg(b.get_upoly()) == genus) {
309 if (a != b && IsOne(GCD(a.get_upoly(), b.get_upoly()))) {
311 OK = OK && add_diff(x, a, b);
314 } else if (a == b && IsOne(GCD(a.get_curve().get_h() +
315 2*a.get_vpoly(), a.get_upoly())) ) {
317 // Exclude the case when one point of the divisor is equal to
320 OK = OK && doubling(x, a);
327 // Call add_cantor() to handle other cases
328 OK = OK && add_cantor(x, a, b);