/* | |
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. | |
// | |
/* CLINT 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:Int32) | |
{ | |
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) -> Int32 | |
{ | |
var x=b^c | |
x-=1 // if x=0, x now -1 | |
return ((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,(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(inout b:[UInt8]) | |
{ | |
let RM=Int(ROM.MODBYTES) | |
var t=[UInt8](count:RM,repeatedValue:0) | |
affine(); | |
x.getA().toBytes(&t) | |
for var i=0;i<RM;i++ | |
{b[i]=t[i]} | |
x.getB().toBytes(&t); | |
for var i=0;i<RM;i++ | |
{b[i+RM]=t[i]} | |
y.getA().toBytes(&t); | |
for var i=0;i<RM;i++ | |
{b[i+2*RM]=t[i]} | |
y.getB().toBytes(&t); | |
for var i=0;i<RM;i++ | |
{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](count:RM,repeatedValue:0) | |
for var i=0;i<RM;i++ {t[i]=b[i]} | |
var ra=BIG.fromBytes(t); | |
for var i=0;i<RM;i++ {t[i]=b[i+RM]} | |
var rb=BIG.fromBytes(t); | |
let rx=FP2(ra,rb) | |
for var i=0;i<RM;i++ {t[i]=b[i+2*RM]} | |
ra=BIG.fromBytes(t) | |
for var i=0;i<RM;i++ {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 var i=0;i<m;i++ | |
{work.append(FP2(0))} | |
work[0].one() | |
work[1].copy(P[0].z) | |
for var i=2;i<m;i++ | |
{ | |
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) | |
for var i=m-2;;i-- | |
{ | |
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) | |
} | |
/* now work[] contains inverses of all Z coordinates */ | |
for var i=0;i<m;i++ | |
{ | |
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 var i=0;i<8;i++ {W.append(ECP2())} | |
var w=[Int8](count:1+(ROM.NLEN*Int(ROM.BASEBITS)+3)/4,repeatedValue:0) | |
if is_infinity() {return ECP2()} | |
affine() | |
/* precompute table */ | |
Q.copy(self) | |
Q.dbl() | |
W[0].copy(self) | |
for var i=1;i<8;i++ | |
{ | |
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 var i=0;i<nb;i++ | |
{ | |
w[i]=Int8(t.lastbits(5)-16) | |
t.dec(Int32(w[i])); t.norm() | |
t.fshr(4) | |
} | |
w[nb]=Int8(t.lastbits(5)) | |
P.copy(W[(w[nb]-1)/2]) | |
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](count:4,repeatedValue:0) | |
let T=ECP2() | |
let C=ECP2() | |
let P=ECP2() | |
var W=[ECP2](); | |
for var i=0;i<8;i++ {W.append(ECP2())} | |
let mt=BIG() | |
var t=[BIG]() | |
var w=[Int8](count:ROM.NLEN*Int(ROM.BASEBITS)+1,repeatedValue:0) | |
for var i=0;i<4;i++ | |
{ | |
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 var i=0;i<4;i++ | |
{ | |
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 var j=0;j<nb;j++ | |
{ | |
for var i=0;i<4;i++ | |
{ | |
a[i]=(t[i].lastbits(2)-2) | |
t[i].dec(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[(w[nb]-1)/2]) | |
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 | |
} | |
} |