| /* |
| 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^48 functions */ |
| |
| /* FP48 elements are of the form a+i.b+i^2.c */ |
| |
| var FP48 = function(ctx) { |
| "use strict"; |
| |
| /* general purpose constructor */ |
| var FP48 = function(d, e, f) { |
| if (!isNaN(d)) |
| { |
| this.a = new ctx.FP16(d); |
| this.b = new ctx.FP16(0); |
| this.c = new ctx.FP16(0); |
| if (d==1) this.stype=ctx.FP.ONE; |
| else this.stype=ctx.FP.SPARSER; |
| } |
| else |
| { |
| if (d instanceof FP48) { |
| this.a = new ctx.FP16(d.a); |
| this.b = new ctx.FP16(d.b); |
| this.c = new ctx.FP16(d.c); |
| } else { |
| this.a = new ctx.FP16(d); |
| this.b = new ctx.FP16(e); |
| this.c = new ctx.FP16(f); |
| } |
| this.stype=ctx.FP.DENSE; |
| } |
| }; |
| |
| FP48.prototype = { |
| /* reduce all components of this mod Modulus */ |
| reduce: function() { |
| this.a.reduce(); |
| this.b.reduce(); |
| this.c.reduce(); |
| }, |
| |
| /* normalize all components of this mod Modulus */ |
| norm: function() { |
| this.a.norm(); |
| this.b.norm(); |
| this.c.norm(); |
| }, |
| |
| /* test x==0 ? */ |
| iszilch: function() { |
| return (this.a.iszilch() && this.b.iszilch() && this.c.iszilch()); |
| }, |
| |
| /* test x==1 ? */ |
| isunity: function() { |
| var one = new ctx.FP16(1); |
| return (this.a.equals(one) && this.b.iszilch() && this.c.iszilch()); |
| }, |
| |
| /* conditional copy of g to this depending on d */ |
| cmove: function(g, d) { |
| this.a.cmove(g.a, d); |
| this.b.cmove(g.b, d); |
| this.c.cmove(g.c, d); |
| d=~(d-1); |
| this.stype^=(this.stype^g.stype)&d; |
| |
| }, |
| |
| /* Constant time select from pre-computed table */ |
| select: function(g, b) { |
| var invf = new FP48(0), |
| m, babs; |
| |
| m = b >> 31; |
| babs = (b ^ m) - m; |
| babs = (babs - 1) / 2; |
| |
| this.cmove(g[0], FP48.teq(babs, 0)); // conditional move |
| this.cmove(g[1], FP48.teq(babs, 1)); |
| this.cmove(g[2], FP48.teq(babs, 2)); |
| this.cmove(g[3], FP48.teq(babs, 3)); |
| this.cmove(g[4], FP48.teq(babs, 4)); |
| this.cmove(g[5], FP48.teq(babs, 5)); |
| this.cmove(g[6], FP48.teq(babs, 6)); |
| this.cmove(g[7], FP48.teq(babs, 7)); |
| |
| invf.copy(this); |
| invf.conj(); |
| this.cmove(invf, (m & 1)); |
| }, |
| |
| settype: function(w) { |
| this.stype=w; |
| }, |
| |
| gettype: function() { |
| return this.stype; |
| }, |
| |
| /* extract a from this */ |
| geta: function() { |
| return this.a; |
| }, |
| |
| /* extract b */ |
| getb: function() { |
| return this.b; |
| }, |
| |
| /* extract c */ |
| getc: function() { |
| return this.c; |
| }, |
| |
| /* return 1 if x==y, else 0 */ |
| equals: function(x) { |
| return (this.a.equals(x.a) && this.b.equals(x.b) && this.c.equals(x.c)); |
| }, |
| |
| /* copy this=x */ |
| copy: function(x) { |
| this.a.copy(x.a); |
| this.b.copy(x.b); |
| this.c.copy(x.c); |
| this.stype=x.stype; |
| }, |
| |
| /* set this=1 */ |
| one: function() { |
| this.a.one(); |
| this.b.zero(); |
| this.c.zero(); |
| this.stype=ctx.FP.ONE; |
| }, |
| |
| /* this=conj(this) */ |
| conj: function() { |
| this.a.conj(); |
| this.b.nconj(); |
| this.c.conj(); |
| }, |
| |
| /* set this from 3 FP16s */ |
| set: function(d, e, f) { |
| this.a.copy(d); |
| this.b.copy(e); |
| this.c.copy(f); |
| this.stype=ctx.FP.DENSE; |
| }, |
| |
| /* set this from one ctx.FP16 */ |
| seta: function(d) { |
| this.a.copy(d); |
| this.b.zero(); |
| this.c.zero(); |
| this.stype=ctx.FP.SPARSER |
| }, |
| |
| /* Granger-Scott Unitary Squaring */ |
| usqr: function() { |
| var A = new ctx.FP16(this.a), |
| B = new ctx.FP16(this.c), |
| C = new ctx.FP16(this.b), |
| D = new ctx.FP16(0); |
| |
| this.a.sqr(); |
| D.copy(this.a); |
| D.add(this.a); |
| this.a.add(D); |
| |
| A.nconj(); |
| |
| A.add(A); |
| this.a.add(A); |
| B.sqr(); |
| B.times_i(); |
| |
| D.copy(B); |
| D.add(B); |
| B.add(D); |
| |
| C.sqr(); |
| D.copy(C); |
| D.add(C); |
| C.add(D); |
| |
| this.b.conj(); |
| this.b.add(this.b); |
| this.c.nconj(); |
| |
| this.c.add(this.c); |
| this.b.add(B); |
| this.c.add(C); |
| this.stype=ctx.FP.DENSE; |
| this.reduce(); |
| }, |
| |
| /* Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */ |
| sqr: function() { |
| if (this.stype==ctx.FP.ONE) |
| return; |
| |
| var A = new ctx.FP16(this.a), |
| B = new ctx.FP16(this.b), |
| C = new ctx.FP16(this.c), |
| D = new ctx.FP16(this.a); |
| |
| A.sqr(); |
| B.mul(this.c); |
| B.add(B); |
| C.sqr(); |
| D.mul(this.b); |
| D.add(D); |
| |
| this.c.add(this.a); |
| this.c.add(this.b); |
| this.c.norm(); |
| this.c.sqr(); |
| |
| this.a.copy(A); |
| |
| A.add(B); |
| A.add(C); |
| A.add(D); |
| A.neg(); |
| B.times_i(); |
| C.times_i(); |
| |
| this.a.add(B); |
| this.b.copy(C); |
| this.b.add(D); |
| this.c.add(A); |
| if (this.stype==ctx.FP.SPARSER) |
| this.stype=ctx.FP.SPARSE; |
| else |
| this.stype=ctx.FP.DENSE; |
| this.norm(); |
| }, |
| |
| /* FP48 full multiplication this=this*y */ |
| mul: function(y) { |
| var z0 = new ctx.FP16(this.a), |
| z1 = new ctx.FP16(0), |
| z2 = new ctx.FP16(this.b), |
| z3 = new ctx.FP16(0), |
| t0 = new ctx.FP16(this.a), |
| t1 = new ctx.FP16(y.a); |
| |
| z0.mul(y.a); |
| z2.mul(y.b); |
| |
| t0.add(this.b); |
| t1.add(y.b); |
| |
| t0.norm(); |
| t1.norm(); |
| |
| z1.copy(t0); |
| z1.mul(t1); |
| t0.copy(this.b); |
| t0.add(this.c); |
| |
| t1.copy(y.b); |
| t1.add(y.c); |
| |
| t0.norm(); |
| t1.norm(); |
| z3.copy(t0); |
| z3.mul(t1); |
| |
| t0.copy(z0); |
| t0.neg(); |
| t1.copy(z2); |
| t1.neg(); |
| |
| z1.add(t0); |
| this.b.copy(z1); |
| this.b.add(t1); |
| |
| z3.add(t1); |
| z2.add(t0); |
| |
| t0.copy(this.a); |
| t0.add(this.c); |
| t1.copy(y.a); |
| t1.add(y.c); |
| |
| t0.norm(); |
| t1.norm(); |
| |
| t0.mul(t1); |
| z2.add(t0); |
| |
| t0.copy(this.c); |
| t0.mul(y.c); |
| t1.copy(t0); |
| t1.neg(); |
| |
| this.c.copy(z2); |
| this.c.add(t1); |
| z3.add(t1); |
| t0.times_i(); |
| this.b.add(t0); |
| |
| z3.times_i(); |
| this.a.copy(z0); |
| this.a.add(z3); |
| this.stype=ctx.FP.DENSE; |
| this.norm(); |
| }, |
| |
| /* FP48 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 */ |
| smul: function(y) { |
| if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.D_TYPE) |
| { |
| var w1=new ctx.FP8(this.a.geta()); |
| var w2=new ctx.FP8(this.a.getb()); |
| var w3=new ctx.FP8(this.b.geta()); |
| |
| w1.mul(y.a.geta()); |
| w2.mul(y.a.getb()); |
| w3.mul(y.b.geta()); |
| |
| var ta=new ctx.FP8(this.a.geta()); |
| var tb=new ctx.FP8(y.a.geta()); |
| ta.add(this.a.getb()); ta.norm(); |
| tb.add(y.a.getb()); tb.norm(); |
| var tc=new ctx.FP8(ta); |
| tc.mul(tb); |
| var t=new ctx.FP8(w1); |
| t.add(w2); |
| t.neg(); |
| tc.add(t); |
| |
| ta.copy(this.a.geta()); ta.add(this.b.geta()); ta.norm(); |
| tb.copy(y.a.geta()); tb.add(y.b.geta()); tb.norm(); |
| var td=new ctx.FP8(ta); |
| td.mul(tb); |
| t.copy(w1); |
| t.add(w3); |
| t.neg(); |
| td.add(t); |
| |
| ta.copy(this.a.getb()); ta.add(this.b.geta()); ta.norm(); |
| tb.copy(y.a.getb()); tb.add(y.b.geta()); tb.norm(); |
| var te=new ctx.FP8(ta); |
| te.mul(tb); |
| t.copy(w2); |
| t.add(w3); |
| t.neg(); |
| te.add(t); |
| |
| w2.times_i(); |
| w1.add(w2); |
| |
| this.a.geta().copy(w1); this.a.getb().copy(tc); |
| this.b.geta().copy(td); this.b.getb().copy(te); |
| this.c.geta().copy(w3); this.c.getb().zero(); |
| |
| this.a.norm(); |
| this.b.norm(); |
| |
| } else { |
| var w1=new ctx.FP8(this.a.geta()); |
| var w2=new ctx.FP8(this.a.getb()); |
| var w3=new ctx.FP8(this.c.getb()); |
| |
| w1.mul(y.a.geta()); |
| w2.mul(y.a.getb()); |
| w3.mul(y.c.getb()); |
| |
| var ta=new ctx.FP8(this.a.geta()); |
| var tb=new ctx.FP8(y.a.geta()); |
| ta.add(this.a.getb()); ta.norm(); |
| tb.add(y.a.getb()); tb.norm(); |
| var tc=new ctx.FP8(ta); |
| tc.mul(tb); |
| var t=new ctx.FP8(w1); |
| t.add(w2); |
| t.neg(); |
| tc.add(t); |
| |
| ta.copy(this.a.geta()); ta.add(this.c.getb()); ta.norm(); |
| tb.copy(y.a.geta()); tb.add(y.c.getb()); tb.norm(); |
| var td=new ctx.FP8(ta); |
| td.mul(tb); |
| t.copy(w1); |
| t.add(w3); |
| t.neg(); |
| td.add(t); |
| |
| ta.copy(this.a.getb()); ta.add(this.c.getb()); ta.norm(); |
| tb.copy(y.a.getb()); tb.add(y.c.getb()); tb.norm(); |
| var te=new ctx.FP8(ta); |
| te.mul(tb); |
| t.copy(w2); |
| t.add(w3); |
| t.neg(); |
| te.add(t); |
| |
| w2.times_i(); |
| w1.add(w2); |
| this.a.geta().copy(w1); this.a.getb().copy(tc); |
| |
| w3.times_i(); |
| w3.norm(); |
| this.b.geta().zero(); this.b.getb().copy(w3); |
| |
| te.norm(); |
| te.times_i(); |
| this.c.geta().copy(te); |
| this.c.getb().copy(td); |
| |
| this.a.norm(); |
| this.c.norm(); |
| |
| } |
| this.stype=ctx.FP.SPARSE; |
| }, |
| |
| /* FP48 full multiplication w=w*y */ |
| /* Supports sparse multiplicands */ |
| /* Usually w is denser than y */ |
| ssmul: function(y) { |
| if (this.stype==ctx.FP.ONE) |
| { |
| this.copy(y); |
| return; |
| } |
| if (y.stype==ctx.FP.ONE) |
| return; |
| |
| if (y.stype>=ctx.FP.SPARSE) |
| { |
| var z0=new ctx.FP16(this.a); |
| var z1=new ctx.FP16(0); |
| var z2=new ctx.FP16(0); |
| var z3=new ctx.FP16(0); |
| z0.mul(y.a); |
| |
| if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.M_TYPE) |
| { |
| if (y.stype==ctx.FP.SPARSE || this.stype==ctx.FP.SPARSE) |
| { |
| z2.getb().copy(this.b.getb()); |
| z2.getb().mul(y.b.getb()); |
| z2.geta().zero(); |
| if (y.stype!=ctx.FP.SPARSE) |
| { |
| z2.geta().copy(this.b.getb()); |
| z2.geta().mul(y.b.geta()); |
| } |
| if (this.stype!=ctx.FP.SPARSE) |
| { |
| z2.geta().copy(this.b.geta()); |
| z2.geta().mul(y.b.getb()); |
| } |
| z2.times_i(); |
| } else { |
| z2.copy(this.b); |
| z2.mul(y.b); |
| } |
| } else { |
| z2.copy(this.b); |
| z2.mul(y.b); |
| } |
| var t0=new ctx.FP16(this.a); |
| var t1=new ctx.FP16(y.a); |
| t0.add(this.b); t0.norm(); |
| t1.add(y.b); t1.norm(); |
| |
| z1.copy(t0); z1.mul(t1); |
| t0.copy(this.b); t0.add(this.c); t0.norm(); |
| t1.copy(y.b); t1.add(y.c); t1.norm(); |
| |
| z3.copy(t0); z3.mul(t1); |
| |
| t0.copy(z0); t0.neg(); |
| t1.copy(z2); t1.neg(); |
| |
| z1.add(t0); |
| this.b.copy(z1); this.b.add(t1); |
| |
| z3.add(t1); |
| z2.add(t0); |
| |
| t0.copy(this.a); t0.add(this.c); t0.norm(); |
| t1.copy(y.a); t1.add(y.c); t1.norm(); |
| |
| t0.mul(t1); |
| z2.add(t0); |
| |
| if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.D_TYPE) |
| { |
| if (y.stype==ctx.FP.SPARSE || this.stype==ctx.FP.SPARSE) |
| { |
| t0.geta().copy(this.c.geta()); |
| t0.geta().mul(y.c.geta()); |
| t0.getb().zero(); |
| if (y.stype!=ctx.FP.SPARSE) |
| { |
| t0.getb().copy(this.c.geta()); |
| t0.getb().mul(y.c.getb()); |
| } |
| if (this.stype!=ctx.FP.SPARSE) |
| { |
| t0.getb().copy(this.c.getb()); |
| t0.getb().mul(y.c.geta()); |
| } |
| } else { |
| t0.copy(this.c); |
| t0.mul(y.c); |
| } |
| } else { |
| t0.copy(this.c); |
| t0.mul(y.c); |
| } |
| t1.copy(t0); t1.neg(); |
| |
| this.c.copy(z2); this.c.add(t1); |
| z3.add(t1); |
| t0.times_i(); |
| this.b.add(t0); |
| z3.norm(); |
| z3.times_i(); |
| this.a.copy(z0); this.a.add(z3); |
| } else { |
| if (this.stype==ctx.FP.SPARSER) |
| { |
| this.smul(y); |
| return; |
| } |
| if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.D_TYPE) |
| { // dense by sparser - 13m |
| var z0=new ctx.FP16(this.a); |
| var z2=new ctx.FP16(this.b); |
| var z3=new ctx.FP16(this.b); |
| var t0=new ctx.FP16(0); |
| var t1=new ctx.FP16(y.a); |
| z0.mul(y.a); |
| z2.pmul(y.b.real()); |
| this.b.add(this.a); |
| t1.real().add(y.b.real()); |
| |
| t1.norm(); |
| this.b.norm(); |
| this.b.mul(t1); |
| z3.add(this.c); |
| z3.norm(); |
| z3.pmul(y.b.real()); |
| |
| t0.copy(z0); t0.neg(); |
| t1.copy(z2); t1.neg(); |
| |
| this.b.add(t0); |
| |
| this.b.add(t1); |
| z3.add(t1); |
| z2.add(t0); |
| |
| t0.copy(this.a); t0.add(this.c); t0.norm(); |
| z3.norm(); |
| t0.mul(y.a); |
| this.c.copy(z2); this.c.add(t0); |
| |
| z3.times_i(); |
| this.a.copy(z0); this.a.add(z3); |
| } |
| if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.M_TYPE) |
| { |
| var z0=new ctx.FP16(this.a); |
| var z1=new ctx.FP16(0); |
| var z2=new ctx.FP16(0); |
| var z3=new ctx.FP16(0); |
| var t0=new ctx.FP16(this.a); |
| var t1=new ctx.FP16(0); |
| |
| z0.mul(y.a); |
| t0.add(this.b); t0.norm(); |
| |
| z1.copy(t0); z1.mul(y.a); |
| t0.copy(this.b); t0.add(this.c); |
| t0.norm(); |
| |
| z3.copy(t0); |
| z3.pmul(y.c.getb()); |
| z3.times_i(); |
| |
| t0.copy(z0); t0.neg(); |
| z1.add(t0); |
| this.b.copy(z1); |
| z2.copy(t0); |
| |
| t0.copy(this.a); t0.add(this.c); t0.norm(); |
| t1.copy(y.a); t1.add(y.c); t1.norm(); |
| |
| t0.mul(t1); |
| z2.add(t0); |
| t0.copy(this.c); |
| |
| t0.pmul(y.c.getb()); |
| t0.times_i(); |
| t1.copy(t0); t1.neg(); |
| |
| this.c.copy(z2); this.c.add(t1); |
| z3.add(t1); |
| t0.times_i(); |
| this.b.add(t0); |
| z3.norm(); |
| z3.times_i(); |
| this.a.copy(z0); this.a.add(z3); |
| } |
| } |
| this.stype=ctx.FP.DENSE; |
| this.norm(); |
| }, |
| |
| |
| /* this=1/this */ |
| inverse: function() { |
| var f0 = new ctx.FP16(this.a), |
| f1 = new ctx.FP16(this.b), |
| f2 = new ctx.FP16(this.a), |
| f3 = new ctx.FP16(0); |
| |
| f0.sqr(); |
| f1.mul(this.c); |
| f1.times_i(); |
| f0.sub(f1); |
| f0.norm(); |
| |
| f1.copy(this.c); |
| f1.sqr(); |
| f1.times_i(); |
| f2.mul(this.b); |
| f1.sub(f2); |
| f1.norm(); |
| |
| f2.copy(this.b); |
| f2.sqr(); |
| f3.copy(this.a); |
| f3.mul(this.c); |
| f2.sub(f3); |
| f2.norm(); |
| |
| f3.copy(this.b); |
| f3.mul(f2); |
| f3.times_i(); |
| this.a.mul(f0); |
| f3.add(this.a); |
| this.c.mul(f1); |
| this.c.times_i(); |
| |
| f3.add(this.c); |
| f3.norm(); |
| f3.inverse(); |
| this.a.copy(f0); |
| this.a.mul(f3); |
| this.b.copy(f1); |
| this.b.mul(f3); |
| this.c.copy(f2); |
| this.c.mul(f3); |
| this.stype=ctx.FP.DENSE; |
| }, |
| |
| /* this=this^p, where p=Modulus, using Frobenius */ |
| frob: function(f,n) { |
| var f2 = new ctx.FP2(f), |
| f3 = new ctx.FP2(f), |
| i; |
| |
| f2.sqr(); |
| f3.mul(f2); |
| |
| f3.mul_ip(); f3.norm(); |
| f3.mul_ip(); f3.norm(); |
| |
| for (i=0;i<n;i++) { |
| this.a.frob(f3); |
| this.b.frob(f3); |
| this.c.frob(f3); |
| |
| this.b.qmul(f); this.b.times_i4(); this.b.times_i2(); |
| this.c.qmul(f2); this.c.times_i4(); this.c.times_i4(); this.c.times_i4(); |
| } |
| this.stype=ctx.FP.DENSE; |
| }, |
| |
| /* trace function */ |
| trace: function() { |
| var t = new ctx.FP16(0); |
| |
| t.copy(this.a); |
| t.imul(3); |
| t.reduce(); |
| |
| return t; |
| }, |
| |
| /* convert this to hex string */ |
| toString: function() { |
| return ("[" + this.a.toString() + "," + this.b.toString() + "," + this.c.toString() + "]"); |
| }, |
| |
| /* convert this to byte array */ |
| toBytes: function(w) { |
| var t = [], |
| i; |
| |
| this.a.geta().geta().geta().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i] = t[i]; |
| } |
| this.a.geta().geta().geta().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.a.geta().geta().getb().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 2 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.a.geta().geta().getb().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 3 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| |
| this.a.geta().getb().geta().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 4 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.a.geta().getb().geta().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 5 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.a.geta().getb().getb().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 6 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.a.geta().getb().getb().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 7 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| |
| this.a.getb().geta().geta().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 8 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.a.getb().geta().geta().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 9 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.a.getb().geta().getb().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 10 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.a.getb().geta().getb().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 11 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| |
| this.a.getb().getb().geta().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 12 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.a.getb().getb().geta().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 13 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.a.getb().getb().getb().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 14 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.a.getb().getb().getb().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 15 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| |
| this.b.geta().geta().geta().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 16 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.b.geta().geta().geta().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 17 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.b.geta().geta().getb().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 18 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.b.geta().geta().getb().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 19 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| |
| this.b.geta().getb().geta().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 20 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.b.geta().getb().geta().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 21 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.b.geta().getb().getb().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 22 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.b.geta().getb().getb().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 23 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| |
| this.b.getb().geta().geta().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 24 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.b.getb().geta().geta().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 25 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.b.getb().geta().getb().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 26 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.b.getb().geta().getb().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 27 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| |
| this.b.getb().getb().geta().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 28 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.b.getb().getb().geta().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 29 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.b.getb().getb().getb().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 30 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.b.getb().getb().getb().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 31 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| |
| this.c.geta().geta().geta().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 32 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.c.geta().geta().geta().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 33 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.c.geta().geta().getb().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 34 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.c.geta().geta().getb().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 35 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| |
| this.c.geta().getb().geta().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 36 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.c.geta().getb().geta().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 37 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.c.geta().getb().getb().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 38 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.c.geta().getb().getb().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 39 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| |
| this.c.getb().geta().geta().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 40 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.c.getb().geta().geta().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 41 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.c.getb().geta().getb().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 42 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.c.getb().geta().getb().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 43 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| |
| this.c.getb().getb().geta().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 44 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.c.getb().getb().geta().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 45 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.c.getb().getb().getb().getA().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 46 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| this.c.getb().getb().getb().getB().toBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| w[i + 47 * ctx.BIG.MODBYTES] = t[i]; |
| } |
| }, |
| |
| /* set this=this^e */ |
| pow: function(e) { |
| var e1, e3, w, nb, i, bt, sf; |
| |
| sf = new FP48(this); |
| sf.norm(); |
| e1 = new ctx.BIG(e); |
| e1.norm(); |
| |
| e3 = new ctx.BIG(e1); |
| e3.pmul(3); |
| e3.norm(); |
| |
| w = new FP48(sf); //w.copy(this); |
| nb = e3.nbits(); |
| |
| for (i = nb - 2; i >= 1; i--) { |
| w.usqr(); |
| bt = e3.bit(i) - e1.bit(i); |
| |
| if (bt == 1) { |
| w.mul(sf); |
| } |
| if (bt == -1) { |
| sf.conj(); |
| w.mul(sf); |
| sf.conj(); |
| } |
| } |
| w.reduce(); |
| |
| return w; |
| }, |
| |
| /* constant time powering by small integer of max length bts */ |
| pinpow: function(e, bts) { |
| var R = [], |
| i, b; |
| |
| R[0] = new FP48(1); |
| R[1] = new FP48(this); |
| |
| for (i = bts - 1; i >= 0; i--) { |
| b = (e >> i) & 1; |
| R[1 - b].mul(R[b]); |
| R[b].usqr(); |
| } |
| |
| this.copy(R[0]); |
| }, |
| |
| /* Faster compressed powering for unitary elements */ |
| compow: function(e, r) { |
| var fa, fb, f, q, m, a, b, g1, g2, c, cp, cpm1, cpm2; |
| |
| fa = new ctx.BIG(0); |
| fa.rcopy(ctx.ROM_FIELD.Fra); |
| fb = new ctx.BIG(0); |
| fb.rcopy(ctx.ROM_FIELD.Frb); |
| f = new ctx.FP2(fa, fb); |
| |
| q = new ctx.BIG(0); |
| q.rcopy(ctx.ROM_FIELD.Modulus); |
| |
| m = new ctx.BIG(q); |
| m.mod(r); |
| |
| a = new ctx.BIG(e); |
| a.mod(m); |
| |
| b = new ctx.BIG(e); |
| b.div(m); |
| |
| g1 = new FP48(0); |
| g2 = new FP48(0); |
| g1.copy(this); |
| |
| c = g1.trace(); |
| |
| if (b.iszilch()) { |
| c=c.xtr_pow(e); |
| return c; |
| } |
| |
| g2.copy(g1); |
| g2.frob(f,1); |
| cp = g2.trace(); |
| g1.conj(); |
| g2.mul(g1); |
| cpm1 = g2.trace(); |
| g2.mul(g1); |
| cpm2 = g2.trace(); |
| |
| c = c.xtr_pow2(cp, cpm1, cpm2, a, b); |
| return c; |
| } |
| }; |
| |
| /* convert from byte array to FP12 */ |
| FP48.fromBytes = function(w) { |
| var t = [], |
| i, a, b, c, d, e, f, g, r, ea, eb, fa, fb; |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| c = new ctx.FP2(a, b); //c.bset(a,b); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 2 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 3 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| d = new ctx.FP2(a, b); //d.bset(a,b); |
| |
| ea = new ctx.FP4(c, d); //e.set(c,d); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 4 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 5 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| c = new ctx.FP2(a, b); //c.bset(a,b); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 6 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 7 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| d = new ctx.FP2(a, b); //d.bset(a,b); |
| |
| eb = new ctx.FP4(c, d); //e.set(c,d); |
| |
| fa = new ctx.FP8(ea,eb); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 8 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 9 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| c = new ctx.FP2(a, b); //c.bset(a,b); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 10 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 11 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| d = new ctx.FP2(a, b); //d.bset(a,b); |
| |
| ea = new ctx.FP4(c, d); //e.set(c,d); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 12 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 13 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| c = new ctx.FP2(a, b); //c.bset(a,b); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 14 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 15 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| d = new ctx.FP2(a, b); //d.bset(a,b); |
| |
| eb = new ctx.FP4(c, d); //e.set(c,d); |
| |
| fb = new ctx.FP8(ea,eb); |
| |
| e = new ctx.FP16(fa,fb); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 16 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 17 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| c = new ctx.FP2(a, b); //c.bset(a,b); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 18 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 19 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| d = new ctx.FP2(a, b); |
| |
| ea = new ctx.FP4(c, d); //e.set(c,d); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 20 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 21 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| c = new ctx.FP2(a, b); //c.bset(a,b); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 22 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 23 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| d = new ctx.FP2(a, b); |
| |
| eb = new ctx.FP4(c, d); //e.set(c,d); |
| |
| fa = new ctx.FP8(ea,eb); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 24 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 25 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| c = new ctx.FP2(a, b); //c.bset(a,b); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 26 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 27 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| d = new ctx.FP2(a, b); |
| |
| ea = new ctx.FP4(c, d); //e.set(c,d); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 28 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 29 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| c = new ctx.FP2(a, b); //c.bset(a,b); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 30 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 31 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| d = new ctx.FP2(a, b); |
| |
| eb = new ctx.FP4(c, d); //e.set(c,d); |
| |
| fb = new ctx.FP8(ea,eb); |
| |
| f = new ctx.FP16(fa, fb); //f.set(c,d); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 32 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 33 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| c = new ctx.FP2(a, b); //c.bset(a,b); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 34 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 35 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| d = new ctx.FP2(a, b); //d.bset(a,b); |
| |
| ea = new ctx.FP4(c, d); //e.set(c,d); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 36 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 37 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| c = new ctx.FP2(a, b); //c.bset(a,b); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 38 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 39 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| d = new ctx.FP2(a, b); //d.bset(a,b); |
| |
| eb = new ctx.FP4(c, d); //e.set(c,d); |
| |
| fa = new ctx.FP8(ea,eb); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 40 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 41 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| c = new ctx.FP2(a, b); //c.bset(a,b); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 42 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 43 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| d = new ctx.FP2(a, b); //d.bset(a,b); |
| |
| ea = new ctx.FP4(c, d); //e.set(c,d); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 44 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 45 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| c = new ctx.FP2(a, b); //c.bset(a,b); |
| |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 46 * ctx.BIG.MODBYTES]; |
| } |
| a = ctx.BIG.fromBytes(t); |
| for (i = 0; i < ctx.BIG.MODBYTES; i++) { |
| t[i] = w[i + 47 * ctx.BIG.MODBYTES]; |
| } |
| b = ctx.BIG.fromBytes(t); |
| d = new ctx.FP2(a, b); //d.bset(a,b); |
| |
| eb = new ctx.FP4(c, d); //e.set(c,d); |
| |
| fb = new ctx.FP8(ea,eb); |
| |
| g = new ctx.FP16(fa, fb); //g.set(c,d); |
| |
| r = new FP48(e, f, g); //r.set(e,f,g); |
| |
| return r; |
| }; |
| |
| /* return 1 if b==c, no branching */ |
| FP48.teq = function(b, c) { |
| var x = b ^ c; |
| x -= 1; // if x=0, x now -1 |
| return ((x >> 31) & 1); |
| }; |
| |
| /* p=q0^u0.q1^u1.q2^u2.q3^u3... */ |
| // Bos & Costello https://eprint.iacr.org/2013/458.pdf |
| // Faz-Hernandez & Longa & Sanchez https://eprint.iacr.org/2013/158.pdf |
| // Side channel attack secure |
| FP48.pow16 = function(q, u) { |
| var g1 = [], |
| g2 = [], |
| g3 = [], |
| g4 = [], |
| r = new FP48(0), |
| p = new FP48(0), |
| t = [], |
| mt = new ctx.BIG(0), |
| fa = new ctx.BIG(0), |
| fb = new ctx.BIG(0), |
| w1 = [], |
| s1 = [], |
| w2 = [], |
| s2 = [], |
| w3 = [], |
| s3 = [], |
| w4 = [], |
| s4 = [], |
| i, j, k, nb, bt, pb1, pb2, pb3, pb4, f; |
| |
| for (i = 0; i < 16; i++) { |
| t[i] = new ctx.BIG(u[i]); t[i].norm(); |
| } |
| |
| g1[0] = new FP48(q[0]); // q[0] |
| g1[1] = new FP48(g1[0]); g1[1].mul(q[1]); // q[0].q[1] |
| g1[2] = new FP48(g1[0]); g1[2].mul(q[2]); // q[0].q[2] |
| g1[3] = new FP48(g1[1]); g1[3].mul(q[2]); // q[0].q[1].q[2] |
| g1[4] = new FP48(q[0]); g1[4].mul(q[3]); // q[0].q[3] |
| g1[5] = new FP48(g1[1]); g1[5].mul(q[3]); // q[0].q[1].q[3] |
| g1[6] = new FP48(g1[2]); g1[6].mul(q[3]); // q[0].q[2].q[3] |
| g1[7] = new FP48(g1[3]); g1[7].mul(q[3]); // q[0].q[1].q[2].q[3] |
| |
| // Use Frobenius |
| fa.rcopy(ctx.ROM_FIELD.Fra); |
| fb.rcopy(ctx.ROM_FIELD.Frb); |
| f = new ctx.FP2(fa, fb); |
| |
| for (i=0;i<8;i++) { |
| g2[i]=new FP48(g1[i]); |
| g2[i].frob(f,4); |
| g3[i]=new FP48(g2[i]); |
| g3[i].frob(f,4); |
| g4[i]=new FP48(g3[i]); |
| g4[i].frob(f,4); |
| |
| } |
| |
| // Make it odd |
| pb1=1-t[0].parity(); |
| t[0].inc(pb1); |
| t[0].norm(); |
| |
| pb2=1-t[4].parity(); |
| t[4].inc(pb2); |
| t[4].norm(); |
| |
| pb3=1-t[8].parity(); |
| t[8].inc(pb3); |
| t[8].norm(); |
| |
| pb4=1-t[12].parity(); |
| t[12].inc(pb4); |
| t[12].norm(); |
| |
| // Number of bits |
| mt.zero(); |
| for (i=0;i<16;i++) { |
| mt.or(t[i]); |
| } |
| |
| nb=1+mt.nbits(); |
| |
| // Sign pivot |
| s1[nb-1]=1; |
| s2[nb-1]=1; |
| s3[nb-1]=1; |
| s4[nb-1]=1; |
| for (i=0;i<nb-1;i++) { |
| t[0].fshr(1); |
| s1[i]=2*t[0].parity()-1; |
| t[4].fshr(1); |
| s2[i]=2*t[4].parity()-1; |
| t[8].fshr(1); |
| s3[i]=2*t[8].parity()-1; |
| t[12].fshr(1); |
| s4[i]=2*t[12].parity()-1; |
| |
| } |
| |
| // Recoded exponent |
| for (i=0; i<nb; i++) { |
| w1[i]=0; |
| k=1; |
| for (j=1; j<4; j++) { |
| bt=s1[i]*t[j].parity(); |
| t[j].fshr(1); |
| t[j].dec(bt>>1); |
| t[j].norm(); |
| w1[i]+=bt*k; |
| k*=2; |
| } |
| w2[i]=0; |
| k=1; |
| for (j=5; j<8; j++) { |
| bt=s2[i]*t[j].parity(); |
| t[j].fshr(1); |
| t[j].dec(bt>>1); |
| t[j].norm(); |
| w2[i]+=bt*k; |
| k*=2; |
| } |
| w3[i]=0; |
| k=1; |
| for (j=9; j<12; j++) { |
| bt=s3[i]*t[j].parity(); |
| t[j].fshr(1); |
| t[j].dec(bt>>1); |
| t[j].norm(); |
| w3[i]+=bt*k; |
| k*=2; |
| } |
| w4[i]=0; |
| k=1; |
| for (j=13; j<16; j++) { |
| bt=s4[i]*t[j].parity(); |
| t[j].fshr(1); |
| t[j].dec(bt>>1); |
| t[j].norm(); |
| w4[i]+=bt*k; |
| k*=2; |
| } |
| } |
| |
| // Main loop |
| p.select(g1,2*w1[nb-1]+1); |
| r.select(g2,2*w2[nb-1]+1); |
| p.mul(r); |
| r.select(g3,2*w3[nb-1]+1); |
| p.mul(r); |
| r.select(g4,2*w4[nb-1]+1); |
| p.mul(r); |
| for (i=nb-2;i>=0;i--) { |
| p.usqr(); |
| r.select(g1,2*w1[i]+s1[i]); |
| p.mul(r); |
| r.select(g2,2*w2[i]+s2[i]); |
| p.mul(r); |
| r.select(g3,2*w3[i]+s3[i]); |
| p.mul(r); |
| r.select(g4,2*w4[i]+s4[i]); |
| p.mul(r); |
| } |
| |
| // apply correction |
| r.copy(q[0]); r.conj(); |
| r.mul(p); |
| p.cmove(r,pb1); |
| |
| r.copy(q[4]); r.conj(); |
| r.mul(p); |
| p.cmove(r,pb2); |
| |
| r.copy(q[8]); r.conj(); |
| r.mul(p); |
| p.cmove(r,pb3); |
| |
| r.copy(q[12]); r.conj(); |
| r.mul(p); |
| p.cmove(r,pb4); |
| |
| p.reduce(); |
| return p; |
| }; |
| |
| return FP48; |
| }; |