| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| */ |
| |
| /* AMCL Fp^12 functions */ |
| /* SU=m, m is Stack Usage (no lazy )*/ |
| /* FP12 elements are of the form a+i.b+i^2.c */ |
| |
| #include "fp12_YYY.h" |
| #include "config_curve_ZZZ.h" |
| |
| /* return 1 if b==c, no branching */ |
| static int teq(sign32 b,sign32 c) |
| { |
| sign32 x=b^c; |
| x-=1; // if x=0, x now -1 |
| return (x>>31)&1; |
| } |
| |
| |
| /* Constant time select from pre-computed table */ |
| static void FP12_YYY_select(FP12_YYY *f,const FP12_YYY g[],sign32 b) |
| { |
| FP12_YYY invf; |
| sign32 m=b>>31; |
| sign32 babs=(b^m)-m; |
| |
| babs=(babs-1)/2; |
| |
| FP12_YYY_cmove(f,&g[0],teq(babs,0)); // conditional move |
| FP12_YYY_cmove(f,&g[1],teq(babs,1)); |
| FP12_YYY_cmove(f,&g[2],teq(babs,2)); |
| FP12_YYY_cmove(f,&g[3],teq(babs,3)); |
| FP12_YYY_cmove(f,&g[4],teq(babs,4)); |
| FP12_YYY_cmove(f,&g[5],teq(babs,5)); |
| FP12_YYY_cmove(f,&g[6],teq(babs,6)); |
| FP12_YYY_cmove(f,&g[7],teq(babs,7)); |
| |
| FP12_YYY_copy(&invf,f); |
| FP12_YYY_conj(&invf,&invf); // 1/f |
| FP12_YYY_cmove(f,&invf,m&1); |
| } |
| |
| |
| |
| /* test x==0 ? */ |
| /* SU= 8 */ |
| int FP12_YYY_iszilch(const FP12_YYY *x) |
| { |
| if (FP4_YYY_iszilch(&(x->a)) && FP4_YYY_iszilch(&(x->b)) && FP4_YYY_iszilch(&(x->c))) return 1; |
| return 0; |
| } |
| |
| /* test x==1 ? */ |
| /* SU= 8 */ |
| int FP12_YYY_isunity(const FP12_YYY *x) |
| { |
| if (FP4_YYY_isunity(&(x->a)) && FP4_YYY_iszilch(&(x->b)) && FP4_YYY_iszilch(&(x->c))) return 1; |
| return 0; |
| } |
| |
| /* FP12 copy w=x */ |
| /* SU= 16 */ |
| void FP12_YYY_copy(FP12_YYY *w,const FP12_YYY *x) |
| { |
| if (x==w) return; |
| FP4_YYY_copy(&(w->a),&(x->a)); |
| FP4_YYY_copy(&(w->b),&(x->b)); |
| FP4_YYY_copy(&(w->c),&(x->c)); |
| w->type=x->type; |
| } |
| |
| /* FP12 w=1 */ |
| /* SU= 8 */ |
| void FP12_YYY_one(FP12_YYY *w) |
| { |
| FP4_YYY_one(&(w->a)); |
| FP4_YYY_zero(&(w->b)); |
| FP4_YYY_zero(&(w->c)); |
| w->type=AMCL_FP_UNITY; |
| } |
| |
| void FP12_YYY_zero(FP12_YYY *w) |
| { |
| FP4_YYY_zero(&(w->a)); |
| FP4_YYY_zero(&(w->b)); |
| FP4_YYY_zero(&(w->c)); |
| w->type=AMCL_FP_ZERO; |
| } |
| |
| /* return 1 if x==y, else 0 */ |
| /* SU= 16 */ |
| int FP12_YYY_equals(const FP12_YYY *x,const FP12_YYY *y) |
| { |
| if (FP4_YYY_equals(&(x->a),&(y->a)) && FP4_YYY_equals(&(x->b),&(y->b)) && FP4_YYY_equals(&(x->c),&(y->c))) |
| return 1; |
| return 0; |
| } |
| |
| /* Set w=conj(x) */ |
| /* SU= 8 */ |
| void FP12_YYY_conj(FP12_YYY *w,const FP12_YYY *x) |
| { |
| FP12_YYY_copy(w,x); |
| FP4_YYY_conj(&(w->a),&(w->a)); |
| FP4_YYY_nconj(&(w->b),&(w->b)); |
| FP4_YYY_conj(&(w->c),&(w->c)); |
| } |
| |
| /* Create FP12 from FP4 */ |
| /* SU= 8 */ |
| void FP12_YYY_from_FP4(FP12_YYY *w,const FP4_YYY *a) |
| { |
| FP4_YYY_copy(&(w->a),a); |
| FP4_YYY_zero(&(w->b)); |
| FP4_YYY_zero(&(w->c)); |
| w->type=AMCL_FP_SPARSER; |
| } |
| |
| /* Create FP12 from 3 FP4's */ |
| /* SU= 16 */ |
| void FP12_YYY_from_FP4s(FP12_YYY *w,const FP4_YYY *a,const FP4_YYY *b,const FP4_YYY *c) |
| { |
| FP4_YYY_copy(&(w->a),a); |
| FP4_YYY_copy(&(w->b),b); |
| FP4_YYY_copy(&(w->c),c); |
| w->type=AMCL_FP_DENSE; |
| } |
| |
| /* Granger-Scott Unitary Squaring. This does not benefit from lazy reduction */ |
| /* SU= 600 */ |
| void FP12_YYY_usqr(FP12_YYY *w,FP12_YYY *x) |
| { |
| FP4_YYY A; |
| FP4_YYY B; |
| FP4_YYY C; |
| FP4_YYY D; |
| |
| FP4_YYY_copy(&A,&(x->a)); |
| |
| FP4_YYY_sqr(&(w->a),&(x->a)); |
| FP4_YYY_add(&D,&(w->a),&(w->a)); |
| FP4_YYY_add(&(w->a),&D,&(w->a)); |
| |
| FP4_YYY_norm(&(w->a)); |
| FP4_YYY_nconj(&A,&A); |
| |
| FP4_YYY_add(&A,&A,&A); |
| FP4_YYY_add(&(w->a),&(w->a),&A); |
| FP4_YYY_sqr(&B,&(x->c)); |
| FP4_YYY_times_i(&B); |
| |
| FP4_YYY_add(&D,&B,&B); |
| FP4_YYY_add(&B,&B,&D); |
| FP4_YYY_norm(&B); |
| |
| FP4_YYY_sqr(&C,&(x->b)); |
| |
| FP4_YYY_add(&D,&C,&C); |
| FP4_YYY_add(&C,&C,&D); |
| |
| FP4_YYY_norm(&C); |
| FP4_YYY_conj(&(w->b),&(x->b)); |
| FP4_YYY_add(&(w->b),&(w->b),&(w->b)); |
| FP4_YYY_nconj(&(w->c),&(x->c)); |
| |
| FP4_YYY_add(&(w->c),&(w->c),&(w->c)); |
| FP4_YYY_add(&(w->b),&B,&(w->b)); |
| FP4_YYY_add(&(w->c),&C,&(w->c)); |
| |
| w->type=AMCL_FP_DENSE; |
| FP12_YYY_reduce(w); /* reduce here as in pow function repeated squarings would trigger multiple reductions */ |
| } |
| |
| /* FP12 squaring w=x^2 */ |
| /* SU= 600 */ |
| void FP12_YYY_sqr(FP12_YYY *w,FP12_YYY *x) |
| { |
| /* Use Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */ |
| |
| FP4_YYY A; |
| FP4_YYY B; |
| FP4_YYY C; |
| FP4_YYY D; |
| |
| if (x->type<=AMCL_FP_UNITY) |
| { |
| FP12_YYY_copy(w,x); |
| return; |
| } |
| |
| FP4_YYY_sqr(&A,&(x->a)); |
| FP4_YYY_mul(&B,&(x->b),&(x->c)); |
| FP4_YYY_add(&B,&B,&B); |
| FP4_YYY_norm(&B); |
| FP4_YYY_sqr(&C,&(x->c)); |
| |
| FP4_YYY_mul(&D,&(x->a),&(x->b)); |
| FP4_YYY_add(&D,&D,&D); |
| FP4_YYY_add(&(w->c),&(x->a),&(x->c)); |
| FP4_YYY_add(&(w->c),&(x->b),&(w->c)); |
| FP4_YYY_norm(&(w->c)); |
| |
| FP4_YYY_sqr(&(w->c),&(w->c)); |
| |
| FP4_YYY_copy(&(w->a),&A); |
| FP4_YYY_add(&A,&A,&B); |
| |
| FP4_YYY_norm(&A); |
| |
| FP4_YYY_add(&A,&A,&C); |
| FP4_YYY_add(&A,&A,&D); |
| |
| FP4_YYY_norm(&A); |
| FP4_YYY_neg(&A,&A); |
| FP4_YYY_times_i(&B); |
| FP4_YYY_times_i(&C); |
| |
| FP4_YYY_add(&(w->a),&(w->a),&B); |
| FP4_YYY_add(&(w->b),&C,&D); |
| FP4_YYY_add(&(w->c),&(w->c),&A); |
| |
| if (x->type==AMCL_FP_SPARSER) |
| w->type=AMCL_FP_SPARSE; |
| else |
| w->type=AMCL_FP_DENSE; |
| |
| FP12_YYY_norm(w); |
| } |
| |
| /* FP12 full multiplication w=w*y */ |
| |
| |
| /* SU= 896 */ |
| /* FP12 full multiplication w=w*y */ |
| void FP12_YYY_mul(FP12_YYY *w,const FP12_YYY *y) |
| { |
| FP4_YYY z0; |
| FP4_YYY z1; |
| FP4_YYY z2; |
| FP4_YYY z3; |
| FP4_YYY t0; |
| FP4_YYY t1; |
| |
| FP4_YYY_mul(&z0,&(w->a),&(y->a)); |
| FP4_YYY_mul(&z2,&(w->b),&(y->b)); // |
| |
| FP4_YYY_add(&t0,&(w->a),&(w->b)); |
| FP4_YYY_add(&t1,&(y->a),&(y->b)); // |
| |
| FP4_YYY_norm(&t0); |
| FP4_YYY_norm(&t1); |
| |
| FP4_YYY_mul(&z1,&t0,&t1); |
| FP4_YYY_add(&t0,&(w->b),&(w->c)); |
| FP4_YYY_add(&t1,&(y->b),&(y->c)); // |
| |
| FP4_YYY_norm(&t0); |
| FP4_YYY_norm(&t1); |
| |
| FP4_YYY_mul(&z3,&t0,&t1); |
| |
| FP4_YYY_neg(&t0,&z0); |
| FP4_YYY_neg(&t1,&z2); |
| |
| FP4_YYY_add(&z1,&z1,&t0); // z1=z1-z0 |
| FP4_YYY_add(&(w->b),&z1,&t1); // z1=z1-z2 |
| FP4_YYY_add(&z3,&z3,&t1); // z3=z3-z2 |
| FP4_YYY_add(&z2,&z2,&t0); // z2=z2-z0 |
| |
| FP4_YYY_add(&t0,&(w->a),&(w->c)); |
| FP4_YYY_add(&t1,&(y->a),&(y->c)); |
| |
| FP4_YYY_norm(&t0); |
| FP4_YYY_norm(&t1); |
| |
| FP4_YYY_mul(&t0,&t1,&t0); |
| FP4_YYY_add(&z2,&z2,&t0); |
| |
| FP4_YYY_mul(&t0,&(w->c),&(y->c)); |
| FP4_YYY_neg(&t1,&t0); |
| |
| FP4_YYY_add(&(w->c),&z2,&t1); |
| FP4_YYY_add(&z3,&z3,&t1); |
| FP4_YYY_times_i(&t0); |
| FP4_YYY_add(&(w->b),&(w->b),&t0); |
| FP4_YYY_norm(&z3); |
| FP4_YYY_times_i(&z3); |
| FP4_YYY_add(&(w->a),&z0,&z3); |
| |
| w->type=AMCL_FP_DENSE; |
| FP12_YYY_norm(w); |
| } |
| |
| /* FP12 full multiplication w=w*y */ |
| /* Supports sparse multiplicands */ |
| /* Usually w is denser than y */ |
| void FP12_YYY_ssmul(FP12_YYY *w,const FP12_YYY *y) |
| { |
| FP4_YYY z0; |
| FP4_YYY z1; |
| FP4_YYY z2; |
| FP4_YYY z3; |
| FP4_YYY t0; |
| FP4_YYY t1; |
| if (w->type==AMCL_FP_UNITY) |
| { |
| FP12_YYY_copy(w,y); |
| return; |
| } |
| if (y->type==AMCL_FP_UNITY) |
| return; |
| |
| if (y->type >= AMCL_FP_SPARSE) |
| { |
| FP4_YYY_mul(&z0,&(w->a),&(y->a)); // xa.ya always 11x11 |
| |
| #if SEXTIC_TWIST_ZZZ == M_TYPE |
| if (y->type==AMCL_FP_SPARSE || w->type==AMCL_FP_SPARSE) |
| { |
| FP2_YYY_mul(&z2.b,&(w->b).b,&(y->b).b); |
| FP2_YYY_zero(&z2.a); |
| if (y->type!=AMCL_FP_SPARSE) |
| FP2_YYY_mul(&z2.a,&(w->b).b,&(y->b).a); |
| if (w->type!=AMCL_FP_SPARSE) |
| FP2_YYY_mul(&z2.a,&(w->b).a,&(y->b).b); |
| FP4_YYY_times_i(&z2); |
| } |
| else |
| #endif |
| FP4_YYY_mul(&z2,&(w->b),&(y->b)); // xb.yb could be 00x00 or 01x01 or or 10x10 or 11x00 or 11x10 or 11x01 or 11x11 |
| |
| FP4_YYY_add(&t0,&(w->a),&(w->b)); // (xa+xb) |
| FP4_YYY_add(&t1,&(y->a),&(y->b)); // (ya+yb) |
| |
| FP4_YYY_norm(&t0); |
| FP4_YYY_norm(&t1); |
| |
| FP4_YYY_mul(&z1,&t0,&t1); // (xa+xb)(ya+yb) always 11x11 |
| FP4_YYY_add(&t0,&(w->b),&(w->c)); // (xb+xc) |
| FP4_YYY_add(&t1,&(y->b),&(y->c)); // (yb+yc) |
| |
| FP4_YYY_norm(&t0); |
| FP4_YYY_norm(&t1); |
| |
| FP4_YYY_mul(&z3,&t0,&t1); // (xb+xc)(yb+yc) could be anything... |
| FP4_YYY_neg(&t0,&z0); // -(xa.ya) |
| FP4_YYY_neg(&t1,&z2); // -(xb.yb) |
| |
| FP4_YYY_add(&z1,&z1,&t0); |
| FP4_YYY_add(&(w->b),&z1,&t1); // /wb = (xa+xb)(ya+yb) -(xa.ya) -(xb.yb) = xa.yb + xb.ya |
| |
| FP4_YYY_add(&z3,&z3,&t1); // (xb+xc)(yb+yc) -(xb.yb) |
| FP4_YYY_add(&z2,&z2,&t0); // (xb.yb) - (xa.ya) |
| |
| FP4_YYY_add(&t0,&(w->a),&(w->c)); // (xa+xc) |
| FP4_YYY_add(&t1,&(y->a),&(y->c)); // (ya+yc) |
| |
| FP4_YYY_norm(&t0); |
| FP4_YYY_norm(&t1); |
| |
| FP4_YYY_mul(&t0,&t1,&t0); // (xa+xc)(ya+yc) always 11x11 |
| FP4_YYY_add(&z2,&z2,&t0); // (xb.yb) - (xa.ya) + (xa+xc)(ya+yc) |
| |
| #if SEXTIC_TWIST_ZZZ == D_TYPE |
| if (y->type==AMCL_FP_SPARSE || w->type==AMCL_FP_SPARSE) |
| { |
| FP2_YYY_mul(&t0.a,&(w->c).a,&(y->c).a); |
| FP2_YYY_zero(&t0.b); |
| if (y->type!=AMCL_FP_SPARSE) |
| FP2_YYY_mul(&t0.b,&(w->c).a,&(y->c).b); |
| if (w->type!=AMCL_FP_SPARSE) |
| FP2_YYY_mul(&t0.b,&(w->c).b,&(y->c).a); |
| } |
| else |
| #endif |
| FP4_YYY_mul(&t0,&(w->c),&(y->c)); // (xc.yc) could be anything |
| |
| FP4_YYY_neg(&t1,&t0); // -(xc.yc) |
| |
| FP4_YYY_add(&(w->c),&z2,&t1); // wc = (xb.yb) - (xa.ya) + (xa+xc)(ya+yc) - (xc.yc) = xb.yb + xc.ya + xa.yc |
| FP4_YYY_add(&z3,&z3,&t1); // (xb+xc)(yb+yc) -(xb.yb) - (xc.yc) = xb.yc + xc.yb |
| FP4_YYY_times_i(&t0); // i.(xc.yc) |
| FP4_YYY_add(&(w->b),&(w->b),&t0); // wb = (xa+xb)(ya+yb) -(xa.ya) -(xb.yb) +i(xc.yc) |
| FP4_YYY_norm(&z3); |
| FP4_YYY_times_i(&z3); // i[(xb+xc)(yb+yc) -(xb.yb) - (xc.yc)] = i(xb.yc + xc.yb) |
| FP4_YYY_add(&(w->a),&z0,&z3); // wa = xa.ya + i(xb.yc + xc.yb) |
| } |
| else |
| { |
| if (w->type==AMCL_FP_SPARSER) |
| { |
| FP12_YYY_smul(w,y); |
| return; |
| } |
| // dense by sparser - 13m |
| #if SEXTIC_TWIST_ZZZ == D_TYPE |
| FP4_YYY_copy(&z3,&(w->b)); |
| FP4_YYY_mul(&z0,&(w->a),&(y->a)); |
| |
| FP4_YYY_pmul(&z2,&(w->b),&(y->b).a); |
| FP4_YYY_add(&(w->b),&(w->a),&(w->b)); |
| FP4_YYY_copy(&t1,&(y->a)); |
| FP2_YYY_add(&t1.a,&t1.a,&(y->b).a); |
| |
| FP4_YYY_norm(&t1); |
| FP4_YYY_norm(&(w->b)); |
| |
| FP4_YYY_mul(&(w->b),&(w->b),&t1); |
| FP4_YYY_add(&z3,&z3,&(w->c)); |
| FP4_YYY_norm(&z3); |
| FP4_YYY_pmul(&z3,&z3,&(y->b).a); |
| FP4_YYY_neg(&t0,&z0); |
| FP4_YYY_neg(&t1,&z2); |
| |
| FP4_YYY_add(&(w->b),&(w->b),&t0); // z1=z1-z0 |
| FP4_YYY_add(&(w->b),&(w->b),&t1); // z1=z1-z2 |
| |
| FP4_YYY_add(&z3,&z3,&t1); // z3=z3-z2 |
| FP4_YYY_add(&z2,&z2,&t0); // z2=z2-z0 |
| |
| FP4_YYY_add(&t0,&(w->a),&(w->c)); |
| FP4_YYY_norm(&t0); |
| FP4_YYY_norm(&z3); |
| |
| FP4_YYY_mul(&t0,&(y->a),&t0); |
| FP4_YYY_add(&(w->c),&z2,&t0); |
| |
| FP4_YYY_times_i(&z3); |
| FP4_YYY_add(&(w->a),&z0,&z3); |
| #endif |
| #if SEXTIC_TWIST_ZZZ == M_TYPE |
| FP4_YYY_mul(&z0,&(w->a),&(y->a)); |
| FP4_YYY_add(&t0,&(w->a),&(w->b)); |
| FP4_YYY_norm(&t0); |
| |
| FP4_YYY_mul(&z1,&t0,&(y->a)); |
| FP4_YYY_add(&t0,&(w->b),&(w->c)); |
| FP4_YYY_norm(&t0); |
| |
| FP4_YYY_pmul(&z3,&t0,&(y->c).b); |
| FP4_YYY_times_i(&z3); |
| |
| FP4_YYY_neg(&t0,&z0); |
| FP4_YYY_add(&z1,&z1,&t0); // z1=z1-z0 |
| |
| FP4_YYY_copy(&(w->b),&z1); |
| FP4_YYY_copy(&z2,&t0); |
| |
| FP4_YYY_add(&t0,&(w->a),&(w->c)); |
| FP4_YYY_add(&t1,&(y->a),&(y->c)); |
| |
| FP4_YYY_norm(&t0); |
| FP4_YYY_norm(&t1); |
| |
| FP4_YYY_mul(&t0,&t1,&t0); |
| FP4_YYY_add(&z2,&z2,&t0); |
| |
| FP4_YYY_pmul(&t0,&(w->c),&(y->c).b); |
| FP4_YYY_times_i(&t0); |
| FP4_YYY_neg(&t1,&t0); |
| FP4_YYY_times_i(&t0); |
| |
| FP4_YYY_add(&(w->c),&z2,&t1); |
| FP4_YYY_add(&z3,&z3,&t1); |
| |
| FP4_YYY_add(&(w->b),&(w->b),&t0); |
| FP4_YYY_norm(&z3); |
| FP4_YYY_times_i(&z3); |
| FP4_YYY_add(&(w->a),&z0,&z3); |
| |
| #endif |
| } |
| w->type=AMCL_FP_DENSE; |
| FP12_YYY_norm(w); |
| } |
| |
| /* FP12 multiplication w=w*y */ |
| /* catering for special case that arises from special form of ATE pairing line function */ |
| /* w and y are both sparser line functions - cost = 6m */ |
| void FP12_YYY_smul(FP12_YYY *w,const FP12_YYY *y) |
| { |
| FP2_YYY w1; |
| FP2_YYY w2; |
| FP2_YYY w3; |
| FP2_YYY ta; |
| FP2_YYY tb; |
| FP2_YYY tc; |
| FP2_YYY td; |
| FP2_YYY te; |
| FP2_YYY t; |
| |
| #if SEXTIC_TWIST_ZZZ == D_TYPE |
| FP2_YYY_mul(&w1,&(w->a).a,&(y->a).a); // A1.A2 |
| FP2_YYY_mul(&w2,&(w->a).b,&(y->a).b); // B1.B2 |
| FP2_YYY_mul(&w3,&(w->b).a,&(y->b).a); // C1.C2 |
| |
| FP2_YYY_add(&ta,&(w->a).a,&(w->a).b); // A1+B1 |
| FP2_YYY_add(&tb,&(y->a).a,&(y->a).b); // A2+B2 |
| FP2_YYY_norm(&ta); |
| FP2_YYY_norm(&tb); |
| FP2_YYY_mul(&tc,&ta,&tb); // (A1+B1)(A2+B2) |
| FP2_YYY_add(&t,&w1,&w2); |
| FP2_YYY_neg(&t,&t); |
| FP2_YYY_add(&tc,&tc,&t); // (A1+B1)(A2+B2)-A1.A2-B1*B2 = (A1.B2+A2.B1) |
| |
| FP2_YYY_add(&ta,&(w->a).a,&(w->b).a); // A1+C1 |
| FP2_YYY_add(&tb,&(y->a).a,&(y->b).a); // A2+C2 |
| FP2_YYY_norm(&ta); |
| FP2_YYY_norm(&tb); |
| FP2_YYY_mul(&td,&ta,&tb); // (A1+C1)(A2+C2) |
| FP2_YYY_add(&t,&w1,&w3); |
| FP2_YYY_neg(&t,&t); |
| FP2_YYY_add(&td,&td,&t); // (A1+C1)(A2+C2)-A1.A2-C1*C2 = (A1.C2+A2.C1) |
| |
| FP2_YYY_add(&ta,&(w->a).b,&(w->b).a); // B1+C1 |
| FP2_YYY_add(&tb,&(y->a).b,&(y->b).a); // B2+C2 |
| FP2_YYY_norm(&ta); |
| FP2_YYY_norm(&tb); |
| FP2_YYY_mul(&te,&ta,&tb); // (B1+C1)(B2+C2) |
| FP2_YYY_add(&t,&w2,&w3); |
| FP2_YYY_neg(&t,&t); |
| FP2_YYY_add(&te,&te,&t); // (B1+C1)(B2+C2)-B1.B2-C1*C2 = (B1.C2+B2.C1) |
| |
| FP2_YYY_mul_ip(&w2); |
| FP2_YYY_add(&w1,&w1,&w2); |
| FP4_YYY_from_FP2s(&(w->a),&w1,&tc); |
| FP4_YYY_from_FP2s(&(w->b),&td,&te); // only norm these 2 |
| FP4_YYY_from_FP2(&(w->c),&w3); |
| |
| FP4_YYY_norm(&(w->a)); |
| FP4_YYY_norm(&(w->b)); |
| #endif |
| |
| #if SEXTIC_TWIST_ZZZ == M_TYPE |
| FP2_YYY_mul(&w1,&(w->a).a,&(y->a).a); // A1.A2 |
| FP2_YYY_mul(&w2,&(w->a).b,&(y->a).b); // B1.B2 |
| FP2_YYY_mul(&w3,&(w->c).b,&(y->c).b); // F1.F2 |
| |
| FP2_YYY_add(&ta,&(w->a).a,&(w->a).b); // A1+B1 |
| FP2_YYY_add(&tb,&(y->a).a,&(y->a).b); // A2+B2 |
| FP2_YYY_norm(&ta); |
| FP2_YYY_norm(&tb); |
| FP2_YYY_mul(&tc,&ta,&tb); // (A1+B1)(A2+B2) |
| FP2_YYY_add(&t,&w1,&w2); |
| FP2_YYY_neg(&t,&t); |
| FP2_YYY_add(&tc,&tc,&t); // (A1+B1)(A2+B2)-A1.A2-B1*B2 = (A1.B2+A2.B1) |
| |
| FP2_YYY_add(&ta,&(w->a).a,&(w->c).b); // A1+F1 |
| FP2_YYY_add(&tb,&(y->a).a,&(y->c).b); // A2+F2 |
| FP2_YYY_norm(&ta); |
| FP2_YYY_norm(&tb); |
| FP2_YYY_mul(&td,&ta,&tb); // (A1+F1)(A2+F2) |
| FP2_YYY_add(&t,&w1,&w3); |
| FP2_YYY_neg(&t,&t); |
| FP2_YYY_add(&td,&td,&t); // (A1+F1)(A2+F2)-A1.A2-F1*F2 = (A1.F2+A2.F1) |
| |
| FP2_YYY_add(&ta,&(w->a).b,&(w->c).b); // B1+F1 |
| FP2_YYY_add(&tb,&(y->a).b,&(y->c).b); // B2+F2 |
| FP2_YYY_norm(&ta); |
| FP2_YYY_norm(&tb); |
| FP2_YYY_mul(&te,&ta,&tb); // (B1+F1)(B2+F2) |
| FP2_YYY_add(&t,&w2,&w3); |
| FP2_YYY_neg(&t,&t); |
| FP2_YYY_add(&te,&te,&t); // (B1+F1)(B2+F2)-B1.B2-F1*F2 = (B1.F2+B2.F1) |
| |
| FP2_YYY_mul_ip(&w2); |
| FP2_YYY_add(&w1,&w1,&w2); |
| FP4_YYY_from_FP2s(&(w->a),&w1,&tc); |
| |
| FP2_YYY_mul_ip(&w3); |
| FP2_YYY_norm(&w3); |
| FP4_YYY_from_FP2H(&(w->b),&w3); |
| |
| FP2_YYY_norm(&te); |
| FP2_YYY_mul_ip(&te); |
| FP4_YYY_from_FP2s(&(w->c),&te,&td); |
| |
| FP4_YYY_norm(&(w->a)); |
| FP4_YYY_norm(&(w->c)); |
| #endif |
| |
| // } |
| w->type=AMCL_FP_SPARSE; |
| } |
| |
| /* Set w=1/x */ |
| /* SU= 600 */ |
| void FP12_YYY_inv(FP12_YYY *w,FP12_YYY *x) |
| { |
| FP4_YYY f0; |
| FP4_YYY f1; |
| FP4_YYY f2; |
| FP4_YYY f3; |
| |
| FP4_YYY_sqr(&f0,&(x->a)); |
| FP4_YYY_mul(&f1,&(x->b),&(x->c)); |
| FP4_YYY_times_i(&f1); |
| FP4_YYY_sub(&f0,&f0,&f1); /* y.a */ |
| FP4_YYY_norm(&f0); |
| |
| FP4_YYY_sqr(&f1,&(x->c)); |
| FP4_YYY_times_i(&f1); |
| FP4_YYY_mul(&f2,&(x->a),&(x->b)); |
| FP4_YYY_sub(&f1,&f1,&f2); /* y.b */ |
| FP4_YYY_norm(&f1); |
| |
| FP4_YYY_sqr(&f2,&(x->b)); |
| FP4_YYY_mul(&f3,&(x->a),&(x->c)); |
| FP4_YYY_sub(&f2,&f2,&f3); /* y.c */ |
| FP4_YYY_norm(&f2); |
| |
| FP4_YYY_mul(&f3,&(x->b),&f2); |
| FP4_YYY_times_i(&f3); |
| FP4_YYY_mul(&(w->a),&f0,&(x->a)); |
| FP4_YYY_add(&f3,&(w->a),&f3); |
| FP4_YYY_mul(&(w->c),&f1,&(x->c)); |
| FP4_YYY_times_i(&(w->c)); |
| |
| FP4_YYY_add(&f3,&(w->c),&f3); |
| FP4_YYY_norm(&f3); |
| |
| FP4_YYY_inv(&f3,&f3); |
| |
| FP4_YYY_mul(&(w->a),&f0,&f3); |
| FP4_YYY_mul(&(w->b),&f1,&f3); |
| FP4_YYY_mul(&(w->c),&f2,&f3); |
| w->type=AMCL_FP_DENSE; |
| } |
| |
| /* constant time powering by small integer of max length bts */ |
| |
| void FP12_YYY_pinpow(FP12_YYY *r,int e,int bts) |
| { |
| int b; |
| FP12_YYY R[2]; |
| |
| FP12_YYY_one(&R[0]); |
| FP12_YYY_copy(&R[1],r); |
| |
| for (int i=bts-1; i>=0; i--) |
| { |
| b=(e>>i)&1; |
| FP12_YYY_mul(&R[1-b],&R[b]); |
| FP12_YYY_usqr(&R[b],&R[b]); |
| } |
| FP12_YYY_copy(r,&R[0]); |
| } |
| |
| /* Compressed powering of unitary elements y=x^(e mod r) */ |
| |
| void FP12_YYY_compow(FP4_YYY *c,const FP12_YYY *x,const BIG_XXX e,const BIG_XXX r) |
| { |
| FP12_YYY g1; |
| FP12_YYY g2; |
| FP4_YYY cp; |
| FP4_YYY cpm1; |
| FP4_YYY cpm2; |
| FP2_YYY f; |
| BIG_XXX q; |
| BIG_XXX a; |
| BIG_XXX b; |
| BIG_XXX m; |
| |
| BIG_XXX_rcopy(a,Fra_YYY); |
| BIG_XXX_rcopy(b,Frb_YYY); |
| FP2_YYY_from_BIGs(&f,a,b); |
| |
| BIG_XXX_rcopy(q,Modulus_YYY); |
| |
| FP12_YYY_copy(&g1,x); |
| FP12_YYY_copy(&g2,x); |
| |
| BIG_XXX_copy(m,q); |
| BIG_XXX_mod(m,r); |
| |
| BIG_XXX_copy(a,e); |
| BIG_XXX_mod(a,m); |
| |
| BIG_XXX_copy(b,e); |
| BIG_XXX_sdiv(b,m); |
| |
| FP12_YYY_trace(c,&g1); |
| |
| if (BIG_XXX_iszilch(b)) |
| { |
| FP4_YYY_xtr_pow(c,c,e); |
| return; |
| } |
| |
| FP12_YYY_frob(&g2,&f); |
| FP12_YYY_trace(&cp,&g2); |
| |
| FP12_YYY_conj(&g1,&g1); |
| FP12_YYY_mul(&g2,&g1); |
| FP12_YYY_trace(&cpm1,&g2); |
| FP12_YYY_mul(&g2,&g1); |
| FP12_YYY_trace(&cpm2,&g2); |
| |
| FP4_YYY_xtr_pow2(c,&cp,c,&cpm1,&cpm2,a,b); |
| } |
| |
| |
| /* SU= 528 */ |
| /* set r=a^b */ |
| /* Note this is simple square and multiply, so not side-channel safe */ |
| |
| void FP12_YYY_pow(FP12_YYY *r,const FP12_YYY *a,const BIG_XXX b) |
| { |
| FP12_YYY w; |
| FP12_YYY sf; |
| BIG_XXX b1; |
| BIG_XXX b3; |
| int nb; |
| int bt; |
| BIG_XXX_copy(b1,b); |
| BIG_XXX_norm(b1); |
| BIG_XXX_pmul(b3,b1,3); |
| BIG_XXX_norm(b3); |
| |
| FP12_YYY_copy(&sf,a); |
| FP12_YYY_norm(&sf); |
| FP12_YYY_copy(&w,&sf); |
| |
| |
| nb=BIG_XXX_nbits(b3); |
| for (int i=nb-2; i>=1; i--) |
| { |
| FP12_YYY_usqr(&w,&w); |
| bt=BIG_XXX_bit(b3,i)-BIG_XXX_bit(b1,i); |
| if (bt==1) |
| FP12_YYY_mul(&w,&sf); |
| if (bt==-1) |
| { |
| FP12_YYY_conj(&sf,&sf); |
| FP12_YYY_mul(&w,&sf); |
| FP12_YYY_conj(&sf,&sf); |
| } |
| } |
| |
| FP12_YYY_copy(r,&w); |
| FP12_YYY_reduce(r); |
| } |
| |
| /* p=q0^u0.q1^u1.q2^u2.q3^u3 */ |
| /* Side channel attack secure */ |
| // Bos & Costello https://eprint.iacr.org/2013/458.pdf |
| // Faz-Hernandez & Longa & Sanchez https://eprint.iacr.org/2013/158.pdf |
| |
| void FP12_YYY_pow4(FP12_YYY *p,const FP12_YYY *q,const BIG_XXX u[4]) |
| { |
| int i; |
| int k; |
| int nb; |
| int pb; |
| int bt; |
| FP12_YYY g[8]; |
| FP12_YYY r; |
| BIG_XXX t[4]; |
| BIG_XXX mt; |
| sign8 w[NLEN_XXX*BASEBITS_XXX+1] = {0}; |
| sign8 s[NLEN_XXX*BASEBITS_XXX+1]; |
| |
| for (i=0; i<4; i++) |
| BIG_XXX_copy(t[i],u[i]); |
| |
| // Precomputed table |
| FP12_YYY_copy(&g[0],&q[0]); // q[0] |
| FP12_YYY_copy(&g[1],&g[0]); |
| FP12_YYY_mul(&g[1],&q[1]); // q[0].q[1] |
| FP12_YYY_copy(&g[2],&g[0]); |
| FP12_YYY_mul(&g[2],&q[2]); // q[0].q[2] |
| FP12_YYY_copy(&g[3],&g[1]); |
| FP12_YYY_mul(&g[3],&q[2]); // q[0].q[1].q[2] |
| FP12_YYY_copy(&g[4],&g[0]); |
| FP12_YYY_mul(&g[4],&q[3]); // q[0].q[3] |
| FP12_YYY_copy(&g[5],&g[1]); |
| FP12_YYY_mul(&g[5],&q[3]); // q[0].q[1].q[3] |
| FP12_YYY_copy(&g[6],&g[2]); |
| FP12_YYY_mul(&g[6],&q[3]); // q[0].q[2].q[3] |
| FP12_YYY_copy(&g[7],&g[3]); |
| FP12_YYY_mul(&g[7],&q[3]); // q[0].q[1].q[2].q[3] |
| |
| // Make it odd |
| pb=1-BIG_XXX_parity(t[0]); |
| BIG_XXX_inc(t[0],pb); |
| BIG_XXX_norm(t[0]); |
| |
| // Number of bits |
| BIG_XXX_zero(mt); |
| for (i=0; i<4; i++) |
| { |
| BIG_XXX_or(mt,mt,t[i]); |
| } |
| nb=1+BIG_XXX_nbits(mt); |
| |
| // Sign pivot |
| s[nb-1]=1; |
| for (i=0; i<nb-1; i++) |
| { |
| BIG_XXX_fshr(t[0],1); |
| s[i]=(signed char)(2*BIG_XXX_parity(t[0])-1); |
| } |
| |
| // Recoded exponent |
| for (i=0; i<nb; i++) |
| { |
| k=1; |
| for (int j=1; j<4; j++) |
| { |
| bt=s[i]*BIG_XXX_parity(t[j]); |
| BIG_XXX_fshr(t[j],1); |
| |
| BIG_XXX_dec(t[j],(bt>>1)); |
| BIG_XXX_norm(t[j]); |
| w[i]+=bt*k; |
| k*=2; |
| } |
| } |
| |
| // Main loop |
| FP12_YYY_select(p,g,2*w[nb-1]+1); |
| for (i=nb-2; i>=0; i--) |
| { |
| FP12_YYY_select(&r,g,2*w[i]+s[i]); |
| FP12_YYY_usqr(p,p); |
| FP12_YYY_mul(p,&r); |
| } |
| // apply correction |
| FP12_YYY_conj(&r,&q[0]); |
| FP12_YYY_mul(&r,p); |
| FP12_YYY_cmove(p,&r,pb); |
| |
| FP12_YYY_reduce(p); |
| |
| // zeroization |
| for (i=0; i<4; i++) |
| BIG_XXX_zero(t[i]); |
| } |
| |
| /* Set w=w^p using Frobenius */ |
| /* SU= 160 */ |
| void FP12_YYY_frob(FP12_YYY *w,const FP2_YYY *f) |
| { |
| FP2_YYY f2; |
| FP2_YYY f3; |
| FP2_YYY_sqr(&f2,f); /* f2=f^2 */ |
| FP2_YYY_mul(&f3,&f2,f); /* f3=f^3 */ |
| |
| FP4_YYY_frob(&(w->a),&f3); |
| FP4_YYY_frob(&(w->b),&f3); |
| FP4_YYY_frob(&(w->c),&f3); |
| |
| FP4_YYY_pmul(&(w->b),&(w->b),f); |
| FP4_YYY_pmul(&(w->c),&(w->c),&f2); |
| w->type=AMCL_FP_DENSE; |
| } |
| |
| /* SU= 8 */ |
| /* normalise all components of w */ |
| void FP12_YYY_norm(FP12_YYY *w) |
| { |
| FP4_YYY_norm(&(w->a)); |
| FP4_YYY_norm(&(w->b)); |
| FP4_YYY_norm(&(w->c)); |
| } |
| |
| /* SU= 8 */ |
| /* reduce all components of w */ |
| void FP12_YYY_reduce(FP12_YYY *w) |
| { |
| FP4_YYY_reduce(&(w->a)); |
| FP4_YYY_reduce(&(w->b)); |
| FP4_YYY_reduce(&(w->c)); |
| } |
| |
| /* trace function w=trace(x) */ |
| /* SU= 8 */ |
| void FP12_YYY_trace(FP4_YYY *w,const FP12_YYY *x) |
| { |
| FP4_YYY_imul(w,&(x->a),3); |
| FP4_YYY_reduce(w); |
| } |
| |
| /* SU= 8 */ |
| /* Output w in hex */ |
| void FP12_YYY_output(FP12_YYY *w) |
| { |
| printf("["); |
| FP4_YYY_output(&(w->a)); |
| printf(","); |
| FP4_YYY_output(&(w->b)); |
| printf(","); |
| FP4_YYY_output(&(w->c)); |
| printf("]"); |
| } |
| |
| /* SU= 64 */ |
| /* Convert g to octet string w */ |
| void FP12_YYY_toOctet(octet *W,const FP12_YYY *g) |
| { |
| BIG_XXX a; |
| W->len=12*MODBYTES_XXX; |
| |
| FP_YYY_redc(a,&(g->a.a.a)); |
| BIG_XXX_toBytes(&(W->val[0]),a); |
| FP_YYY_redc(a,&(g->a.a.b)); |
| BIG_XXX_toBytes(&(W->val[MODBYTES_XXX]),a); |
| FP_YYY_redc(a,&(g->a.b.a)); |
| BIG_XXX_toBytes(&(W->val[2*MODBYTES_XXX]),a); |
| FP_YYY_redc(a,&(g->a.b.b)); |
| BIG_XXX_toBytes(&(W->val[3*MODBYTES_XXX]),a); |
| FP_YYY_redc(a,&(g->b.a.a)); |
| BIG_XXX_toBytes(&(W->val[4*MODBYTES_XXX]),a); |
| FP_YYY_redc(a,&(g->b.a.b)); |
| BIG_XXX_toBytes(&(W->val[5*MODBYTES_XXX]),a); |
| FP_YYY_redc(a,&(g->b.b.a)); |
| BIG_XXX_toBytes(&(W->val[6*MODBYTES_XXX]),a); |
| FP_YYY_redc(a,&(g->b.b.b)); |
| BIG_XXX_toBytes(&(W->val[7*MODBYTES_XXX]),a); |
| FP_YYY_redc(a,&(g->c.a.a)); |
| BIG_XXX_toBytes(&(W->val[8*MODBYTES_XXX]),a); |
| FP_YYY_redc(a,&(g->c.a.b)); |
| BIG_XXX_toBytes(&(W->val[9*MODBYTES_XXX]),a); |
| FP_YYY_redc(a,&(g->c.b.a)); |
| BIG_XXX_toBytes(&(W->val[10*MODBYTES_XXX]),a); |
| FP_YYY_redc(a,&(g->c.b.b)); |
| BIG_XXX_toBytes(&(W->val[11*MODBYTES_XXX]),a); |
| } |
| |
| /* SU= 24 */ |
| /* Restore g from octet string w */ |
| void FP12_YYY_fromOctet(FP12_YYY *g,const octet *W) |
| { |
| BIG_XXX b; |
| BIG_XXX_fromBytes(b,&W->val[0]); |
| FP_YYY_nres(&(g->a.a.a),b); |
| BIG_XXX_fromBytes(b,&W->val[MODBYTES_XXX]); |
| FP_YYY_nres(&(g->a.a.b),b); |
| BIG_XXX_fromBytes(b,&W->val[2*MODBYTES_XXX]); |
| FP_YYY_nres(&(g->a.b.a),b); |
| BIG_XXX_fromBytes(b,&W->val[3*MODBYTES_XXX]); |
| FP_YYY_nres(&(g->a.b.b),b); |
| BIG_XXX_fromBytes(b,&W->val[4*MODBYTES_XXX]); |
| FP_YYY_nres(&(g->b.a.a),b); |
| BIG_XXX_fromBytes(b,&W->val[5*MODBYTES_XXX]); |
| FP_YYY_nres(&(g->b.a.b),b); |
| BIG_XXX_fromBytes(b,&W->val[6*MODBYTES_XXX]); |
| FP_YYY_nres(&(g->b.b.a),b); |
| BIG_XXX_fromBytes(b,&W->val[7*MODBYTES_XXX]); |
| FP_YYY_nres(&(g->b.b.b),b); |
| BIG_XXX_fromBytes(b,&W->val[8*MODBYTES_XXX]); |
| FP_YYY_nres(&(g->c.a.a),b); |
| BIG_XXX_fromBytes(b,&W->val[9*MODBYTES_XXX]); |
| FP_YYY_nres(&(g->c.a.b),b); |
| BIG_XXX_fromBytes(b,&W->val[10*MODBYTES_XXX]); |
| FP_YYY_nres(&(g->c.b.a),b); |
| BIG_XXX_fromBytes(b,&W->val[11*MODBYTES_XXX]); |
| FP_YYY_nres(&(g->c.b.b),b); |
| } |
| |
| /* Move b to a if d=1 */ |
| void FP12_YYY_cmove(FP12_YYY *f,const FP12_YYY *g,int d) |
| { |
| FP4_YYY_cmove(&(f->a),&(g->a),d); |
| FP4_YYY_cmove(&(f->b),&(g->b),d); |
| FP4_YYY_cmove(&(f->c),&(g->c),d); |
| d=~(d-1); |
| f->type^=(f->type^g->type)&d; |
| } |
| |