blob: f87ca0c06ba49f1822892de59a28f05f7b977bf9 [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.
*/
//
// big.swift
//
// Created by Michael Scott on 12/06/2015.
// Copyright (c) 2015 Michael Scott. All rights reserved.
// BIG number class
//
import amcl
#if D32
public typealias Chunk = Int32
public typealias DChunk = Int64
#endif
#if D64
public typealias Chunk = Int64
#endif
public struct BIG{
#if D32
static public let CHUNK:Int=32
static let BASEBITS:UInt = @BASE32@
#endif
#if D64
static public let CHUNK:Int=64
static let BASEBITS:UInt = @BASE64@
#endif
static let MODBYTES:UInt = @NB@
static let NLEN:Int=Int(1+((8*BIG.MODBYTES-1)/BIG.BASEBITS))
static let DNLEN:Int=2*BIG.NLEN
static let BMASK:Chunk=((1<<Chunk(BIG.BASEBITS))-1)
static let HBITS = (BIG.BASEBITS/2)
static let HMASK:Chunk = ((1<<Chunk(BIG.HBITS))-1)
static let NEXCESS:Int = (1<<(BIG.CHUNK-Int(BIG.BASEBITS)-1))
static let BIGBITS:UInt = (BIG.MODBYTES*8)
var w=[Chunk](repeating: 0,count: NLEN)
/* Constructors */
init() {
for i in 0 ..< BIG.NLEN {w[i]=0}
}
init(_ x: Int)
{
w[0]=Chunk(x);
for i in 1 ..< BIG.NLEN {w[i]=0}
}
init(_ x: BIG)
{
for i in 0 ..< BIG.NLEN {w[i]=x.w[i]}
}
init(_ x: DBIG)
{
for i in 0 ..< BIG.NLEN {w[i]=x.w[i]}
}
public init(_ x: [Chunk])
{
for i in 0 ..< BIG.NLEN {w[i]=x[i]}
}
func get(_ i: Int) -> Chunk
{
return w[i]
}
mutating func set(_ i: Int,_ x: Chunk)
{
w[i]=x
}
mutating func xortop(_ x: Chunk)
{
w[BIG.NLEN-1]^=x
}
mutating func ortop(_ x: Chunk)
{
w[BIG.NLEN-1]|=x
}
#if D32
static func muladd(_ a: Chunk,_ b: Chunk,_ c: Chunk,_ r: Chunk) -> (Chunk,Chunk)
{
let prod:DChunk = DChunk(a)*DChunk(b)+DChunk(c)+DChunk(r)
let bot=Chunk(prod&DChunk(BIG.BMASK))
let top=Chunk(prod>>DChunk(BIG.BASEBITS))
return (top,bot)
}
#endif
#if D64
static func muladd(_ a: Chunk,_ b: Chunk,_ c: Chunk,_ r: Chunk) -> (Chunk,Chunk)
{
let (tp,bt)=a.multipliedFullWidth(by: b)
var bot = Chunk(bt)&BIG.BMASK
var top = (tp << Chunk(64-BIG.BASEBITS)) | Chunk(bt >> BIG.BASEBITS)
/*
let x0=a&BIG.HMASK;
let x1=(a>>Chunk(BIG.HBITS))
let y0=b&BIG.HMASK;
let y1=(b>>Chunk(BIG.HBITS))
var bot=x0*y0
var top=x1*y1
let mid=x0*y1+x1*y0
let u0=mid&BIG.HMASK
let u1=(mid>>Chunk(BIG.HBITS))
bot=bot+(u0<<Chunk(BIG.HBITS))
top+=u1
*/
bot+=c; bot+=r
let carry=bot>>Chunk(BIG.BASEBITS)
bot &= BIG.BMASK
top+=carry
return (top,bot)
}
#endif
/* test for zero */
func iszilch() -> Bool
{
for i in 0 ..< BIG.NLEN {if w[i] != 0 {return false}}
return true
}
/* set to zero */
mutating func zero()
{
for i in 0 ..< BIG.NLEN {w[i] = 0}
}
/* set to one */
mutating func one()
{
w[0]=1
for i in 1 ..< BIG.NLEN {w[i]=0}
}
/* Test for equal to one */
func isunity() -> Bool
{
for i in 1 ..< BIG.NLEN {if w[i] != 0 {return false}}
if w[0] != 1 {return false}
return true
}
/* Copy from another BIG */
mutating func copy(_ x: BIG)
{
for i in 0 ..< BIG.NLEN {w[i] = x.w[i]}
}
mutating func copy(_ x: DBIG)
{
for i in 0 ..< BIG.NLEN {w[i] = x.w[i]}
}
/* Conditional swap of two bigs depending on d using XOR - no branches */
mutating func cswap(_ b: inout BIG,_ d: Int)
{
var c = Chunk(d)
c = ~(c-1)
for i in 0 ..< BIG.NLEN
{
let t=c&(w[i]^b.w[i])
w[i]^=t
b.w[i]^=t
}
}
mutating func cmove(_ g: BIG,_ d: Int)
{
let b=Chunk(-d)
for i in 0 ..< BIG.NLEN
{
w[i]^=(w[i]^g.w[i])&b;
}
}
/* normalise BIG - force all digits < 2^BIG.BASEBITS */
@discardableResult mutating func norm() -> Chunk
{
var carry=Chunk(0);
for i in 0 ..< BIG.NLEN-1
{
let d=w[i]+carry
w[i]=d&BIG.BMASK
carry=d>>Chunk(BIG.BASEBITS)
}
w[BIG.NLEN-1]+=carry
return (w[BIG.NLEN-1]>>Chunk((8*BIG.MODBYTES)%BIG.BASEBITS))
}
/* Shift right by less than a word */
@discardableResult mutating func fshr(_ k: UInt) -> Int
{
let kw=Chunk(k);
let r=w[0]&((Chunk(1)<<kw)-1)
for i in 0 ..< BIG.NLEN-1
{
w[i]=(w[i]>>kw)|((w[i+1]<<(Chunk(BIG.BASEBITS)-kw))&BIG.BMASK)
}
w[BIG.NLEN-1]>>=kw;
return Int(r)
}
/* general shift right */
mutating func shr(_ k: UInt)
{
let n=k%BIG.BASEBITS
let m=Int(k/BIG.BASEBITS)
for i in 0 ..< BIG.NLEN-m-1
{
w[i]=(w[m+i]>>Chunk(n))|((w[m+i+1]<<Chunk(BIG.BASEBITS-n))&BIG.BMASK)
}
w[BIG.NLEN - m - 1]=w[BIG.NLEN-1]>>Chunk(n)
for i in BIG.NLEN - m ..< BIG.NLEN {w[i]=0}
}
/* Shift right by less than a word */
@discardableResult mutating func fshl(_ k: Int) -> Int
{
let kw=Chunk(k)
w[BIG.NLEN-1]=((w[BIG.NLEN-1]<<kw))|(w[BIG.NLEN-2]>>(Chunk(BIG.BASEBITS)-kw))
for i in (1...BIG.NLEN-2).reversed()
{
w[i]=((w[i]<<kw)&BIG.BMASK)|(w[i-1]>>(Chunk(BIG.BASEBITS)-kw))
}
w[0]=(w[0]<<kw)&BIG.BMASK
return Int(w[BIG.NLEN-1]>>Chunk((8*BIG.MODBYTES)%BIG.BASEBITS))
}
/* general shift left */
mutating func shl(_ k: UInt)
{
let n=k%BIG.BASEBITS
let m=Int(k/BIG.BASEBITS)
w[BIG.NLEN-1]=(w[BIG.NLEN-1-m]<<Chunk(n))
if BIG.NLEN>=m+2 {w[BIG.NLEN-1]|=(w[BIG.NLEN-m-2]>>Chunk(BIG.BASEBITS-n))}
for i in (m+1...BIG.NLEN-2).reversed()
{
w[i]=((w[i-m]<<Chunk(n))&BIG.BMASK)|(w[i-m-1]>>Chunk(BIG.BASEBITS-n))
}
w[m]=(w[0]<<Chunk(n))&BIG.BMASK
for i in 0 ..< m {w[i]=0}
}
/* return number of bits */
func nbits() -> Int
{
var k=(BIG.NLEN-1)
var t=BIG(self)
t.norm()
while k>=0 && t.w[k]==0 {k -= 1}
if k<0 {return 0}
var bts=Int(BIG.BASEBITS)*k
var c=t.w[k];
while c != 0 {c/=2; bts += 1}
return bts
}
func toRawString() -> String
{
var s:String="("
for i in 0 ..< BIG.NLEN-1
{
let n=String(w[i],radix:16,uppercase:false)
s+=n
s+=","
}
let n=String(w[BIG.NLEN-1],radix:16,uppercase:false)
s+=n
s+=")"
return s
}
/* Convert to Hex String */
func toString() -> String
{
_ = BIG()
var s:String=""
var len=nbits()
if len%4 == 0 {len/=4}
else {len/=4; len += 1}
if len<2*Int(BIG.MODBYTES) {len=2*Int(BIG.MODBYTES)}
for i in (0...len-1).reversed()
{
var b = BIG(self)
b.shr(UInt(i*4))
let n=String(b.w[0]&15,radix:16,uppercase:false)
s+=n
}
return s
}
/* return this+x */
func plus(_ x: BIG) -> BIG
{
var s=BIG()
for i in 0 ..< BIG.NLEN
{
s.w[i]=w[i]+x.w[i]
}
return s
}
/* this+=x */
mutating func add(_ x: BIG)
{
for i in 0 ..< BIG.NLEN
{
w[i]+=x.w[i]
}
}
/* this|=x */
mutating func or(_ x: BIG)
{
for i in 0 ..< BIG.NLEN
{
w[i]|=x.w[i]
}
}
/* this+=x, where x is int */
mutating func inc(_ x: Int) {
norm();
w[0]+=Chunk(x);
}
/* return this.x */
func minus(_ x: BIG) -> BIG
{
var d=BIG();
for i in 0 ..< BIG.NLEN
{
d.w[i]=w[i]-x.w[i];
}
return d;
}
/* this-=x */
mutating func sub(_ x: BIG)
{
for i in 0 ..< BIG.NLEN
{
w[i]-=x.w[i]
}
}
/* reverse subtract this=x-this */
mutating func rsub(_ x: BIG)
{
for i in 0 ..< BIG.NLEN
{
w[i]=x.w[i]-w[i]
}
}
/* this-=x where x is int */
mutating func dec(_ x: Int) {
norm();
w[0]-=Chunk(x);
}
/* this*=x, where x is small int<NEXCESS */
mutating func imul(_ c: Int)
{
for i in 0 ..< BIG.NLEN {w[i]*=Chunk(c)}
}
/* convert this BIG to byte array */
func tobytearray(_ b: inout [UInt8],_ n: Int)
{
//norm();
var c=BIG(self);
c.norm()
for i in (0...Int(BIG.MODBYTES)-1).reversed()
{
b[i+n]=UInt8(c.w[0]&0xff);
c.fshr(8);
}
}
/* convert from byte array to BIG */
static func frombytearray(_ b: [UInt8],_ n: Int) -> BIG
{
var m=BIG();
for i in 0 ..< Int(BIG.MODBYTES)
{
m.fshl(8)
m.w[0]+=Chunk(b[i+n])&0xff //(int)b[i+n]&0xff;
}
return m;
}
func toBytes(_ b: inout [UInt8])
{
tobytearray(&b,0)
}
static func fromBytes(_ b: [UInt8]) -> BIG
{
return frombytearray(b,0)
}
/* set this[i]+=x*y+c, and return high part
func muladd(_ x: Int32,_ y: Int32,_ c: Int32,_ i: Int) -> Int32
{
let prod:DChunk = DChunk(x)*DChunk(y)+DChunk(c)+DChunk(w[i])
w[i]=Int32(prod&DChunk(BIG.BMASK))
return Int32(prod>>DChunk(BIG.BASEBITS))
} */
/* this*=x, where x is >NEXCESS */
@discardableResult mutating func pmul(_ c: Int) -> Chunk
{
var carry=Chunk(0);
//norm();
for i in 0 ..< BIG.NLEN
{
let ak=w[i]
let (top,bot)=BIG.muladd(ak,Chunk(c),carry,Chunk(0))
carry=top; w[i]=bot;
}
return carry;
}
/* this*=c and catch overflow in DBIG */
mutating func pxmul(_ c: Int) -> DBIG
{
var m=DBIG()
var carry=Chunk(0)
for j in 0 ..< BIG.NLEN
{
let (top,bot)=BIG.muladd(w[j],Chunk(c),carry,m.w[j])
carry=top; m.w[j]=bot
}
m.w[BIG.NLEN]=carry
return m;
}
/* divide by 3 */
mutating func div3() -> Chunk
{
var carry=Chunk(0)
norm();
let base=Chunk(1<<BIG.BASEBITS);
for i in (0...BIG.NLEN-1).reversed()
{
let ak=(carry*base+w[i]);
w[i]=ak/3;
carry=ak%3;
}
return carry;
}
/* return a*b where result fits in a BIG */
static func smul(_ a: BIG,_ b: BIG) -> BIG
{
var c=BIG()
for i in 0 ..< BIG.NLEN
{
var carry=Chunk(0)
for j in 0 ..< BIG.NLEN
{
if (i+j<BIG.NLEN) {
let (top,bot)=BIG.muladd(a.w[i],b.w[j],carry,c.w[i+j])
carry=top; c.w[i+j]=bot
//carry=c.muladd(a.w[i],b.w[j],carry,i+j)
}
}
}
return c;
}
/* Compare a and b, return 0 if a==b, -1 if a<b, +1 if a>b. Inputs must be normalised */
static func comp(_ a: BIG,_ b: BIG) -> Int
{
for i in (0...BIG.NLEN-1).reversed()
{
if (a.w[i]==b.w[i]) {continue}
if (a.w[i]>b.w[i]) {return 1}
else {return -1}
}
return 0;
}
/* set x = x mod 2^m */
mutating func mod2m(_ m: UInt)
{
let wd=Int(m/BIG.BASEBITS)
let bt=m%BIG.BASEBITS
let msk=Chunk(1<<bt)-1;
w[wd]&=msk;
for i in wd+1 ..< BIG.NLEN {w[i]=0}
}
/* Arazi and Qi inversion mod 256 */
static func invmod256(_ a: Int) -> Int
{
var t1:Int=0
var c=(a>>1)&1
t1+=c
t1&=1
t1=2-t1
t1<<=1
var U=t1+1
// i=2
var b=a&3
t1=U*b; t1>>=2
c=(a>>2)&3
var t2=(U*c)&3
t1+=t2
t1*=U; t1&=3
t1=4-t1
t1<<=2
U+=t1
// i=4
b=a&15
t1=U*b; t1>>=4
c=(a>>4)&15
t2=(U*c)&15
t1+=t2
t1*=U; t1&=15
t1=16-t1
t1<<=4
U+=t1
return U
}
/* return parity */
func parity() -> Int
{
return Int(w[0]%2)
}
/* return n-th bit */
func bit(_ n: UInt) -> Int
{
if ((w[Int(n/BIG.BASEBITS)]&(1<<Chunk(n%BIG.BASEBITS)))>0) {return 1;}
else {return 0;}
}
/* return n last bits */
mutating func lastbits(_ n: UInt) -> Int
{
let msk=(Chunk(1)<<Chunk(n))-1;
norm();
return Int((w[0])&msk)
}
/* a=1/a mod 2^256. This is very fast! */
mutating func invmod2m()
{
var U=BIG()
var b=BIG()
var c=BIG()
U.inc(BIG.invmod256(lastbits(8)))
var i=UInt(8)
while (i<BIG.BIGBITS)
{
U.norm();
b.copy(self)
b.mod2m(i)
var t1=BIG.smul(U,b)
t1.shr(i)
c.copy(self)
c.shr(i)
c.mod2m(i)
var t2=BIG.smul(U,c)
t2.mod2m(i)
t1.add(t2); t1.norm()
b=BIG.smul(t1,U)
t1.copy(b)
t1.mod2m(i)
t2.one(); t2.shl(i); t1.rsub(t2); t1.norm()
t1.shl(i)
U.add(t1)
i<<=1
}
U.mod2m(BIG.BIGBITS)
self.copy(U)
self.norm()
}
/* reduce this mod m */
mutating func mod(_ m1: BIG)
{
var k=0
var m=BIG(m1)
var r=BIG(0)
norm()
if (BIG.comp(self,m)<0) {return}
repeat
{
m.fshl(1)
k += 1
} while (BIG.comp(self,m)>=0)
while (k>0)
{
m.fshr(1)
r.copy(self)
r.sub(m)
r.norm()
cmove(r,Int(1-((r.w[BIG.NLEN-1]>>Chunk(BIG.CHUNK-1))&1)))
/*
if (BIG.comp(self,m)>=0)
{
sub(m)
norm()
} */
k -= 1
}
}
/* divide this by m */
mutating func div(_ m1: BIG)
{
var k=0
norm()
var e=BIG(1)
var b=BIG(self)
var r=BIG(0)
var m=BIG(m1)
zero()
while (BIG.comp(b,m)>=0)
{
e.fshl(1)
m.fshl(1)
k += 1
}
while (k>0)
{
m.fshr(1)
e.fshr(1)
r.copy(b)
r.sub(m)
r.norm()
let d=Int(1-((r.w[BIG.NLEN-1]>>Chunk(BIG.CHUNK-1))&1))
b.cmove(r,d)
r.copy(self)
r.add(e)
r.norm()
cmove(r,d)
/*
if (BIG.comp(b,m)>=0)
{
add(e)
norm()
b.sub(m)
b.norm()
} */
k -= 1;
}
}
/* get 8*BIG.MODBYTES size random number */
static func random(_ rng: inout RAND) -> BIG
{
var m=BIG();
var j:Int=0
var r:UInt8=0
/* generate random BIG */
for _ in 0 ..< Int(8*BIG.MODBYTES)
{
if (j==0) {r=rng.getByte()}
else {r>>=1}
let b=Chunk(r&1);
m.shl(1); m.w[0]+=b;// m.inc(b);
j += 1; j&=7;
}
return m;
}
/* Create random BIG in portable way, one bit at a time, less than q */
static public func randomnum(_ q: BIG,_ rng: inout RAND) -> BIG
{
var d=DBIG(0);
var j:Int=0
var r:UInt8=0
for _ in 0 ..< 2*q.nbits()
{
if (j==0) {r=rng.getByte()}
else {r>>=1}
let b=Chunk(r&1);
d.shl(1); d.w[0]+=b; // m.inc(b);
j += 1; j&=7;
}
let m=d.mod(q);
return m;
}
/* return NAF value as +/- 1, 3 or 5. x and x3 should be normed.
nbs is number of bits processed, and nzs is number of trailing 0s detected
static func nafbits(_ x: BIG,_ x3:BIG ,i:Int) -> [Chunk]
{
var j:Int
var n=[Chunk](repeating: 0,count: 3)
var nb=x3.bit(UInt(i))-x.bit(UInt(i))
n[1]=1;
n[0]=0;
if (nb==0) {n[0]=0; return n}
if (i==0) {n[0]=Chunk(nb); return n}
if (nb>0) {n[0]=1}
else {n[0]=(-1)}
j=i-1
while (true)
{
n[1] += 1
n[0]*=2
nb=x3.bit(UInt(j))-x.bit(UInt(j))
if (nb>0) {n[0]+=1}
if (nb<0) {n[0]-=1}
if (n[0]>5 || n[0] < -5) {break}
j-=1
if j==0 {break}
}
if ((n[0]%2 != 0) && (j != 0))
{ // backtrack
if (nb>0) {n[0]=(n[0]-1)/2}
if (nb<0) {n[0]=(n[0]+1)/2}
n[1] -= 1;
}
while (n[0]%2==0)
{ // remove trailing zeros
n[0]/=2
n[2] += 1
n[1] -= 1
}
return n;
} */
/* Jacobi Symbol (this/p). Returns 0, 1 or -1 */
mutating func jacobi(_ p: BIG) -> Int
{
var n8:Int
var k:Int
var m:Int=0;
var t=BIG()
var x=BIG()
var n=BIG()
let zilch=BIG()
let one=BIG(1)
if (p.parity()==0 || BIG.comp(self,zilch)==0 || BIG.comp(p,one)<=0) {return 0}
norm()
x.copy(self)
n.copy(p)
x.mod(p)
while (BIG.comp(n,one)>0)
{
if (BIG.comp(x,zilch)==0) {return 0}
n8=n.lastbits(3)
k=0
while (x.parity()==0)
{
k += 1
x.shr(1)
}
if (k%2==1) {m+=((n8*n8-1)/8)}
let w=Int(x.lastbits(2)-1)
m+=(n8-1)*w/4
t.copy(n)
t.mod(x)
n.copy(x)
x.copy(t)
m%=2
}
if (m==0) {return 1}
else {return -1}
}
/* this=1/this mod p. Binary method */
mutating func invmodp(_ p: BIG)
{
mod(p)
var u=BIG(self)
var v=BIG(p)
var x1=BIG(1)
var x2=BIG()
var t=BIG()
let one=BIG(1)
while ((BIG.comp(u,one) != 0 ) && (BIG.comp(v,one) != 0 ))
{
while (u.parity()==0)
{
u.fshr(1);
if (x1.parity() != 0 )
{
x1.add(p);
x1.norm();
}
x1.fshr(1);
}
while (v.parity()==0)
{
v.fshr(1);
if (x2.parity() != 0 )
{
x2.add(p);
x2.norm();
}
x2.fshr(1);
}
if (BIG.comp(u,v)>=0)
{
u.sub(v);
u.norm();
if (BIG.comp(x1,x2)>=0) {x1.sub(x2)}
else
{
t.copy(p);
t.sub(x2);
x1.add(t);
}
x1.norm();
}
else
{
v.sub(u);
v.norm();
if (BIG.comp(x2,x1)>=0) {x2.sub(x1)}
else
{
t.copy(p);
t.sub(x1);
x2.add(t);
}
x2.norm();
}
}
if (BIG.comp(u,one)==0) {copy(x1)}
else {copy(x2)}
}
/* return a*b as DBIG */
#if D32
static func mul(_ a: BIG,_ b:BIG) -> DBIG
{
var t:DChunk
var co:DChunk
var c=DBIG()
let RM:DChunk=DChunk(BIG.BMASK);
let RB:DChunk=DChunk(BIG.BASEBITS)
// a.norm();
// b.norm();
var d=[DChunk](repeating: 0,count: BIG.NLEN)
var s:DChunk
for i in 0 ..< BIG.NLEN
{
d[i]=DChunk(a.w[i])*DChunk(b.w[i]);
}
s=d[0]
t=s; c.w[0]=Chunk(t&RM); co=t>>RB
for k in 1 ..< BIG.NLEN
{
s+=d[k]; t=co+s;
for i in 1+k/2...k
{t+=DChunk(a.w[i]-a.w[k-i])*DChunk(b.w[k-i]-b.w[i])}
c.w[k]=Chunk(t&RM); co=t>>RB
}
for k in BIG.NLEN ..< 2*BIG.NLEN-1
{
s-=d[k-BIG.NLEN]; t=co+s;
//for var i=BIG.NLEN-1;i>=1+k/2;i--
var i=1+k/2
while i<BIG.NLEN
//for i in 1+k/2...BIG.NLEN-1
{
t+=DChunk(a.w[i]-a.w[k-i])*DChunk(b.w[k-i]-b.w[i])
i+=1
}
c.w[k]=Chunk(t&RM); co=t>>RB
}
c.w[2*BIG.NLEN-1]=Chunk(co);
return c
}
/* return a^2 as DBIG */
static func sqr(_ a: BIG) -> DBIG
{
var t:DChunk
var co:DChunk
var c=DBIG()
let RM:DChunk=DChunk(BIG.BMASK);
let RB:DChunk=DChunk(BIG.BASEBITS)
// a.norm();
t=DChunk(a.w[0])*DChunk(a.w[0])
c.w[0]=Chunk(t&RM); co=t>>RB
var j:Int
j=1
while j<BIG.NLEN-1
{
t=DChunk(a.w[j])*DChunk(a.w[0]); for i in 1 ..< (j+1)/2 {t+=DChunk(a.w[j-i])*DChunk(a.w[i])}; t+=t; t+=co
c.w[j]=Chunk(t&RM); co=t>>RB
j+=1
t=DChunk(a.w[j])*DChunk(a.w[0]); for i in 1 ..< (j+1)/2 {t+=DChunk(a.w[j-i])*DChunk(a.w[i])}; t+=t; t+=co; t+=DChunk(a.w[j/2])*DChunk(a.w[j/2])
c.w[j]=Chunk(t&RM); co=t>>RB
j+=1
}
j=BIG.NLEN-1+(BIG.NLEN%2)
while j<BIG.DNLEN-3
{
t=DChunk(a.w[BIG.NLEN-1])*DChunk(a.w[j-BIG.NLEN+1]); for i in j-BIG.NLEN+2 ..< (j+1)/2 {t+=DChunk(a.w[j-i])*DChunk(a.w[i])}; t+=t; t+=co
c.w[j]=Chunk(t&RM); co=t>>RB
j+=1;
t=DChunk(a.w[BIG.NLEN-1])*DChunk(a.w[j-BIG.NLEN+1]); for i in j-BIG.NLEN+2 ..< (j+1)/2 {t+=DChunk(a.w[j-i])*DChunk(a.w[i])}; t+=t; t+=co; t+=DChunk(a.w[j/2])*DChunk(a.w[j/2])
c.w[j]=Chunk(t&RM); co=t>>RB
j+=1;
}
t=DChunk(a.w[BIG.NLEN-2])*DChunk(a.w[BIG.NLEN-1])
t+=t; t+=co;
c.w[BIG.DNLEN-3]=Chunk(t&RM); co=t>>RB
t=DChunk(a.w[BIG.NLEN-1])*DChunk(a.w[BIG.NLEN-1])+co
c.w[BIG.DNLEN-2]=Chunk(t&RM); co=t>>RB
c.w[BIG.DNLEN-1]=Chunk(co)
/*
t=DChunk(a.w[0])*DChunk(a.w[0])
c.w[0]=Chunk(t&RM); co=t>>RB
t=DChunk(a.w[1])*DChunk(a.w[0]); t+=t; t+=co
c.w[1]=Chunk(t&RM); co=t>>RB
var j:Int
let last=BIG.NLEN-(BIG.NLEN%2)
j=2
//for j=2;j<last;j+=2
while (j<last)
{
t=DChunk(a.w[j])*DChunk(a.w[0]); for i in 1 ..< (j+1)/2 {t+=DChunk(a.w[j-i])*DChunk(a.w[i])} ; t+=t; t+=co; t+=DChunk(a.w[j/2])*DChunk(a.w[j/2])
c.w[j]=Chunk(t&RM); co=t>>RB
t=DChunk(a.w[j+1])*DChunk(a.w[0]); for i in 1 ..< (j+2)/2 {t+=DChunk(a.w[j+1-i])*DChunk(a.w[i])} ; t+=t; t+=co
c.w[j+1]=Chunk(t&RM); co=t>>RB
j+=2
}
j=last
if (BIG.NLEN%2)==1
{
t=DChunk(a.w[j])*DChunk(a.w[0]); for i in 1 ..< (j+1)/2 {t+=DChunk(a.w[j-i])*DChunk(a.w[i])} ; t+=t; t+=co; t+=DChunk(a.w[j/2])*DChunk(a.w[j/2])
c.w[j]=Chunk(t&RM); co=t>>RB; j += 1
t=DChunk(a.w[BIG.NLEN-1])*DChunk(a.w[j-BIG.NLEN+1]); for i in j-BIG.NLEN+2 ..< (j+1)/2 {t+=DChunk(a.w[j-i])*DChunk(a.w[i])}; t+=t; t+=co
c.w[j]=Chunk(t&RM); co=t>>RB; j += 1
}
while (j<BIG.DNLEN-2)
{
t=DChunk(a.w[BIG.NLEN-1])*DChunk(a.w[j-BIG.NLEN+1]); for i in j-BIG.NLEN+2 ..< (j+1)/2 {t+=DChunk(a.w[j-i])*DChunk(a.w[i])} ; t+=t; t+=co; t+=DChunk(a.w[j/2])*DChunk(a.w[j/2])
c.w[j]=Chunk(t&RM); co=t>>RB
t=DChunk(a.w[BIG.NLEN-1])*DChunk(a.w[j-BIG.NLEN+2]); for i in j-BIG.NLEN+3 ..< (j+2)/2 {t+=DChunk(a.w[j+1-i])*DChunk(a.w[i])} ; t+=t; t+=co
c.w[j+1]=Chunk(t&RM); co=t>>RB
j+=2
}
t=DChunk(a.w[BIG.NLEN-1])*DChunk(a.w[BIG.NLEN-1])+co
c.w[BIG.DNLEN-2]=Chunk(t&RM); co=t>>RB
c.w[BIG.DNLEN-1]=Chunk(co)
*/
return c;
}
static func monty(_ md:BIG,_ mc:Chunk,_ d: inout DBIG) -> BIG
{
// let md=BIG(ROM.Modulus);
let RM:DChunk=DChunk(BIG.BMASK)
let RB:DChunk=DChunk(BIG.BASEBITS)
var t:DChunk
var s:DChunk
var c:DChunk
var dd=[DChunk](repeating: 0,count: BIG.NLEN)
var v=[Chunk](repeating: 0,count: BIG.NLEN)
var b=BIG(0)
t=DChunk(d.w[0]); v[0]=(Chunk(t&RM)&*mc)&BIG.BMASK; t+=DChunk(v[0])*DChunk(md.w[0]); c=DChunk(d.w[1])+(t>>RB); s=0
for k in 1 ..< BIG.NLEN
{
t=c+s+DChunk(v[0])*DChunk(md.w[k])
//for i in 1+k/2...k-1
//for var i=k-1;i>k/2;i--
var i=1+k/2
while i<k
{
t+=DChunk(v[k-i]-v[i])*DChunk(md.w[i]-md.w[k-i])
i+=1
}
v[k]=(Chunk(t&RM)&*mc)&BIG.BMASK; t+=DChunk(v[k])*DChunk(md.w[0]); c=DChunk(d.w[k+1])+(t>>RB)
dd[k]=DChunk(v[k])*DChunk(md.w[k]); s+=dd[k]
}
for k in BIG.NLEN ..< 2*BIG.NLEN-1
{
t=c+s;
//for i in 1+k/2...BIG.NLEN-1
//for var i=BIG.NLEN-1;i>=1+k/2;i--
var i=1+k/2
while i<BIG.NLEN
{
t+=DChunk(v[k-i]-v[i])*DChunk(md.w[i]-md.w[k-i])
i+=1
}
b.w[k-BIG.NLEN]=Chunk(t&RM); c=DChunk(d.w[k+1])+(t>>RB); s-=dd[k-BIG.NLEN+1]
}
b.w[BIG.NLEN-1]=Chunk(c&RM)
// b.norm()
return b;
}
#endif
#if D64
static func mul(_ a: BIG,_ b:BIG) -> DBIG
{
var c=DBIG()
var carry:Chunk
for i in 0 ..< BIG.NLEN {
carry=0
for j in 0..<BIG.NLEN {
let (top,bot)=BIG.muladd(a.w[i],b.w[j],carry,c.w[i+j])
carry=top; c.w[i+j]=bot
}
c.w[BIG.NLEN+i]=carry
}
return c
}
static func sqr(_ a: BIG) -> DBIG
{
var c=DBIG()
var carry:Chunk
for i in 0 ..< BIG.NLEN {
carry=0
for j in i+1 ..< BIG.NLEN {
let (top,bot)=BIG.muladd(2*a.w[i],a.w[j],carry,c.w[i+j])
carry=top; c.w[i+j]=bot
}
c.w[BIG.NLEN+i]=carry
}
for i in 0 ..< BIG.NLEN {
let (top,bot)=BIG.muladd(a.w[i],a.w[i],Chunk(0),c.w[2*i])
c.w[2*i]=bot
c.w[2*i+1]+=top
}
c.norm()
return c
}
static func monty(_ md:BIG,_ mc:Chunk,_ d: inout DBIG) -> BIG
{
var b=BIG()
// let md=BIG(ROM.Modulus);
var carry:Chunk
var m:Chunk
for i in 0 ..< BIG.NLEN {
if mc == -1 {
m=(-d.w[i])&BIG.BMASK
} else {
if mc == 1 {
m=d.w[i]
} else {
m=(mc&*d.w[i])&BIG.BMASK;
}
}
carry=0
for j in 0 ..< BIG.NLEN {
let (top,bot)=BIG.muladd(m,md.w[j],carry,d.w[i+j])
carry=top; d.w[i+j]=bot
}
d.w[BIG.NLEN+i]+=carry
}
for i in 0 ..< BIG.NLEN {
b.w[i]=d.w[BIG.NLEN+i]
}
b.norm();
return b
}
#endif
/* Optimized combined shift, subtract and norm */
static func ssn(_ r: inout BIG,_ a :BIG,_ m: inout BIG) -> Int
{
let n=BIG.NLEN-1
m.w[0]=(m.w[0]>>1)|((m.w[1]<<Chunk(BIG.BASEBITS-1))&BIG.BMASK)
r.w[0]=a.w[0]-m.w[0]
var carry=r.w[0]>>Chunk(BIG.BASEBITS)
r.w[0] &= BIG.BMASK
for i in 1 ..< n {
m.w[i]=(m.w[i]>>1)|((m.w[i+1]<<Chunk(BIG.BASEBITS-1))&BIG.BMASK)
r.w[i]=a.w[i]-m.w[i]+carry
carry=r.w[i]>>Chunk(BIG.BASEBITS)
r.w[i] &= BIG.BMASK
}
m.w[n]>>=1
r.w[n]=a.w[n]-m.w[n]+carry
return Int((r.w[n]>>Chunk(BIG.CHUNK-1))&Chunk(1))
}
/* return a*b mod m */
static func modmul(_ a1: BIG,_ b1 :BIG,_ m: BIG) -> BIG
{
var a=BIG(a1); var b=BIG(b1);
a.mod(m)
b.mod(m)
var d=mul(a,b)
return d.mod(m)
}
/* return a^2 mod m */
static func modsqr(_ a1: BIG,_ m: BIG) -> BIG
{
var a=BIG(a1)
a.mod(m)
var d=sqr(a)
return d.mod(m)
}
/* return -a mod m */
static func modneg(_ a1: BIG,_ m: BIG) -> BIG
{
var a=BIG(a1)
a.mod(m)
return m.minus(a)
}
/* return this^e mod m */
mutating func powmod(_ e1: BIG,_ m: BIG) -> BIG
{
norm();
var e=BIG(e1)
e.norm();
var a=BIG(1)
var z=BIG(e)
var s=BIG(self)
while (true)
{
let bt=z.parity();
z.fshr(1)
if bt==1 {a=BIG.modmul(a,s,m)}
if (z.iszilch()) {break}
s=BIG.modsqr(s,m)
}
return a
}
}