blob: 03845a1a16527d535f9bda091e47caf5da4f3170 [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.
*/
//
// ecp.swift
//
// Created by Michael Scott on 30/06/2015.
// Copyright (c) 2015 Michael Scott. All rights reserved.
//
public struct ECP {
private var x:FP
private var y:FP
private var z:FP
/* Constructor - set to O */
init()
{
x=FP(0)
y=FP(1)
if CONFIG_CURVE.CURVETYPE==CONFIG_CURVE.EDWARDS {
z=FP(1)
} else {
z=FP(0)
}
}
/* test for O point-at-infinity */
public func is_infinity() -> Bool
{
if (CONFIG_CURVE.CURVETYPE==CONFIG_CURVE.EDWARDS)
{
return x.iszilch() && y.equals(z)
}
if (CONFIG_CURVE.CURVETYPE==CONFIG_CURVE.WEIERSTRASS)
{
return x.iszilch() && z.iszilch()
}
if (CONFIG_CURVE.CURVETYPE==CONFIG_CURVE.MONTGOMERY)
{
return z.iszilch()
}
return true
}
/* Conditional swap of P and Q dependant on d */
private mutating func cswap(_ Q: inout ECP,_ d:Int)
{
x.cswap(&(Q.x),d)
if CONFIG_CURVE.CURVETYPE != CONFIG_CURVE.MONTGOMERY {y.cswap(&(Q.y),d)}
z.cswap(&(Q.z),d)
}
/* Conditional move of Q to P dependant on d */
private mutating func cmove(_ Q: ECP,_ d:Int)
{
x.cmove(Q.x,d)
if CONFIG_CURVE.CURVETYPE != CONFIG_CURVE.MONTGOMERY {y.cmove(Q.y,d)}
z.cmove(Q.z,d)
}
/* 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)
}
/* self=P */
public mutating func copy(_ P: ECP)
{
x.copy(P.x)
if CONFIG_CURVE.CURVETYPE != CONFIG_CURVE.MONTGOMERY {y.copy(P.y)}
z.copy(P.z)
}
/* self=-self */
mutating func neg() {
if (CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.WEIERSTRASS)
{
y.neg(); y.norm();
}
if (CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.EDWARDS)
{
x.neg(); x.norm();
}
return;
}
/* Constant time select from pre-computed table */
private mutating func select(_ W:[ECP],_ b:Int32)
{
var MP=ECP()
let m=b>>31
var babs=(b^m)-m
babs=(babs-1)/2
cmove(W[0],ECP.teq(babs,0)); // conditional move
cmove(W[1],ECP.teq(babs,1))
cmove(W[2],ECP.teq(babs,2))
cmove(W[3],ECP.teq(babs,3))
cmove(W[4],ECP.teq(babs,4))
cmove(W[5],ECP.teq(babs,5))
cmove(W[6],ECP.teq(babs,6))
cmove(W[7],ECP.teq(babs,7))
MP.copy(self)
MP.neg()
cmove(MP,Int(m&1))
}
/* Test P == Q */
func equals(_ Q: ECP) -> Bool
{
var a=FP(0)
var b=FP(0)
a.copy(x); a.mul(Q.z)
b.copy(Q.x); b.mul(z)
if !a.equals(b) {return false}
if CONFIG_CURVE.CURVETYPE != CONFIG_CURVE.MONTGOMERY
{
a.copy(y); a.mul(Q.z);
b.copy(Q.y); b.mul(z);
if !a.equals(b) {return false}
}
return true
}
mutating func mulx(_ w: FP)
{
x.mul(w)
}
/* set self=O */
mutating func inf()
{
// INF=true;
x.zero()
if CONFIG_CURVE.CURVETYPE != CONFIG_CURVE.MONTGOMERY {y.one()}
if CONFIG_CURVE.CURVETYPE != CONFIG_CURVE.EDWARDS {z.zero()}
else {z.one()}
}
/* Calculate RHS of curve equation */
static func RHS(_ x: FP) -> FP
{
var r=FP(x)
r.sqr()
if CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.WEIERSTRASS
{ // x^3+Ax+B
let b=FP(BIG(ROM.CURVE_B))
r.mul(x)
if (ROM.CURVE_A == -3)
{
var cx=FP(x)
cx.imul(3)
cx.neg(); cx.norm()
r.add(cx)
}
r.add(b);
}
if (CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.EDWARDS)
{ // (Ax^2-1)/(Bx^2-1)
var b=FP(BIG(ROM.CURVE_B))
let one=FP(1);
b.mul(r);
b.sub(one); b.norm()
if ROM.CURVE_A == -1 {r.neg()}
r.sub(one); r.norm()
b.inverse()
r.mul(b);
}
if CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.MONTGOMERY
{ // x^3+Ax^2+x
var x3=FP(0)
x3.copy(r);
x3.mul(x);
r.imul(ROM.CURVE_A);
r.add(x3);
r.add(x);
}
r.reduce();
return r;
}
/* set (x,y) from two BIGs */
public init(_ ix: BIG,_ iy: BIG)
{
x=FP(ix)
y=FP(iy)
z=FP(1)
x.norm()
let rhs=ECP.RHS(x);
if CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.MONTGOMERY
{
if rhs.jacobi() != 1 {inf()}
}
else
{
var y2=FP(y)
y2.sqr()
if !y2.equals(rhs) {inf()}
}
}
/* set (x,y) from BIG and a bit */
public init(_ ix: BIG,_ s:Int)
{
x=FP(ix)
x.norm()
var rhs=ECP.RHS(x)
y=FP(0)
z=FP(1)
if rhs.jacobi()==1
{
var ny=rhs.sqrt()
if (ny.redc().parity() != s) {ny.neg()}
y.copy(ny)
}
else {inf()}
}
/* set from x - calculate y from curve equation */
public init(_ ix:BIG)
{
x=FP(ix)
x.norm()
var rhs=ECP.RHS(x)
y=FP(0)
z=FP(1)
if rhs.jacobi()==1
{
if CONFIG_CURVE.CURVETYPE != CONFIG_CURVE.MONTGOMERY {y.copy(rhs.sqrt())}
}
else {inf()}
}
/* set to affine - from (x,y,z) to (x,y) */
mutating func affine()
{
if is_infinity() {return}
let one=FP(1)
if (z.equals(one)) {
x.reduce(); y.reduce()
return
}
z.inverse()
x.mul(z); x.reduce()
if CONFIG_CURVE.CURVETYPE != CONFIG_CURVE.MONTGOMERY
{
y.mul(z); y.reduce()
}
z.copy(one)
}
/* extract x as a BIG */
func getX() -> BIG
{
var W=ECP(); W.copy(self)
W.affine()
return W.x.redc()
}
/* extract y as a BIG */
func getY() -> BIG
{
var W=ECP(); W.copy(self)
W.affine();
return W.y.redc();
}
/* get sign of Y */
func getS() -> Int
{
let y=getY()
return y.parity()
}
/* extract x as an FP */
func getx() -> FP
{
return x;
}
/* extract y as an FP */
func gety() -> FP
{
return y;
}
/* extract z as an FP */
func getz() -> FP
{
return z;
}
/* convert to byte array */
func toBytes(_ b:inout [UInt8],_ compress: Bool)
{
let RM=Int(CONFIG_BIG.MODBYTES)
var t=[UInt8](repeating: 0,count: RM)
var W=ECP(); W.copy(self)
W.affine()
W.x.redc().toBytes(&t)
for i in 0 ..< RM {b[i+1]=t[i]}
if CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.MONTGOMERY {
b[0]=0x06
return
}
if compress {
b[0]=0x02
if W.y.redc().parity()==1 {b[0]=0x03}
return
}
b[0]=0x04
W.y.redc().toBytes(&t);
for i in 0 ..< RM {b[i+RM+1]=t[i]}
}
/* convert from byte array to point */
static func fromBytes(_ b: [UInt8]) -> ECP
{
let RM=Int(CONFIG_BIG.MODBYTES)
var t=[UInt8](repeating: 0,count: RM)
let p=BIG(ROM.Modulus);
for i in 0 ..< RM {t[i]=b[i+1]}
let px=BIG.fromBytes(t)
if BIG.comp(px,p)>=0 {return ECP()}
if CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.MONTGOMERY {
return ECP(px)
}
if b[0]==0x04 {
for i in 0 ..< RM {t[i]=b[i+RM+1]}
let py=BIG.fromBytes(t)
if BIG.comp(py,p)>=0 {return ECP()}
return ECP(px,py)
}
if b[0]==0x02 || b[0]==0x03 {
return ECP(px,Int(b[0]&1))
}
return ECP()
}
/* convert to hex string */
func toString() -> String
{
var W=ECP(); W.copy(self)
if W.is_infinity() {return "infinity"}
W.affine();
if CONFIG_CURVE.CURVETYPE==CONFIG_CURVE.MONTGOMERY {return "("+W.x.redc().toString()+")"}
else {return "("+W.x.redc().toString()+","+W.y.redc().toString()+")"}
}
/* self*=2 */
mutating func dbl()
{
if (CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.WEIERSTRASS)
{
if ROM.CURVE_A == 0
{
var t0=FP(y)
t0.sqr()
var t1=FP(y)
t1.mul(z);
var t2=FP(z)
t2.sqr()
z.copy(t0)
z.add(t0); z.norm()
z.add(z); z.add(z); z.norm()
t2.imul(3*ROM.CURVE_B_I)
var x3=FP(t2)
x3.mul(z)
var y3=FP(t0)
y3.add(t2); y3.norm()
z.mul(t1)
t1.copy(t2); t1.add(t2); t2.add(t1)
t0.sub(t2); t0.norm(); y3.mul(t0); y3.add(x3)
t1.copy(x); t1.mul(y)
x.copy(t0); x.norm(); x.mul(t1); x.add(x)
x.norm()
y.copy(y3); y.norm()
}
else {
var t0=FP(x)
var t1=FP(y)
var t2=FP(z)
var t3=FP(x)
var z3=FP(z)
var y3=FP(0)
var x3=FP(0)
var b=FP(0)
if ROM.CURVE_B_I==0
{
b.copy(FP(BIG(ROM.CURVE_B)))
}
t0.sqr() //1 x^2
t1.sqr() //2 y^2
t2.sqr() //3
t3.mul(y) //4
t3.add(t3); t3.norm()//5
z3.mul(x) //6
z3.add(z3); z3.norm()//7
y3.copy(t2)
if ROM.CURVE_B_I==0 {
y3.mul(b) //8
}
else {
y3.imul(ROM.CURVE_B_I)
}
y3.sub(z3) //9 ***
x3.copy(y3); x3.add(y3); x3.norm()//10
y3.add(x3) //11
x3.copy(t1); x3.sub(y3); x3.norm()//12
y3.add(t1); y3.norm()//13
y3.mul(x3) //14
x3.mul(t3) //15
t3.copy(t2); t3.add(t2) //16
t2.add(t3) //t2.norm(); //17
if ROM.CURVE_B_I==0 {
z3.mul(b) //18
}
else {
z3.imul(ROM.CURVE_B_I)
}
z3.sub(t2) //19
z3.sub(t0); z3.norm()//20 ***
t3.copy(z3); t3.add(z3) //21
z3.add(t3); z3.norm() //22
t3.copy(t0); t3.add(t0) //23
t0.add(t3) //24
t0.sub(t2); t0.norm()//25
t0.mul(z3)//26
y3.add(t0) //27
t0.copy(y); t0.mul(z)//28
t0.add(t0); t0.norm() //29
z3.mul(t0)//30
x3.sub(z3) //31
t0.add(t0); t0.norm()//32
t1.add(t1); t1.norm()//33
z3.copy(t0); z3.mul(t1)//34
x.copy(x3); x.norm()
y.copy(y3); y.norm()
z.copy(z3); z.norm()
}
}
if CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.EDWARDS
{
var C=FP(x)
var D=FP(y)
var H=FP(z)
var J=FP(0)
x.mul(y); x.add(x); x.norm()
C.sqr()
D.sqr()
if ROM.CURVE_A == -1 {C.neg()}
y.copy(C); y.add(D); y.norm()
H.sqr(); H.add(H)
z.copy(y)
J.copy(y); J.sub(H); J.norm()
x.mul(J)
C.sub(D); C.norm()
y.mul(C)
z.mul(J)
}
if CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.MONTGOMERY
{
var A=FP(x)
var B=FP(x);
var AA=FP(0);
var BB=FP(0);
var C=FP(0);
A.add(z); A.norm()
AA.copy(A); AA.sqr()
B.sub(z); B.norm()
BB.copy(B); BB.sqr()
C.copy(AA); C.sub(BB); C.norm()
x.copy(AA); x.mul(BB)
A.copy(C); A.imul((ROM.CURVE_A+2)/4)
BB.add(A); BB.norm()
z.copy(BB); z.mul(C)
}
return
}
/* self+=Q */
mutating func add(_ Q:ECP)
{
if CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.WEIERSTRASS
{
if ROM.CURVE_A == 0
{
let b=3*ROM.CURVE_B_I
var t0=FP(x)
t0.mul(Q.x)
var t1=FP(y)
t1.mul(Q.y)
var t2=FP(z)
t2.mul(Q.z)
var t3=FP(x)
t3.add(y); t3.norm()
var t4=FP(Q.x)
t4.add(Q.y); t4.norm()
t3.mul(t4)
t4.copy(t0); t4.add(t1)
t3.sub(t4); t3.norm()
t4.copy(y)
t4.add(z); t4.norm()
var x3=FP(Q.y)
x3.add(Q.z); x3.norm()
t4.mul(x3)
x3.copy(t1)
x3.add(t2)
t4.sub(x3); t4.norm()
x3.copy(x); x3.add(z); x3.norm()
var y3=FP(Q.x)
y3.add(Q.z); y3.norm()
x3.mul(y3)
y3.copy(t0)
y3.add(t2)
y3.rsub(x3); y3.norm()
x3.copy(t0); x3.add(t0)
t0.add(x3); t0.norm()
t2.imul(b);
var z3=FP(t1); z3.add(t2); z3.norm()
t1.sub(t2); t1.norm()
y3.imul(b)
x3.copy(y3); x3.mul(t4); t2.copy(t3); t2.mul(t1); x3.rsub(t2)
y3.mul(t0); t1.mul(z3); y3.add(t1)
t0.mul(t3); z3.mul(t4); z3.add(t0)
x.copy(x3); x.norm()
y.copy(y3); y.norm()
z.copy(z3); z.norm()
}
else {
var t0=FP(x)
var t1=FP(y)
var t2=FP(z)
var t3=FP(x)
var t4=FP(Q.x)
var z3=FP(0)
var y3=FP(Q.x)
var x3=FP(Q.y)
var b=FP(0)
if ROM.CURVE_B_I==0
{
b.copy(FP(BIG(ROM.CURVE_B)))
}
t0.mul(Q.x) //1
t1.mul(Q.y) //2
t2.mul(Q.z) //3
t3.add(y); t3.norm() //4
t4.add(Q.y); t4.norm()//5
t3.mul(t4)//6
t4.copy(t0); t4.add(t1) //7
t3.sub(t4); t3.norm() //8
t4.copy(y); t4.add(z); t4.norm()//9
x3.add(Q.z); x3.norm()//10
t4.mul(x3) //11
x3.copy(t1); x3.add(t2) //12
t4.sub(x3); t4.norm()//13
x3.copy(x); x3.add(z); x3.norm() //14
y3.add(Q.z); y3.norm()//15
x3.mul(y3) //16
y3.copy(t0); y3.add(t2) //17
y3.rsub(x3); y3.norm() //18
z3.copy(t2)
if ROM.CURVE_B_I==0
{
z3.mul(b) //18
}
else {
z3.imul(ROM.CURVE_B_I)
}
x3.copy(y3); x3.sub(z3); x3.norm() //20
z3.copy(x3); z3.add(x3) //21
x3.add(z3) //22
z3.copy(t1); z3.sub(x3); z3.norm() //23
x3.add(t1); x3.norm() //24
if ROM.CURVE_B_I==0
{
y3.mul(b) //18
}
else {
y3.imul(ROM.CURVE_B_I)
}
t1.copy(t2); t1.add(t2) //26
t2.add(t1) //27
y3.sub(t2) //28
y3.sub(t0); y3.norm() //29
t1.copy(y3); t1.add(y3) //30
y3.add(t1); y3.norm() //31
t1.copy(t0); t1.add(t0) //32
t0.add(t1) //33
t0.sub(t2); t0.norm()//34
t1.copy(t4); t1.mul(y3)//35
t2.copy(t0); t2.mul(y3)//36
y3.copy(x3); y3.mul(z3)//37
y3.add(t2) //y3.norm();//38
x3.mul(t3)//39
x3.sub(t1)//40
z3.mul(t4)//41
t1.copy(t3); t1.mul(t0)//42
z3.add(t1)
x.copy(x3); x.norm()
y.copy(y3); y.norm()
z.copy(z3); z.norm()
}
}
if CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.EDWARDS
{
let b=FP(BIG(ROM.CURVE_B))
var A=FP(z)
var B=FP(0)
var C=FP(x)
var D=FP(y)
var E=FP(0)
var F=FP(0)
var G=FP(0)
A.mul(Q.z)
B.copy(A); B.sqr()
C.mul(Q.x)
D.mul(Q.y)
E.copy(C); E.mul(D); E.mul(b)
F.copy(B); F.sub(E)
G.copy(B); G.add(E)
if ROM.CURVE_A==1
{
E.copy(D); E.sub(C)
}
C.add(D)
B.copy(x); B.add(y)
D.copy(Q.x); D.add(Q.y)
B.norm(); D.norm()
B.mul(D)
B.sub(C); B.norm(); F.norm()
B.mul(F)
x.copy(A); x.mul(B)
G.norm()
if ROM.CURVE_A==1
{
E.norm(); C.copy(E); C.mul(G)
}
if ROM.CURVE_A == -1
{
C.norm(); C.mul(G)
}
y.copy(A); y.mul(C)
z.copy(F); z.mul(G)
}
return;
}
/* Differential Add for Montgomery curves. self+=Q where W is self-Q and is affine. */
mutating func dadd(_ Q:ECP,_ W:ECP)
{
var A=FP(x)
var B=FP(x)
var C=FP(Q.x)
var D=FP(Q.x)
var DA=FP(0)
var CB=FP(0)
A.add(z)
B.sub(z)
C.add(Q.z)
D.sub(Q.z)
A.norm()
D.norm()
DA.copy(D); DA.mul(A)
C.norm();
B.norm();
CB.copy(C); CB.mul(B)
A.copy(DA); A.add(CB); A.norm(); A.sqr()
B.copy(DA); B.sub(CB); B.norm(); B.sqr()
x.copy(A)
z.copy(W.x); z.mul(B)
}
/* this-=Q */
mutating func sub(_ Q:ECP)
{
var NQ=ECP(); NQ.copy(Q)
NQ.neg()
add(NQ)
}
/* constant time multiply by small integer of length bts - use ladder */
func pinmul(_ e:Int32,_ bts:Int32) -> ECP
{
if CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.MONTGOMERY
{return self.mul(BIG(Int(e)))}
else
{
var P=ECP()
var R0=ECP()
var R1=ECP(); R1.copy(self)
for i in (0...bts-1).reversed()
{
let b=Int(e>>i)&1;
P.copy(R1);
P.add(R0);
R0.cswap(&R1,b);
R1.copy(P);
R0.dbl();
R0.cswap(&R1,b);
}
P.copy(R0);
P.affine();
return P;
}
}
/* return e.self */
public func mul(_ e:BIG) -> ECP
{
if (e.iszilch() || is_infinity()) {return ECP()}
var P=ECP()
if CONFIG_CURVE.CURVETYPE == CONFIG_CURVE.MONTGOMERY
{
/* use Ladder */
var D=ECP()
var R0=ECP(); R0.copy(self)
var R1=ECP(); R1.copy(self)
R1.dbl();
D.copy(self); D.affine();
let nb=e.nbits();
for i in (0...nb-2).reversed()
{
let b=e.bit(UInt(i))
P.copy(R1)
P.dadd(R0,D)
R0.cswap(&R1,b)
R1.copy(P)
R0.dbl()
R0.cswap(&R1,b)
}
P.copy(R0)
}
else
{
// fixed size windows
var mt=BIG()
var t=BIG()
var Q=ECP()
var C=ECP()
var W=[ECP]()
let n=1+(CONFIG_BIG.NLEN*Int(CONFIG_BIG.BASEBITS)+3)/4
var w=[Int8](repeating: 0,count: n)
// precompute table
Q.copy(self)
Q.dbl()
W.append(ECP())
W[0].copy(self)
for i in 1 ..< 8
{
W.append(ECP())
W[i].copy(W[i-1])
W[i].add(Q)
}
// 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()
{
Q.select(W,Int32(w[i]));
P.dbl();
P.dbl();
P.dbl();
P.dbl();
P.add(Q);
}
P.sub(C); /* apply correction */
}
P.affine();
return P;
}
/* Return e.this+f.Q */
public func mul2(_ e:BIG,_ Q:ECP,_ f:BIG) -> ECP
{
var te=BIG()
var tf=BIG()
var mt=BIG()
var S=ECP()
var T=ECP()
var C=ECP()
var W=[ECP]()
let n=1+(CONFIG_BIG.NLEN*Int(CONFIG_BIG.BASEBITS)+1)/2
var w=[Int8](repeating: 0,count: n);
te.copy(e);
tf.copy(f);
// precompute table
for _ in 0 ..< 8 {W.append(ECP())}
W[1].copy(self); W[1].sub(Q)
W[2].copy(self); W[2].add(Q)
S.copy(Q); S.dbl();
W[0].copy(W[1]); W[0].sub(S)
W[3].copy(W[2]); W[3].add(S)
T.copy(self); T.dbl()
W[5].copy(W[1]); W[5].add(T)
W[6].copy(W[2]); W[6].add(T)
W[4].copy(W[5]); W[4].sub(S)
W[7].copy(W[6]); W[7].add(S)
// if multiplier is odd, add 2, else add 1 to multiplier, and add 2P or P to correction
var s=te.parity()
te.inc(1); te.norm(); var ns=te.parity(); mt.copy(te); mt.inc(1); mt.norm()
te.cmove(mt,s)
T.cmove(self,ns)
C.copy(T)
s=tf.parity()
tf.inc(1); tf.norm(); ns=tf.parity(); mt.copy(tf); mt.inc(1); mt.norm()
tf.cmove(mt,s)
S.cmove(Q,ns)
C.add(S)
mt.copy(te); mt.add(tf); mt.norm()
let nb=1+(mt.nbits()+1)/2
// convert exponent to signed 2-bit window
for i in 0 ..< nb
{
let a=(te.lastbits(3)-4);
te.dec(a); te.norm();
te.fshr(2);
let b=(tf.lastbits(3)-4);
tf.dec(b); tf.norm();
tf.fshr(2);
w[i]=Int8(4*a+b);
}
w[nb]=Int8(4*te.lastbits(3)+tf.lastbits(3));
S.copy(W[Int(w[nb]-1)/2]);
for i in (0...nb-1).reversed()
{
T.select(W,Int32(w[i]));
S.dbl();
S.dbl();
S.add(T);
}
S.sub(C); /* apply correction */
S.affine();
return S;
}
mutating func cfp()
{
let cf=ROM.CURVE_Cof_I;
if cf==1 {return}
if cf==4 {
dbl(); dbl()
return
}
if cf==8 {
dbl(); dbl(); dbl()
return;
}
let c=BIG(ROM.CURVE_Cof);
copy(mul(c));
}
static func mapit(_ h:[UInt8]) -> ECP
{
let q=BIG(ROM.Modulus)
var x=BIG.fromBytes(h)
x.mod(q)
var P=ECP()
while (true) {
while (true) {
if CONFIG_CURVE.CURVETYPE != CONFIG_CURVE.MONTGOMERY {
P.copy(ECP(x,0))
} else {
P.copy(ECP(x))
}
x.inc(1); x.norm();
if !P.is_infinity() {break}
}
P.cfp()
if !P.is_infinity() {break}
}
return P
}
static public func generator() -> ECP
{
let gx=BIG(ROM.CURVE_Gx);
var G:ECP
if CONFIG_CURVE.CURVETYPE != CONFIG_CURVE.MONTGOMERY
{
let gy=BIG(ROM.CURVE_Gy)
G=ECP(gx,gy)
}
else
{G=ECP(gx)}
return G
}
}