blob: e1288d61c8a2a00ac8f3d5b98f76725589dd6ba4 [file] [log] [blame]
/*
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.
*/
//
// ecp2.swift
//
// Created by Michael Scott on 07/07/2015.
// Copyright (c) 2015 Michael Scott. All rights reserved.
//
/* AMCL Weierstrass elliptic curve functions over FP2 */
final class ECP2 {
private var x:FP2
private var y:FP2
private var z:FP2
private var INF:Bool
/* Constructor - set self=O */
init()
{
INF=true
x=FP2(0)
y=FP2(1)
z=FP2(1)
}
/* Test self=O? */
func is_infinity() -> Bool
{
return INF
}
/* copy self=P */
func copy(_ P:ECP2)
{
x.copy(P.x)
y.copy(P.y)
z.copy(P.z)
INF=P.INF
}
/* set self=O */
func inf() {
INF=true
x.zero()
y.zero()
z.zero()
}
/* Conditional move of Q to P dependant on d */
func cmove(_ Q:ECP2,_ d:Int)
{
x.cmove(Q.x,d);
y.cmove(Q.y,d);
z.cmove(Q.z,d);
var bd:Bool
if d==0 {bd=false}
else {bd=true}
INF = (INF != ((INF != Q.INF) && bd))
}
/* 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 */
func select(_ W:[ECP2],_ b:Int32)
{
let MP=ECP2()
let m=b>>31
var babs=(b^m)-m
babs=(babs-1)/2
cmove(W[0],ECP2.teq(babs,0)) // conditional move
cmove(W[1],ECP2.teq(babs,1))
cmove(W[2],ECP2.teq(babs,2))
cmove(W[3],ECP2.teq(babs,3))
cmove(W[4],ECP2.teq(babs,4))
cmove(W[5],ECP2.teq(babs,5))
cmove(W[6],ECP2.teq(babs,6))
cmove(W[7],ECP2.teq(babs,7))
MP.copy(self)
MP.neg()
cmove(MP,Int(m&1))
}
/* Test if P == Q */
func equals(_ Q:ECP2) -> Bool
{
if is_infinity() && Q.is_infinity() {return true}
if is_infinity() || Q.is_infinity() {return false}
let zs2=FP2(z); zs2.sqr()
let zo2=FP2(Q.z); zo2.sqr()
let zs3=FP2(zs2); zs3.mul(z)
let zo3=FP2(zo2); zo3.mul(Q.z)
zs2.mul(Q.x)
zo2.mul(x)
if !zs2.equals(zo2) {return false}
zs3.mul(Q.y)
zo3.mul(y)
if !zs3.equals(zo3) {return false}
return true;
}
/* set self=-self */
func neg()
{
if is_infinity() {return}
y.neg(); y.norm()
return
}
/* set to Affine - (x,y,z) to (x,y) */
func affine() {
if is_infinity() {return}
let one=FP2(1)
if z.equals(one) {return}
z.inverse()
let z2=FP2(z)
z2.sqr()
x.mul(z2); x.reduce()
y.mul(z2)
y.mul(z); y.reduce()
z.copy(one)
}
/* extract affine x as FP2 */
func getX() -> FP2
{
affine()
return x
}
/* extract affine y as FP2 */
func getY() -> FP2
{
affine()
return y
}
/* extract projective x */
func getx() -> FP2
{
return x
}
/* extract projective y */
func gety() -> FP2
{
return y
}
/* extract projective z */
func getz() -> FP2
{
return z
}
/* convert to byte array */
func toBytes(_ b:inout [UInt8])
{
let RM=Int(ROM.MODBYTES)
var t=[UInt8](repeating: 0,count: RM)
affine();
x.getA().toBytes(&t)
for i in 0 ..< RM
{b[i]=t[i]}
x.getB().toBytes(&t);
for i in 0 ..< RM
{b[i+RM]=t[i]}
y.getA().toBytes(&t);
for i in 0 ..< RM
{b[i+2*RM]=t[i]}
y.getB().toBytes(&t);
for i in 0 ..< RM
{b[i+3*RM]=t[i]}
}
/* convert from byte array to point */
static func fromBytes(_ b:[UInt8]) -> ECP2
{
let RM=Int(ROM.MODBYTES)
var t=[UInt8](repeating: 0,count: RM)
for i in 0 ..< RM {t[i]=b[i]}
var ra=BIG.fromBytes(t);
for i in 0 ..< RM {t[i]=b[i+RM]}
var rb=BIG.fromBytes(t);
let rx=FP2(ra,rb)
for i in 0 ..< RM {t[i]=b[i+2*RM]}
ra=BIG.fromBytes(t)
for i in 0 ..< RM {t[i]=b[i+3*RM]}
rb=BIG.fromBytes(t)
let ry=FP2(ra,rb)
return ECP2(rx,ry)
}
/* convert self to hex string */
func toString() -> String
{
if is_infinity() {return "infinity"}
affine()
return "("+x.toString()+","+y.toString()+")"
}
/* Calculate RHS of twisted curve equation x^3+B/i */
static func RHS(_ x:FP2) -> FP2
{
x.norm()
let r=FP2(x)
r.sqr()
let b=FP2(BIG(ROM.CURVE_B))
b.div_ip();
r.mul(x);
r.add(b);
r.reduce();
return r;
}
/* construct self from (x,y) - but set to O if not on curve */
init(_ ix:FP2,_ iy:FP2)
{
x=FP2(ix)
y=FP2(iy)
z=FP2(1)
let rhs=ECP2.RHS(x)
let y2=FP2(y)
y2.sqr()
if y2.equals(rhs) {INF=false}
else {x.zero(); INF=true}
}
/* construct this from x - but set to O if not on curve */
init(_ ix:FP2)
{
x=FP2(ix)
y=FP2(1)
z=FP2(1)
let rhs=ECP2.RHS(x)
if rhs.sqrt()
{
y.copy(rhs);
INF=false;
}
else {x.zero(); INF=true;}
}
/* this+=this */
func dbl() -> Int
{
if (INF) {return -1}
if y.iszilch()
{
inf();
return -1;
}
let w1=FP2(x)
let w2=FP2(0)
let w3=FP2(x)
let w8=FP2(x)
w1.sqr()
w8.copy(w1)
w8.imul(3)
w2.copy(y); w2.sqr()
w3.copy(x); w3.mul(w2)
w3.imul(4)
w1.copy(w3); w1.neg()
w1.norm()
x.copy(w8); x.sqr()
x.add(w1)
x.add(w1)
x.norm()
z.mul(y)
z.add(z)
w2.add(w2)
w2.sqr()
w2.add(w2)
w3.sub(x)
y.copy(w8); y.mul(w3)
w2.norm()
y.sub(w2)
y.norm()
z.norm()
return 1
}
/* this+=Q - return 0 for add, 1 for double, -1 for O */
func add(_ Q:ECP2) -> Int
{
if INF
{
copy(Q)
return -1
}
if Q.INF {return -1}
var aff=false
if Q.z.isunity() {aff=true}
var A:FP2
var C:FP2
let B=FP2(z)
let D=FP2(z)
if (!aff)
{
A=FP2(Q.z)
C=FP2(Q.z)
A.sqr(); B.sqr()
C.mul(A); D.mul(B)
A.mul(x)
C.mul(y)
}
else
{
A=FP2(x)
C=FP2(y)
B.sqr()
D.mul(B)
}
B.mul(Q.x); B.sub(A)
D.mul(Q.y); D.sub(C)
if B.iszilch()
{
if D.iszilch()
{
dbl()
return 1
}
else
{
INF=true
return -1
}
}
if !aff {z.mul(Q.z)}
z.mul(B)
let e=FP2(B); e.sqr()
B.mul(e)
A.mul(e)
e.copy(A)
e.add(A); e.add(B)
x.copy(D); x.sqr(); x.sub(e)
A.sub(x)
y.copy(A); y.mul(D)
C.mul(B); y.sub(C)
x.norm()
y.norm()
z.norm()
return 0
}
/* set self-=Q */
func sub(_ Q:ECP2) -> Int
{
Q.neg()
let D=add(Q)
Q.neg()
return D
}
/* set self*=q, where q is Modulus, using Frobenius */
func frob(_ X:FP2)
{
if INF {return}
let X2=FP2(X)
X2.sqr()
x.conj()
y.conj()
z.conj()
z.reduce()
x.mul(X2)
y.mul(X2)
y.mul(X)
}
/* normalises m-array of ECP2 points. Requires work vector of m FP2s */
private static func multiaffine(_ m:Int,_ P:[ECP2])
{
let t1=FP2(0)
let t2=FP2(0)
var work=[FP2]()
for _ in 0 ..< m
{work.append(FP2(0))}
work[0].one()
work[1].copy(P[0].z)
for i in 2 ..< m
{
work[i].copy(work[i-1])
work[i].mul(P[i-1].z)
}
t1.copy(work[m-1]); t1.mul(P[m-1].z)
t1.inverse()
t2.copy(P[m-1].z)
work[m-1].mul(t1)
var i=m-2
while true
{
if (i==0)
{
work[0].copy(t1)
work[0].mul(t2)
break;
}
work[i].mul(t2)
work[i].mul(t1)
t2.mul(P[i].z)
i-=1
}
/* now work[] contains inverses of all Z coordinates */
for i in 0 ..< m
{
P[i].z.one()
t1.copy(work[i]); t1.sqr()
P[i].x.mul(t1)
t1.mul(work[i])
P[i].y.mul(t1)
}
}
/* P*=e */
func mul(_ e:BIG) -> ECP2
{
/* fixed size windows */
let mt=BIG()
let t=BIG()
let P=ECP2()
let Q=ECP2()
let C=ECP2()
var W=[ECP2]();
for _ in 0 ..< 8 {W.append(ECP2())}
var w=[Int8](repeating: 0,count: 1+(ROM.NLEN*Int(ROM.BASEBITS)+3)/4)
if is_infinity() {return ECP2()}
affine()
/* precompute table */
Q.copy(self)
Q.dbl()
W[0].copy(self)
for i in 1 ..< 8
{
W[i].copy(W[i-1])
W[i].add(Q)
}
/* convert the table to affine */
ECP2.multiaffine(8,W);
/* make exponent odd - add 2P if even, P if odd */
t.copy(e)
let s=t.parity()
t.inc(1); t.norm(); let ns=t.parity(); mt.copy(t); mt.inc(1); mt.norm()
t.cmove(mt,s)
Q.cmove(self,ns)
C.copy(Q)
let nb=1+(t.nbits()+3)/4
/* convert exponent to signed 4-bit window */
for i in 0 ..< nb
{
w[i]=Int8(t.lastbits(5)-16)
t.dec(Int(w[i])); t.norm()
t.fshr(4)
}
w[nb]=Int8(t.lastbits(5))
P.copy(W[Int(w[nb]-1)/2])
for i in (0...nb-1).reversed()
//for var i=nb-1;i>=0;i--
{
Q.select(W,Int32(w[i]))
P.dbl()
P.dbl()
P.dbl()
P.dbl()
P.add(Q)
}
P.sub(C);
P.affine()
return P;
}
/* P=u0.Q0+u1*Q1+u2*Q2+u3*Q3 */
static func mul4(_ Q:[ECP2],_ u:[BIG]) -> ECP2
{
var a=[Int32](repeating: 0,count: 4)
let T=ECP2()
let C=ECP2()
let P=ECP2()
var W=[ECP2]();
for _ in 0 ..< 8 {W.append(ECP2())}
let mt=BIG()
var t=[BIG]()
var w=[Int8](repeating: 0,count: ROM.NLEN*Int(ROM.BASEBITS)+1)
for i in 0 ..< 4
{
t.append(BIG(u[i]))
Q[i].affine()
}
/* precompute table */
W[0].copy(Q[0]); W[0].sub(Q[1])
W[1].copy(W[0])
W[2].copy(W[0])
W[3].copy(W[0])
W[4].copy(Q[0]); W[4].add(Q[1])
W[5].copy(W[4])
W[6].copy(W[4])
W[7].copy(W[4])
T.copy(Q[2]); T.sub(Q[3])
W[1].sub(T)
W[2].add(T)
W[5].sub(T)
W[6].add(T)
T.copy(Q[2]); T.add(Q[3])
W[0].sub(T)
W[3].add(T)
W[4].sub(T)
W[7].add(T)
ECP2.multiaffine(8,W);
/* if multiplier is even add 1 to multiplier, and add P to correction */
mt.zero(); C.inf()
for i in 0 ..< 4
{
if (t[i].parity()==0)
{
t[i].inc(1); t[i].norm()
C.add(Q[i])
}
mt.add(t[i]); mt.norm()
}
let nb=1+mt.nbits();
/* convert exponent to signed 1-bit window */
for j in 0 ..< nb
{
for i in 0 ..< 4 {
a[i]=Int32(t[i].lastbits(2)-2)
t[i].dec(Int(a[i]))
t[i].norm()
t[i].fshr(1)
}
w[j]=Int8(8*a[0]+4*a[1]+2*a[2]+a[3])
}
w[nb]=Int8(8*t[0].lastbits(2)+4*t[1].lastbits(2))
w[nb]+=Int8(2*t[2].lastbits(2)+t[3].lastbits(2))
P.copy(W[Int(w[nb]-1)/2])
for i in (0...nb-1).reversed()
//for var i=nb-1;i>=0;i--
{
T.select(W,Int32(w[i]))
P.dbl()
P.add(T)
}
P.sub(C) /* apply correction */
P.affine()
return P
}
}