| /* |
| 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. |
| */ |
| |
| // |
| // fp24.swift |
| // |
| // Created by Michael Scott on 07/07/2015. |
| // Copyright (c) 2015 Michael Scott. All rights reserved. |
| // |
| |
| /* AMCL Fp^24 functions */ |
| /* FP24 elements are of the form a+i.b+i^2.c */ |
| |
| public struct FP24 |
| { |
| static public let ZERO:Int=0 |
| static public let ONE:Int=1 |
| static public let SPARSER:Int=2 |
| static public let SPARSE:Int=3 |
| static public let DENSE:Int=4 |
| |
| private var a:FP8 |
| private var b:FP8 |
| private var c:FP8 |
| private var stype:Int |
| |
| /* reduce all components of this mod Modulus */ |
| mutating func reduce() |
| { |
| a.reduce() |
| b.reduce() |
| c.reduce() |
| } |
| /* normalise all components of this */ |
| mutating func norm() |
| { |
| a.norm(); |
| b.norm(); |
| c.norm(); |
| } |
| |
| mutating func settype(_ t:Int) |
| { |
| stype=t |
| } |
| |
| mutating func gettype() -> Int |
| { |
| return stype |
| } |
| |
| /* Constructors */ |
| init(_ d:FP8) |
| { |
| a=FP8(d) |
| b=FP8() |
| c=FP8() |
| stype=FP24.SPARSER |
| } |
| |
| init() |
| { |
| a=FP8() |
| b=FP8() |
| c=FP8() |
| stype=FP24.ZERO |
| } |
| |
| init(_ d:Int) |
| { |
| a=FP8(d) |
| b=FP8() |
| c=FP8() |
| if (d==1) {stype=FP24.ONE} |
| else {stype=FP24.SPARSER} |
| } |
| |
| init(_ d:FP8,_ e:FP8,_ f:FP8) |
| { |
| a=FP8(d) |
| b=FP8(e) |
| c=FP8(f) |
| stype=FP24.DENSE |
| } |
| |
| init(_ x:FP24) |
| { |
| a=FP8(x.a) |
| b=FP8(x.b) |
| c=FP8(x.c) |
| stype=x.stype |
| } |
| /* test x==0 ? */ |
| func iszilch() -> Bool |
| { |
| return a.iszilch() && b.iszilch() && c.iszilch() |
| } |
| |
| mutating func cmove(_ g:FP24,_ d:Int) |
| { |
| a.cmove(g.a,d) |
| b.cmove(g.b,d) |
| c.cmove(g.c,d) |
| let u = ~(d-1) |
| stype^=(stype^g.stype)&u |
| } |
| |
| /* return 1 if b==c, no branching */ |
| private static func teq(_ b:Int32,_ c:Int32) -> Int |
| { |
| var x=b^c |
| x-=1 // if x=0, x now -1 |
| return Int((x>>31)&1) |
| } |
| /* Constant time select from pre-computed table */ |
| mutating func select(_ g:[FP24],_ b:Int32) |
| { |
| |
| let m=b>>31 |
| var babs=(b^m)-m |
| |
| babs=(babs-1)/2 |
| |
| cmove(g[0],FP24.teq(babs,0)) // conditional move |
| cmove(g[1],FP24.teq(babs,1)) |
| cmove(g[2],FP24.teq(babs,2)) |
| cmove(g[3],FP24.teq(babs,3)) |
| cmove(g[4],FP24.teq(babs,4)) |
| cmove(g[5],FP24.teq(babs,5)) |
| cmove(g[6],FP24.teq(babs,6)) |
| cmove(g[7],FP24.teq(babs,7)) |
| |
| var invf=FP24(self) |
| invf.conj() |
| cmove(invf,Int(m&1)) |
| } |
| |
| /* test x==1 ? */ |
| public func isunity() -> Bool |
| { |
| let one=FP8(1) |
| return a.equals(one) && b.iszilch() && c.iszilch() |
| } |
| /* return 1 if x==y, else 0 */ |
| public func equals(_ x:FP24) -> Bool |
| { |
| return a.equals(x.a) && b.equals(x.b) && c.equals(x.c) |
| } |
| /* extract a from self */ |
| func geta() -> FP8 |
| { |
| return a |
| } |
| /* extract b */ |
| func getb() -> FP8 |
| { |
| return b |
| } |
| /* extract c */ |
| func getc() -> FP8 |
| { |
| return c |
| } |
| /* copy self=x */ |
| public mutating func copy(_ x:FP24) |
| { |
| a.copy(x.a) |
| b.copy(x.b) |
| c.copy(x.c) |
| stype=x.stype |
| } |
| /* set self=1 */ |
| mutating func one() |
| { |
| a.one() |
| b.zero() |
| c.zero() |
| stype=FP24.ONE |
| } |
| |
| /* set self=0 */ |
| mutating func zero() |
| { |
| a.zero() |
| b.zero() |
| c.zero() |
| stype=FP24.ZERO |
| } |
| |
| /* self=conj(self) */ |
| mutating func conj() |
| { |
| a.conj() |
| b.nconj() |
| c.conj() |
| } |
| |
| /* Granger-Scott Unitary Squaring */ |
| mutating func usqr() |
| { |
| var A=FP8(a) |
| var B=FP8(c) |
| var C=FP8(b) |
| var D=FP8() |
| |
| a.sqr() |
| D.copy(a); D.add(a) |
| a.add(D) |
| |
| a.norm() |
| A.nconj() |
| |
| A.add(A) |
| a.add(A) |
| B.sqr() |
| B.times_i() |
| |
| D.copy(B); D.add(B) |
| B.add(D) |
| B.norm() |
| |
| C.sqr() |
| D.copy(C); D.add(C) |
| C.add(D) |
| C.norm() |
| |
| b.conj() |
| b.add(b) |
| c.nconj() |
| |
| c.add(c) |
| b.add(B) |
| c.add(C) |
| stype=FP24.DENSE |
| reduce() |
| |
| } |
| |
| /* Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */ |
| mutating func sqr() |
| { |
| if (stype==FP24.ONE) {return} |
| var A=FP8(a) |
| var B=FP8(b) |
| var C=FP8(c) |
| var D=FP8(a) |
| |
| A.sqr() |
| B.mul(c) |
| B.add(B); B.norm() |
| C.sqr() |
| D.mul(b) |
| D.add(D) |
| |
| c.add(a) |
| c.add(b); c.norm() |
| c.sqr() |
| |
| a.copy(A) |
| |
| A.add(B) |
| A.norm() |
| A.add(C) |
| A.add(D) |
| A.norm() |
| |
| A.neg() |
| B.times_i() |
| C.times_i() |
| |
| a.add(B) |
| |
| b.copy(C); b.add(D) |
| c.add(A) |
| if (stype==FP24.SPARSER) { |
| stype=FP24.SPARSE |
| } else { |
| stype=FP24.DENSE |
| } |
| norm() |
| } |
| |
| /* FP24 full multiplication this=this*y */ |
| mutating func mul(_ y:FP24) |
| { |
| var z0=FP8(a) |
| var z1=FP8() |
| var z2=FP8(b) |
| var z3=FP8() |
| var t0=FP8(a) |
| var t1=FP8(y.a) |
| |
| z0.mul(y.a) |
| z2.mul(y.b) |
| |
| t0.add(b) |
| t1.add(y.b) |
| |
| t0.norm(); t1.norm() |
| |
| z1.copy(t0); z1.mul(t1) |
| t0.copy(b); t0.add(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) |
| b.copy(z1); b.add(t1) |
| |
| z3.add(t1) |
| z2.add(t0) |
| |
| t0.copy(a); t0.add(c) |
| t1.copy(y.a); t1.add(y.c) |
| |
| t0.norm(); t1.norm() |
| |
| t0.mul(t1) |
| z2.add(t0) |
| |
| t0.copy(c); t0.mul(y.c) |
| t1.copy(t0); t1.neg() |
| |
| c.copy(z2); c.add(t1) |
| z3.add(t1) |
| t0.times_i() |
| b.add(t0) |
| |
| z3.norm() |
| z3.times_i() |
| a.copy(z0); a.add(z3) |
| stype=FP24.DENSE |
| norm() |
| } |
| |
| /* FP24 full multiplication w=w*y */ |
| /* Supports sparse multiplicands */ |
| /* Usually w is denser than y */ |
| mutating func ssmul(_ y:FP24) |
| { |
| if stype==FP24.ONE { |
| copy(y) |
| return |
| } |
| if y.stype==FP24.ONE { |
| return |
| } |
| if y.stype>=FP24.SPARSE { |
| var z0=FP8(a) |
| var z1=FP8() |
| var z2=FP8() |
| var z3=FP8() |
| z0.mul(y.a) |
| |
| if CONFIG_CURVE.SEXTIC_TWIST == CONFIG_CURVE.M_TYPE { |
| if y.stype==FP24.SPARSE || stype==FP24.SPARSE { |
| var ga=FP4() |
| var gb=FP4() |
| |
| gb.copy(b.getb()) |
| gb.mul(y.b.getb()) |
| ga.zero() |
| if y.stype != FP24.SPARSE { |
| ga.copy(b.getb()) |
| ga.mul(y.b.geta()) |
| } |
| if stype != FP24.SPARSE { |
| ga.copy(b.geta()) |
| ga.mul(y.b.getb()) |
| } |
| z2.set_fp4s(ga,gb) |
| z2.times_i() |
| } else { |
| z2.copy(b) |
| z2.mul(y.b) |
| } |
| } else { |
| z2.copy(b) |
| z2.mul(y.b) |
| } |
| var t0=FP8(a) |
| var t1=FP8(y.a) |
| t0.add(b); t0.norm() |
| t1.add(y.b); t1.norm() |
| |
| z1.copy(t0); z1.mul(t1) |
| t0.copy(b); t0.add(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) |
| b.copy(z1); b.add(t1) |
| |
| z3.add(t1) |
| z2.add(t0) |
| |
| t0.copy(a); t0.add(c); t0.norm() |
| t1.copy(y.a); t1.add(y.c); t1.norm() |
| |
| t0.mul(t1) |
| z2.add(t0) |
| |
| if CONFIG_CURVE.SEXTIC_TWIST == CONFIG_CURVE.D_TYPE { |
| if y.stype==FP24.SPARSE || stype==FP24.SPARSE { |
| var ga=FP4() |
| var gb=FP4() |
| |
| ga.copy(c.geta()) |
| ga.mul(y.c.geta()) |
| gb.zero() |
| if y.stype != FP24.SPARSE { |
| gb.copy(c.geta()) |
| gb.mul(y.c.getb()) |
| } |
| if stype != FP24.SPARSE { |
| gb.copy(c.getb()) |
| gb.mul(y.c.geta()) |
| } |
| t0.set_fp4s(ga,gb) |
| } else { |
| t0.copy(c) |
| t0.mul(y.c) |
| } |
| } else { |
| t0.copy(c) |
| t0.mul(y.c) |
| } |
| t1.copy(t0); t1.neg() |
| |
| c.copy(z2); c.add(t1) |
| z3.add(t1) |
| t0.times_i() |
| b.add(t0) |
| z3.norm() |
| z3.times_i() |
| a.copy(z0); a.add(z3); |
| } else { |
| if stype==FP24.SPARSER { |
| smul(y) |
| return |
| } |
| if CONFIG_CURVE.SEXTIC_TWIST == CONFIG_CURVE.D_TYPE { // dense by sparser - 13m |
| var z0=FP8(a) |
| var z2=FP8(b) |
| var z3=FP8(b) |
| var t0=FP8() |
| var t1=FP8(y.a) |
| z0.mul(y.a) |
| z2.pmul(y.b.real()) |
| b.add(a) |
| t1.adds(y.b.real()) |
| |
| t1.norm() |
| b.norm() |
| b.mul(t1) |
| z3.add(c) |
| z3.norm() |
| z3.pmul(y.b.real()) |
| |
| t0.copy(z0); t0.neg() |
| t1.copy(z2); t1.neg() |
| |
| b.add(t0) |
| |
| b.add(t1) |
| z3.add(t1) |
| z2.add(t0) |
| |
| t0.copy(a); t0.add(c); t0.norm() |
| z3.norm() |
| t0.mul(y.a) |
| c.copy(z2); c.add(t0) |
| |
| z3.times_i() |
| a.copy(z0); a.add(z3) |
| } |
| if CONFIG_CURVE.SEXTIC_TWIST == CONFIG_CURVE.M_TYPE { |
| var z0=FP8(a) |
| var z1=FP8() |
| var z2=FP8() |
| var z3=FP8() |
| var t0=FP8(a) |
| var t1=FP8() |
| |
| z0.mul(y.a) |
| t0.add(b); t0.norm() |
| |
| z1.copy(t0); z1.mul(y.a) |
| t0.copy(b); t0.add(c) |
| t0.norm() |
| |
| z3.copy(t0) |
| z3.pmul(y.c.getb()) |
| z3.times_i() |
| |
| t0.copy(z0); t0.neg() |
| z1.add(t0) |
| b.copy(z1) |
| z2.copy(t0) |
| |
| t0.copy(a); t0.add(c); t0.norm() |
| t1.copy(y.a); t1.add(y.c); t1.norm() |
| |
| t0.mul(t1) |
| z2.add(t0) |
| t0.copy(c) |
| |
| t0.pmul(y.c.getb()) |
| t0.times_i() |
| t1.copy(t0); t1.neg() |
| |
| c.copy(z2); c.add(t1) |
| z3.add(t1) |
| t0.times_i() |
| b.add(t0) |
| z3.norm() |
| z3.times_i() |
| a.copy(z0); a.add(z3) |
| } |
| } |
| stype=FP24.DENSE |
| norm() |
| } |
| |
| /* Special case of multiplication arises from special form of ATE pairing line function */ |
| mutating func smul(_ y:FP24) |
| { |
| if CONFIG_CURVE.SEXTIC_TWIST == CONFIG_CURVE.D_TYPE { |
| var w1=FP4(a.geta()) |
| var w2=FP4(a.getb()) |
| var w3=FP4(b.geta()) |
| |
| w1.mul(y.a.geta()) |
| w2.mul(y.a.getb()) |
| w3.mul(y.b.geta()) |
| |
| var ta=FP4(a.geta()) |
| var tb=FP4(y.a.geta()) |
| ta.add(a.getb()); ta.norm() |
| tb.add(y.a.getb()); tb.norm() |
| var tc=FP4(ta) |
| tc.mul(tb) |
| var t=FP4(w1) |
| t.add(w2) |
| t.neg() |
| tc.add(t) |
| |
| ta.copy(a.geta()); ta.add(b.geta()); ta.norm() |
| tb.copy(y.a.geta()); tb.add(y.b.geta()); tb.norm() |
| var td=FP4(ta) |
| td.mul(tb) |
| t.copy(w1) |
| t.add(w3) |
| t.neg() |
| td.add(t) |
| |
| ta.copy(a.getb()); ta.add(b.geta()); ta.norm() |
| tb.copy(y.a.getb()); tb.add(y.b.geta()); tb.norm() |
| var te=FP4(ta) |
| te.mul(tb) |
| t.copy(w2) |
| t.add(w3) |
| t.neg() |
| te.add(t) |
| |
| w2.times_i() |
| w1.add(w2) |
| |
| a.set_fp4s(w1,tc) |
| b.set_fp4s(td,te) |
| c.set_fp4(w3) |
| |
| a.norm() |
| b.norm() |
| } else { |
| var w1=FP4(a.geta()) |
| var w2=FP4(a.getb()) |
| var w3=FP4(c.getb()) |
| |
| w1.mul(y.a.geta()) |
| w2.mul(y.a.getb()) |
| w3.mul(y.c.getb()) |
| |
| var ta=FP4(a.geta()) |
| var tb=FP4(y.a.geta()) |
| ta.add(a.getb()); ta.norm() |
| tb.add(y.a.getb()); tb.norm() |
| var tc=FP4(ta) |
| tc.mul(tb) |
| var t=FP4(w1) |
| t.add(w2) |
| t.neg() |
| tc.add(t) |
| |
| ta.copy(a.geta()); ta.add(c.getb()); ta.norm() |
| tb.copy(y.a.geta()); tb.add(y.c.getb()); tb.norm() |
| var td=FP4(ta) |
| td.mul(tb) |
| t.copy(w1) |
| t.add(w3) |
| t.neg() |
| td.add(t) |
| |
| ta.copy(a.getb()); ta.add(c.getb()); ta.norm() |
| tb.copy(y.a.getb()); tb.add(y.c.getb()); tb.norm() |
| var te=FP4(ta) |
| te.mul(tb) |
| t.copy(w2) |
| t.add(w3) |
| t.neg() |
| te.add(t) |
| |
| w2.times_i() |
| w1.add(w2) |
| a.set_fp4s(w1,tc); |
| |
| w3.times_i() |
| w3.norm() |
| b.set_fp4h(w3); |
| |
| te.norm() |
| te.times_i() |
| c.set_fp4s(te,td) |
| |
| a.norm() |
| c.norm() |
| |
| } |
| stype=FP24.SPARSE |
| } |
| |
| /* self=1/self */ |
| mutating func inverse() |
| { |
| var f0=FP8(a) |
| var f1=FP8(b) |
| var f2=FP8(a) |
| var f3=FP8() |
| |
| //norm() |
| f0.sqr() |
| f1.mul(c) |
| f1.times_i() |
| f0.sub(f1); f0.norm() |
| |
| f1.copy(c); f1.sqr() |
| f1.times_i() |
| f2.mul(b) |
| f1.sub(f2); f1.norm() |
| |
| f2.copy(b); f2.sqr() |
| f3.copy(a); f3.mul(c) |
| f2.sub(f3); f2.norm() |
| |
| f3.copy(b); f3.mul(f2) |
| f3.times_i() |
| a.mul(f0) |
| f3.add(a) |
| c.mul(f1) |
| c.times_i() |
| |
| f3.add(c); f3.norm() |
| f3.inverse() |
| a.copy(f0); a.mul(f3) |
| b.copy(f1); b.mul(f3) |
| c.copy(f2); c.mul(f3) |
| stype=FP24.DENSE |
| } |
| |
| /* self=self^p using Frobenius */ |
| mutating func frob(_ f:FP2,_ n:Int) |
| { |
| |
| var f2=FP2(f) |
| var f3=FP2(f) |
| |
| f2.sqr() |
| f3.mul(f2) |
| f3.mul_ip(); f3.norm() |
| |
| for _ in 0 ..< n { |
| a.frob(f3) |
| b.frob(f3) |
| c.frob(f3) |
| |
| b.qmul(f); b.times_i2() |
| c.qmul(f2); c.times_i2(); c.times_i2() |
| } |
| stype=FP24.DENSE |
| } |
| |
| /* trace function */ |
| func trace() -> FP8 |
| { |
| var t=FP8() |
| t.copy(a) |
| t.imul(3) |
| t.reduce() |
| return t |
| } |
| |
| /* convert from byte array to FP24 */ |
| static func fromBytes(_ w:[UInt8]) -> FP24 |
| { |
| let RM=Int(CONFIG_BIG.MODBYTES) |
| var t=[UInt8](repeating: 0,count: RM) |
| |
| for i in 0 ..< RM {t[i]=w[i]} |
| var a=BIG.fromBytes(t) |
| for i in 0 ..< RM {t[i]=w[i+RM]} |
| var b=BIG.fromBytes(t) |
| var c=FP2(a,b) |
| |
| for i in 0 ..< RM {t[i]=w[i+2*RM]} |
| a.copy(BIG.fromBytes(t)) |
| for i in 0 ..< RM {t[i]=w[i+3*RM]} |
| b.copy(BIG.fromBytes(t)) |
| var d=FP2(a,b) |
| |
| var ea=FP4(c,d) |
| |
| for i in 0 ..< RM {t[i]=w[i+4*RM]} |
| a.copy(BIG.fromBytes(t)) |
| for i in 0 ..< RM {t[i]=w[i+5*RM]} |
| b.copy(BIG.fromBytes(t)) |
| c.copy(FP2(a,b)) |
| |
| for i in 0 ..< RM {t[i]=w[i+6*RM]} |
| a.copy(BIG.fromBytes(t)) |
| for i in 0 ..< RM {t[i]=w[i+7*RM]} |
| b.copy(BIG.fromBytes(t)) |
| d.copy(FP2(a,b)) |
| |
| var eb=FP4(c,d) |
| |
| let e=FP8(ea,eb) |
| |
| for i in 0 ..< RM {t[i]=w[i+8*RM]} |
| a.copy(BIG.fromBytes(t)) |
| for i in 0 ..< RM {t[i]=w[i+9*RM]} |
| b.copy(BIG.fromBytes(t)) |
| c.copy(FP2(a,b)) |
| |
| for i in 0 ..< RM {t[i]=w[i+10*RM]} |
| a.copy(BIG.fromBytes(t)) |
| for i in 0 ..< RM {t[i]=w[i+11*RM]} |
| b.copy(BIG.fromBytes(t)) |
| d.copy(FP2(a,b)) |
| |
| ea.copy(FP4(c,d)) |
| |
| |
| for i in 0 ..< RM {t[i]=w[i+12*RM]} |
| a.copy(BIG.fromBytes(t)) |
| for i in 0 ..< RM {t[i]=w[i+13*RM]} |
| b.copy(BIG.fromBytes(t)) |
| c.copy(FP2(a,b)) |
| |
| for i in 0 ..< RM {t[i]=w[i+14*RM]} |
| a.copy(BIG.fromBytes(t)) |
| for i in 0 ..< RM {t[i]=w[i+15*RM]} |
| b.copy(BIG.fromBytes(t)) |
| d.copy(FP2(a,b)) |
| |
| eb.copy(FP4(c,d)) |
| |
| |
| let f=FP8(ea,eb) |
| |
| |
| for i in 0 ..< RM {t[i]=w[i+16*RM]} |
| a.copy(BIG.fromBytes(t)) |
| for i in 0 ..< RM {t[i]=w[i+17*RM]} |
| b.copy(BIG.fromBytes(t)) |
| c.copy(FP2(a,b)) |
| |
| for i in 0 ..< RM {t[i]=w[i+18*RM]} |
| a.copy(BIG.fromBytes(t)) |
| for i in 0 ..< RM {t[i]=w[i+19*RM]} |
| b.copy(BIG.fromBytes(t)) |
| d.copy(FP2(a,b)) |
| |
| ea.copy(FP4(c,d)) |
| |
| |
| for i in 0 ..< RM {t[i]=w[i+20*RM]} |
| a.copy(BIG.fromBytes(t)) |
| for i in 0 ..< RM {t[i]=w[i+21*RM]} |
| b.copy(BIG.fromBytes(t)) |
| c.copy(FP2(a,b)) |
| |
| for i in 0 ..< RM {t[i]=w[i+22*RM]} |
| a.copy(BIG.fromBytes(t)) |
| for i in 0 ..< RM {t[i]=w[i+23*RM]} |
| b.copy(BIG.fromBytes(t)) |
| d.copy(FP2(a,b)) |
| |
| eb.copy(FP4(c,d)) |
| |
| let g=FP8(ea,eb) |
| |
| return FP24(e,f,g) |
| } |
| |
| /* convert this to byte array */ |
| func toBytes(_ w:inout [UInt8]) |
| { |
| let RM=Int(CONFIG_BIG.MODBYTES) |
| var t=[UInt8](repeating: 0,count: RM) |
| |
| a.geta().geta().getA().toBytes(&t) |
| for i in 0 ..< RM {w[i]=t[i]} |
| a.geta().geta().getB().toBytes(&t) |
| for i in 0 ..< RM {w[i+RM]=t[i]} |
| a.geta().getb().getA().toBytes(&t) |
| for i in 0 ..< RM {w[i+2*RM]=t[i]} |
| a.geta().getb().getB().toBytes(&t) |
| for i in 0 ..< RM {w[i+3*RM]=t[i]} |
| |
| a.getb().geta().getA().toBytes(&t) |
| for i in 0 ..< RM {w[i+4*RM]=t[i]} |
| a.getb().geta().getB().toBytes(&t) |
| for i in 0 ..< RM {w[i+5*RM]=t[i]} |
| a.getb().getb().getA().toBytes(&t) |
| for i in 0 ..< RM {w[i+6*RM]=t[i]} |
| a.getb().getb().getB().toBytes(&t) |
| for i in 0 ..< RM {w[i+7*RM]=t[i]} |
| |
| |
| |
| b.geta().geta().getA().toBytes(&t) |
| for i in 0 ..< RM {w[i+8*RM]=t[i]} |
| b.geta().geta().getB().toBytes(&t) |
| for i in 0 ..< RM {w[i+9*RM]=t[i]} |
| b.geta().getb().getA().toBytes(&t) |
| for i in 0 ..< RM {w[i+10*RM]=t[i]} |
| b.geta().getb().getB().toBytes(&t) |
| for i in 0 ..< RM {w[i+11*RM]=t[i]} |
| |
| b.getb().geta().getA().toBytes(&t) |
| for i in 0 ..< RM {w[i+12*RM]=t[i]} |
| b.getb().geta().getB().toBytes(&t) |
| for i in 0 ..< RM {w[i+13*RM]=t[i]} |
| b.getb().getb().getA().toBytes(&t) |
| for i in 0 ..< RM {w[i+14*RM]=t[i]} |
| b.getb().getb().getB().toBytes(&t) |
| for i in 0 ..< RM {w[i+15*RM]=t[i]} |
| |
| |
| |
| c.geta().geta().getA().toBytes(&t) |
| for i in 0 ..< RM {w[i+16*RM]=t[i]} |
| c.geta().geta().getB().toBytes(&t) |
| for i in 0 ..< RM {w[i+17*RM]=t[i]} |
| c.geta().getb().getA().toBytes(&t) |
| for i in 0 ..< RM {w[i+18*RM]=t[i]} |
| c.geta().getb().getB().toBytes(&t) |
| for i in 0 ..< RM {w[i+19*RM]=t[i]} |
| |
| c.getb().geta().getA().toBytes(&t) |
| for i in 0 ..< RM {w[i+20*RM]=t[i]} |
| c.getb().geta().getB().toBytes(&t) |
| for i in 0 ..< RM {w[i+21*RM]=t[i]} |
| c.getb().getb().getA().toBytes(&t) |
| for i in 0 ..< RM {w[i+22*RM]=t[i]} |
| c.getb().getb().getB().toBytes(&t) |
| for i in 0 ..< RM {w[i+23*RM]=t[i]} |
| } |
| |
| /* convert to hex string */ |
| public func toString() -> String |
| { |
| return ("["+a.toString()+","+b.toString()+","+c.toString()+"]") |
| } |
| |
| /* self=self^e */ |
| /* Note this is simple square and multiply, so not side-channel safe */ |
| func pow(_ e:BIG) -> FP24 |
| { |
| var sf = FP24(self) |
| sf.norm() |
| |
| var e1=BIG(e) |
| e1.norm() |
| var e3=BIG(e1) |
| e3.pmul(3) |
| e3.norm(); |
| |
| var w=FP24(sf) |
| let nb=e3.nbits() |
| |
| for i in (1...nb-2).reversed() |
| { |
| w.usqr() |
| let bt=e3.bit(UInt(i))-e1.bit(UInt(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 */ |
| mutating func pinpow(_ e:Int32,_ bts:Int32) |
| { |
| var R=[FP24]() |
| R.append(FP24(1)) |
| R.append(FP24(self)) |
| |
| for i in (0...bts-1).reversed() |
| { |
| let b=Int((e>>i)&1) |
| R[1-b].mul(R[b]) |
| R[b].usqr() |
| } |
| copy(R[0]) |
| } |
| |
| public func compow(_ e :BIG,_ r :BIG) -> FP8 |
| { |
| let f=FP2(BIG(ROM.Fra),BIG(ROM.Frb)) |
| let q=BIG(ROM.Modulus) |
| |
| var g1=FP24(self) |
| var g2=FP24(self) |
| |
| var m=BIG(q) |
| m.mod(r) |
| |
| var a=BIG(e) |
| a.mod(m) |
| |
| var b=BIG(e) |
| b.div(m); |
| |
| var c=g1.trace() |
| |
| if b.iszilch() |
| { |
| c=c.xtr_pow(e) |
| return c |
| } |
| |
| g2.frob(f,1) |
| let cp=g2.trace() |
| g1.conj() |
| g2.mul(g1) |
| let cpm1=g2.trace() |
| g2.mul(g1) |
| let cpm2=g2.trace() |
| |
| c=c.xtr_pow2(cp,cpm1,cpm2,a,b) |
| |
| return c |
| } |
| |
| /* P=u0.Q0+u1*Q1+u2*Q2+u3*Q3.. */ |
| // Bos & Costello https://eprint.iacr.org/2013/458.pdf |
| // Faz-Hernandez & Longa & Sanchez https://eprint.iacr.org/2013/158.pdf |
| // Side channel attack secure |
| |
| static func pow8(_ q:[FP24],_ u:[BIG]) -> FP24 |
| { |
| var g1=[FP24]() |
| var g2=[FP24]() |
| |
| for _ in 0 ..< 8 { |
| g1.append(FP24()) |
| g2.append(FP24()) |
| } |
| |
| var r=FP24() |
| var p=FP24() |
| |
| var t=[BIG]() |
| for i in 0 ..< 8 { |
| t.append(BIG(u[i])) |
| t[i].norm() |
| } |
| |
| var mt=BIG(0); |
| var w1=[Int8](repeating: 0,count: CONFIG_BIG.NLEN*Int(CONFIG_BIG.BASEBITS)+1) |
| var s1=[Int8](repeating: 0,count: CONFIG_BIG.NLEN*Int(CONFIG_BIG.BASEBITS)+1) |
| var w2=[Int8](repeating: 0,count: CONFIG_BIG.NLEN*Int(CONFIG_BIG.BASEBITS)+1) |
| var s2=[Int8](repeating: 0,count: CONFIG_BIG.NLEN*Int(CONFIG_BIG.BASEBITS)+1) |
| |
| |
| // precompute table |
| g1[0].copy(q[0]) // q[0] |
| g1[1].copy(g1[0]); g1[1].mul(q[1]) // q[0].q[1] |
| g1[2].copy(g1[0]); g1[2].mul(q[2]) // q[0].q[2] |
| g1[3].copy(g1[1]); g1[3].mul(q[2]) // q[0].q[1].q[2] |
| g1[4].copy(g1[0]); g1[4].mul(q[3]) // q[0].q[3] |
| g1[5].copy(g1[1]); g1[5].mul(q[3]) // q[0].q[1].q[3] |
| g1[6].copy(g1[2]); g1[6].mul(q[3]) // q[0].q[2].q[3] |
| g1[7].copy(g1[3]); g1[7].mul(q[3]) // q[0].q[1].q[2].q[3] |
| |
| // Use Frobenius |
| let f=FP2(BIG(ROM.Fra),BIG(ROM.Frb)) |
| for i in 0 ..< 8 { |
| g2[i].copy(g1[i]); g2[i].frob(f,4) |
| } |
| |
| // Make it odd |
| let pb1=1-t[0].parity() |
| t[0].inc(pb1) |
| t[0].norm() |
| |
| let pb2=1-t[4].parity() |
| t[4].inc(pb2) |
| t[4].norm() |
| |
| // Number of bits |
| mt.zero(); |
| for i in 0 ..< 8 { |
| mt.or(t[i]); |
| } |
| |
| let nb=1+mt.nbits() |
| |
| // Sign pivot |
| |
| s1[nb-1]=1 |
| s2[nb-1]=1 |
| for i in 0 ..< nb-1 { |
| t[0].fshr(1) |
| s1[i]=2*Int8(t[0].parity())-1 |
| t[4].fshr(1) |
| s2[i]=2*Int8(t[4].parity())-1 |
| } |
| |
| // Recoded exponent |
| for i in 0 ..< nb { |
| w1[i]=0 |
| var k=1 |
| for j in 1 ..< 4 { |
| let bt=s1[i]*Int8(t[j].parity()) |
| t[j].fshr(1) |
| t[j].dec(Int(bt>>1)) |
| t[j].norm() |
| w1[i]+=bt*Int8(k) |
| k=2*k |
| } |
| w2[i]=0 |
| k=1 |
| for j in 5 ..< 8 { |
| let bt=s2[i]*Int8(t[j].parity()) |
| t[j].fshr(1) |
| t[j].dec(Int(bt>>1)) |
| t[j].norm() |
| w2[i]+=bt*Int8(k) |
| k=2*k |
| } |
| } |
| |
| // Main loop |
| p.select(g1,Int32(2*w1[nb-1]+1)) |
| r.select(g2,Int32(2*w2[nb-1]+1)) |
| p.mul(r) |
| for i in (0 ..< nb-1).reversed() { |
| p.usqr() |
| r.select(g1,Int32(2*w1[i]+s1[i])) |
| p.mul(r) |
| r.select(g2,Int32(2*w2[i]+s2[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) |
| |
| p.reduce() |
| return p |
| } |
| } |