/* computation of $c <- U ^ {3^m+1}$, $U \in T_2(F_{3^3M})$ * This is the algorithm 7 in the paper above. */ static void algorithm7(element_t c, element_t u) { element_ptr u0 = ITEM(u,0,0), u1 = ITEM(u,0,1), u2 = ITEM(u,1,0), u3 = ITEM(u,1,1), u4 = ITEM(u,2,0), u5 = ITEM(u,2,1); field_ptr f = FIELD(u0); /*GF(3^m)*/ params *p = PARAM(u0); element_t a0, a1, a2, a3, a4, a5, a6, m0, m1, m2, m3, m4, m5, m6, m7, m8, v0, v1, v2, v3, v4, v5, e1; element_init(a0, f); element_init(a1, f); element_init(a2, f); element_init(a3, f); element_init(a4, f); element_init(a5, f); element_init(a6, f); element_init(m0, f); element_init(m1, f); element_init(m2, f); element_init(m3, f); element_init(m4, f); element_init(m5, f); element_init(m6, f); element_init(m7, f); element_init(m8, f); element_init(v0, f); element_init(v1, f); element_init(v2, f); element_init(v3, f); element_init(v4, f); element_init(v5, f); element_init(e1, f); element_set1(e1); element_add(a0, u0, u1); element_add(a1, u2, u3); element_sub(a2, u4, u5); element_mul(m0, u0, u4); element_mul(m1, u1, u5); element_mul(m2, u2, u4); element_mul(m3, u3, u5); element_mul(m4, a0, a2); element_mul(m5, u1, u2); element_mul(m6, u0, u3); element_mul(m7, a0, a1); element_mul(m8, a1, a2); element_add(a3, m5, m6); element_sub(a3, a3, m7); element_neg(a4, m2); element_sub(a4, a4, m3); element_sub(a5, m3, m2); element_sub(a6, m1, m0); element_add(a6, a6, m4); if (p->m % 6 == 1) { element_add(v0, m0, m1); element_add(v0, v0, a4); element_add(v0, e1, v0); element_sub(v1, m5, m6); element_add(v1, v1, a6); element_sub(v2, a4, a3); element_add(v3, m8, a5); element_sub(v3, v3, a6); element_add(v4, a3, a4); element_neg(v4, v4); element_add(v5, m8, a5); } else { // p->m % 6 == 5 element_add(v0, m0, m1); element_sub(v0, v0, a4); element_add(v0, e1, v0); element_sub(v1, m6, m5); element_add(v1, v1, a6); element_set(v2, a3); element_add(v3, m8, a5); element_add(v3, v3, a6); element_add(v4, a3, a4); element_neg(v4, v4); element_add(v5, m8, a5); element_neg(v5, v5); } element_set(ITEM(c,0,0), v0); element_set(ITEM(c,0,1), v1); element_set(ITEM(c,1,0), v2); element_set(ITEM(c,1,1), v3); element_set(ITEM(c,2,0), v4); element_set(ITEM(c,2,1), v5); element_clear(a0); element_clear(a1); element_clear(a2); element_clear(a3); element_clear(a4); element_clear(a5); element_clear(a6); element_clear(m0); element_clear(m1); element_clear(m2); element_clear(m3); element_clear(m4); element_clear(m5); element_clear(m6); element_clear(m7); element_clear(m8); element_clear(v0); element_clear(v1); element_clear(v2); element_clear(v3); element_clear(v4); element_clear(v5); element_clear(e1); }
/* $c <- a-b$ */ static void gf32m_sub(element_t c, element_t a, element_t b) { element_ptr a0 = GF32M(a)->_0, a1 = GF32M(a)->_1, b0 = GF32M(b)->_0, b1 = GF32M(b)->_1, c0 = GF32M(c)->_0, c1 = GF32M(c)->_1; element_sub(c0, a0, b0); element_sub(c1, a1, b1); }
/* this is the algorithm 4 in the paper of J.Beuchat et.al, "Algorithms and Arithmetic Operators for Computing * the $eta_T$ Pairing in Characteristic Three" */ static void algorithm4(element_t c, element_ptr xp, element_ptr yp, element_ptr xq, element_ptr yq) { params *p = PARAM(xp); unsigned int re = p->m % 12; field_ptr f = FIELD(xp) /*GF(3^m)*/, f6 = FIELD(c) /*GF(3^{6*m})*/; element_t e1, xpp, ypp, xqq, yqq, t, nt, nt2, v1, v2, a1, a2, R, u, S; element_init(e1, f); element_init(xpp, f); element_init(ypp, f); element_init(xqq, f); element_init(yqq, f); element_init(t, f); element_init(nt, f); element_init(nt2, f); element_init(v1, f); element_init(v2, f); element_init(a1, f6); element_init(a2, f6); element_init(R, f6); element_init(u, f); element_init(S, f6); element_set1(e1); element_set(xpp, xp); xp = xpp; // clone element_add(xp, xp, e1); // xp == xp + b element_set(ypp, yp); yp = ypp; // clone if (re == 1 || re == 11) element_neg(yp, yp); // yp == -\mu*b*yp, \mu == 1 when re==1, or 11 element_set(xqq, xq); xq = xqq; // clone element_cubic(xq, xq); // xq == xq^3 element_set(yqq, yq); yq = yqq; // clone element_cubic(yq, yq); // yq == yq^3 element_add(t, xp, xq); // t == xp+xq element_neg(nt, t); // nt == -t element_mul(nt2, t, nt); // nt2 == -t^2 element_mul(v2, yp, yq); // v2 == yp*yq element_mul(v1, yp, t); // v1 == yp*t if (re == 7 || re == 11) { // \lambda == 1 element_t nyp, nyq; element_init(nyp, f); element_init(nyq, f); element_neg(nyp, yp); // nyp == -yp element_neg(nyq, yq); // nyq == -yq element_set(ITEM(a1,0,0), v1); element_set(ITEM(a1,0,1), nyq); element_set(ITEM(a1,1,0), nyp); element_clear(nyp); element_clear(nyq); } else { // \lambda == -1 element_neg(v1, v1); // v1 == -yp*t element_set(ITEM(a1,0,0), v1); element_set(ITEM(a1,0,1), yq); element_set(ITEM(a1,1,0), yp); } // a2 == -t^2 +yp*yq*s -t*p -p^2 element_set(ITEM(a2,0,0), nt2); element_set(ITEM(a2,0,1), v2); element_set(ITEM(a2,1,0), nt); element_neg(ITEM(a2,2,0), e1); element_mul(R, a1, a2); int i; for (i = 0; i < (p->m - 1) / 2; i++) { element_cubic(R, R); element_cubic(xq, xq); element_cubic(xq, xq); element_sub(xq, xq, e1); // xq <= xq^9-b element_cubic(yq, yq); element_cubic(yq, yq); element_neg(yq, yq); // yq <= -yq^9 element_add(t, xp, xq); // t == xp+xq element_neg(nt, t); // nt == -t element_mul(nt2, t, nt); // nt2 == -t^2 element_mul(u, yp, yq); // u == yp*yq element_set0(S); element_set(ITEM(S,0,0), nt2); element_set(ITEM(S,0,1), u); element_set(ITEM(S,1,0), nt); element_neg(ITEM(S,2,0), e1); element_mul(R, R, S); } element_set(c, R); element_clear(e1); element_clear(xpp); element_clear(ypp); element_clear(xqq); element_clear(yqq); element_clear(t); element_clear(nt); element_clear(nt2); element_clear(v1); element_clear(v2); element_clear(a1); element_clear(a2); element_clear(R); element_clear(u); element_clear(S); }
//============================================ // 四則演算のテストプログラム //============================================ void test_arithmetic_operation(Field f) { int i; unsigned long long int t1, t2; Element a, b, c, d; char loop[] = "100"; mpz_t e, exp; //-------------------- // init //-------------------- element_init(a, f); element_init(b, f); element_init(c, f); element_init(d, f); //-------------------- // add //-------------------- element_set_str(a, "1C12C39A2AD14054EDC9EE504301127AFFEEAADC59A78B50FCFFED87AC6EB8BF 20E1A922384561EA82602CD664D85D442DAC5D391E142ABB3CFEC2A095C22DF9"); element_set_str(b, "F1B91250A124F268B8239185B23B31EB25179A11A9A0398E61B701F7D4F7265 20D206C5F7D007EDBA34A4B041622289D64F04CA28CEAC490619585AA14F7B2F"); element_set_str(d, "7BD59BA97A27FBD2AD60CD0173FC358353DE53D5C418EE8649AFDA729BE2B23 1E42B4E392D45A19EE1EB6EE1F557D8C86F922C32EE2D702C497BAFB3711A927"); element_add(c, a, b); assert(element_cmp(c, d) == 0); t1 = rdtsc(); for (i = 0; i < N; i++) { element_add(c, a, b); } t2 = rdtsc(); printf("element add: %.2lf [clock]\n", (double)(t2 - t1) / N); //-------------------- // sub //-------------------- element_set(d, c); element_sub(c, c, d); assert(element_is_zero(c)); //-------------------- // mul //-------------------- element_mul(c, a, b); element_set_str(d, "1D0562FF0AB317FFDE555320A7072D2B29C07077E08996CE5F093BB8E4200B2C 9B04361A24DC7F37C8BD09A7C51A9D8577168AD021BF2B4AC3D67552F481B1A"); assert(element_cmp(c, d) == 0); t1 = rdtsc(); for (i = 0; i < N; i++) { element_mul(c, a, b); } t2 = rdtsc(); printf("element mul: %.2lf [clock]\n", (double)(t2 - t1) / N); mpz_init_set_str(e, "1B45F16C848B9C476C1D2FF1FD60A0D0C19BBA6F3ECE3CF6C5FCE4FAB7CAD4FF", 16); element_pow(c, a, e); element_set_str(d, "B40190CE812CB4F668A839952128D19B1748F3BB19E902480D089AF9053A6D2 19DA59F09C3C20472C3BD19A4FC95BCAF266B9D1539AAD23E3C67C4F3A7CA51D"); assert(element_cmp(c, d) == 0); mpz_clear(e); //-------------------- // sqr //-------------------- element_sqr(c, a); element_mul(d, a, a); assert(element_cmp(c, d) == 0); t1 = rdtsc(); for (i = 0; i < N; i++) { element_sqr(c, a); } t2 = rdtsc(); printf("element sqr: %.2lf [clock]\n", (double)(t2 - t1) / N); //-------------------- // random //-------------------- element_random(a); element_random(b); //-------------------- // inv //-------------------- element_mul(c, a, b); element_inv(b, b); element_mul(c, c, b); element_inv(d, a); element_mul(d, a, d); assert(element_cmp(c, a) == 0); assert(element_is_one(d)); t1 = rdtsc(); for (i = 0; i < N; i++) { element_inv(b, a); } t2 = rdtsc(); printf("element inv: %.2lf [clock]\n", (double)(t2 - t1) / N); //-------------------- // pow //-------------------- mpz_init_set_str(exp, loop, 10); element_set_one(b); for (i = 0; i < atoi(loop); i++) { element_mul(b, b, a); } element_pow(c, a, exp); assert(element_cmp(b, c) == 0); mpz_set(exp, f->order); for (i = 0; i < 100; i++) { element_random(a); element_pow(b, a, exp); assert(element_cmp(b, a) == 0); } t1 = rdtsc(); for (i = 0; i < N; i++) { element_pow(b, a, exp); } t2 = rdtsc(); printf("element pow with order: %.2lf [clock]\n", (double)(t2 - t1) / N); mpz_clear(exp); //-------------------- // clear //-------------------- element_clear(a); element_clear(b); element_clear(c); element_clear(d); }
//compute c_i=a_i+b_i at one time. static void multi_add(element_ptr c[], element_ptr a[], element_ptr b[], int n){ int i; element_t* table = (element_t*)pbc_malloc(sizeof(element_t)*n); //a big problem? point_ptr p, q, r; element_t e0, e1, e2; curve_data_ptr cdp = (curve_data_ptr)a[0]->field->data; p = (point_ptr)a[0]->data; q = (point_ptr)b[0]->data; element_init(e0, p->x->field); element_init(e1, p->x->field); element_init(e2, p->x->field); element_init(table[0], p->x->field); element_sub(table[0], q->x, p->x); for(i=1; i<n; i++){ p = (point_ptr)a[i]->data; q = (point_ptr)b[i]->data; element_init(table[i], p->x->field); element_sub(table[i], q->x, p->x); element_mul(table[i], table[i], table[i-1]); } element_invert(e2, table[n-1]); for(i=n-1; i>0; i--){ p = (point_ptr)a[i]->data; q = (point_ptr)b[i]->data; element_mul(table[i], table[i-1], e2); element_sub(e1, q->x, p->x); element_mul(e2,e2,e1); //e2=e2*(x2_j-x1_j) } element_set(table[0],e2); //e2 no longer used. for(i=0; i<n; i++){ p = (point_ptr)a[i]->data; q = (point_ptr)b[i]->data; r = (point_ptr)c[i]->data; if (p->inf_flag) { curve_set(c[i], b[i]); continue; } if (q->inf_flag) { curve_set(c[i], a[i]); continue; } if (!element_cmp(p->x, q->x)) { //a[i]=b[i] if (!element_cmp(p->y, q->y)) { if (element_is0(p->y)) { r->inf_flag = 1; continue; } else { double_no_check(r, p, cdp->a); continue; } } //points are inverses of each other r->inf_flag = 1; continue; } else { //lambda = (y2-y1)/(x2-x1) element_sub(e2, q->y, p->y); element_mul(e2, e2, table[i]); //x3 = lambda^2 - x1 - x2 element_square(e0, e2); element_sub(e0, e0, p->x); element_sub(e0, e0, q->x); //y3 = (x1-x3)lambda - y1 element_sub(e1, p->x, e0); element_mul(e1, e1, e2); element_sub(e1, e1, p->y); element_set(r->x, e0); element_set(r->y, e1); r->inf_flag = 0; } } element_clear(e0); element_clear(e1); element_clear(e2); for(i=0; i<n; i++){ element_clear(table[i]); } pbc_free(table); }
//compute c_i=a_i+a_i at one time. static void multi_double(element_ptr c[], element_ptr a[], int n) { int i; element_t* table = (element_t*)pbc_malloc(sizeof(element_t)*n); //a big problem? element_t e0, e1, e2; point_ptr q, r; curve_data_ptr cdp = (curve_data_ptr)a[0]->field->data; q = (point_ptr)a[0]->data; element_init(e0,q->y->field); element_init(e1,q->y->field); element_init(e2,q->y->field); for(i=0; i<n; i++){ q = (point_ptr)a[i]->data; r = (point_ptr)c[i]->data; element_init(table[i],q->y->field); if (q->inf_flag) { r->inf_flag = 1; continue; } if (element_is0(q->y)) { r->inf_flag = 1; continue; } } //to compute 1/2y multi. see Cohen's GTM139 Algorithm 10.3.4 for(i=0; i<n; i++){ q = (point_ptr)a[i]->data; element_double(table[i],q->y); if(i>0) element_mul(table[i],table[i],table[i-1]); } element_invert(e2,table[n-1]); //ONLY ONE inv is required now. for(i=n-1; i>0; i--){ q = (point_ptr)a[i]->data; element_mul(table[i],table[i-1],e2); element_mul(e2,e2,q->y); element_double(e2,e2); //e2=e2*2y_j } element_set(table[0],e2); //e2 no longer used. for(i=0; i<n; i++){ q = (point_ptr)a[i]->data; r = (point_ptr)c[i]->data; if(r->inf_flag) continue; //e2=lambda = (3x^2 + a) / 2y element_square(e2, q->x); element_mul_si(e2, e2, 3); element_add(e2, e2, cdp->a); element_mul(e2, e2, table[i]); //Recall that table[i]=1/2y_i //x1 = lambda^2 - 2x element_double(e1, q->x); element_square(e0, e2); element_sub(e0, e0, e1); //y1 = (x - x1)lambda - y element_sub(e1, q->x, e0); element_mul(e1, e1, e2); element_sub(e1, e1, q->y); element_set(r->x, e0); element_set(r->y, e1); r->inf_flag = 0; } element_clear(e0); element_clear(e1); element_clear(e2); for(i=0; i<n; i++){ element_clear(table[i]); } pbc_free(table); }
// Requires cofactor is even. TODO: This seems to contradict a comment below. // Requires in != out. // Mangles in. static void lucas_even(element_ptr out, element_ptr in, mpz_t cofactor) { if (element_is1(in)) { element_set(out, in); return; } element_t temp; element_init_same_as(temp, out); element_ptr in0 = element_x(in); element_ptr in1 = element_y(in); element_ptr v0 = element_x(out); element_ptr v1 = element_y(out); element_ptr t0 = element_x(temp); element_ptr t1 = element_y(temp); size_t j; element_set_si(t0, 2); element_double(t1, in0); element_set(v0, t0); element_set(v1, t1); j = mpz_sizeinbase(cofactor, 2) - 1; for (;;) { if (!j) { element_mul(v1, v0, v1); element_sub(v1, v1, t1); element_square(v0, v0); element_sub(v0, v0, t0); break; } if (mpz_tstbit(cofactor, j)) { element_mul(v0, v0, v1); element_sub(v0, v0, t1); element_square(v1, v1); element_sub(v1, v1, t0); } else { element_mul(v1, v0, v1); element_sub(v1, v1, t1); element_square(v0, v0); element_sub(v0, v0, t0); } j--; } // Assume cofactor = (q^2 - q + 1) / r is odd // thus v1 = V_k, v0 = V_{k-1} // U = (P v1 - 2 v0) / (P^2 - 4) element_double(v0, v0); element_mul(in0, t1, v1); element_sub(in0, in0, v0); element_square(t1, t1); element_sub(t1, t1, t0); element_sub(t1, t1, t0); element_halve(v0, v1); element_div(v1, in0, t1); element_mul(v1, v1, in1); element_clear(temp); }