blob: ab99c1311fa1b15c64e8318429ebde0bda62dec1 [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.
*/
/* Finite Field arithmetic */
/* AMCL mod p functions */
public final class FP {
private final BIG x;
private static BIG p=new BIG(ROM.Modulus);
/* Constructors */
public FP(int a)
{
x=new BIG(a);
nres();
}
public FP(BIG a)
{
x=new BIG(a);
nres();
}
public FP(FP a)
{
x=new BIG(a.x);
}
/* convert to string */
public String toString()
{
String s=redc().toString();
return s;
}
public String toRawString()
{
String s=x.toRawString();
return s;
}
/* convert to Montgomery n-residue form */
public void nres()
{
if (ROM.MODTYPE!=ROM.PSEUDO_MERSENNE)
{
DBIG d=new DBIG(x);
d.shl(ROM.NLEN*ROM.BASEBITS);
x.copy(d.mod(p));
}
}
/* convert back to regular form */
public BIG redc()
{
if (ROM.MODTYPE!=ROM.PSEUDO_MERSENNE)
{
DBIG d=new DBIG(x);
return BIG.mod(d);
}
else
{
BIG r=new BIG(x);
return r;
}
}
/* test this=0? */
public boolean iszilch() {
reduce();
return x.iszilch();
}
/* copy from FP b */
public void copy(FP b)
{
x.copy(b.x);
}
/* set this=0 */
public void zero()
{
x.zero();
}
/* set this=1 */
public void one()
{
x.one(); nres();
}
/* normalise this */
public void norm()
{
x.norm();
}
/* swap FPs depending on d */
public void cswap(FP b,int d)
{
x.cswap(b.x,d);
}
/* copy FPs depending on d */
public void cmove(FP b,int d)
{
x.cmove(b.x,d);
}
/* this*=b mod Modulus */
public void mul(FP b)
{
long ea=BIG.EXCESS(x);
long eb=BIG.EXCESS(b.x);
if ((ea+1)*(eb+1)+1>=ROM.FEXCESS) reduce();
DBIG d=BIG.mul(x,b.x);
x.copy(BIG.mod(d));
}
/* this*=c mod Modulus, where c is a small int */
public void imul(int c)
{
norm();
boolean s=false;
if (c<0)
{
c=-c;
s=true;
}
long afx=(BIG.EXCESS(x)+1)*(c+1)+1;
if (c<ROM.NEXCESS && afx<ROM.FEXCESS)
{
x.imul(c);
}
else
{
if (afx<ROM.FEXCESS) x.pmul(c);
else
{
DBIG d=x.pxmul(c);
x.copy(d.mod(p));
}
}
if (s) neg();
norm();
}
/* this*=this mod Modulus */
public void sqr()
{
DBIG d;
long ea=BIG.EXCESS(x);
if ((ea+1)*(ea+1)+1>=ROM.FEXCESS)
reduce();
d=BIG.sqr(x);
x.copy(BIG.mod(d));
}
/* this+=b */
public void add(FP b) {
x.add(b.x);
if (BIG.EXCESS(x)+2>=ROM.FEXCESS) reduce();
}
/* this = -this mod Modulus */
public void neg()
{
int sb;
long ov;
BIG m=new BIG(p);
norm();
ov=BIG.EXCESS(x);
sb=1; while(ov!=0) {sb++;ov>>=1;}
m.fshl(sb);
x.rsub(m);
if (BIG.EXCESS(x)>=ROM.FEXCESS) reduce();
}
/* this-=b */
public void sub(FP b)
{
FP n=new FP(b);
n.neg();
this.add(n);
}
/* this/=2 mod Modulus */
public void div2()
{
x.norm();
if (x.parity()==0)
x.fshr(1);
else
{
x.add(p);
x.norm();
x.fshr(1);
}
}
/* this=1/this mod Modulus */
public void inverse()
{
BIG r=redc();
r.invmodp(p);
x.copy(r);
nres();
}
/* return TRUE if this==a */
public boolean equals(FP a)
{
a.reduce();
reduce();
if (BIG.comp(a.x,x)==0) return true;
return false;
}
/* reduce this mod Modulus */
public void reduce()
{
x.mod(p);
}
/* return this^e mod Modulus */
public FP pow(BIG e)
{
int bt;
FP r=new FP(1);
e.norm();
x.norm();
FP m=new FP(this);
while (true)
{
bt=e.parity();
e.fshr(1);
if (bt==1) r.mul(m);
if (e.iszilch()) break;
m.sqr();
}
r.x.mod(p);
return r;
}
/* return sqrt(this) mod Modulus */
public FP sqrt()
{
reduce();
BIG b=new BIG(p);
if (ROM.MOD8==5)
{
b.dec(5); b.norm(); b.shr(3);
FP i=new FP(this); i.x.shl(1);
FP v=i.pow(b);
i.mul(v); i.mul(v);
i.x.dec(1);
FP r=new FP(this);
r.mul(v); r.mul(i);
r.reduce();
return r;
}
else
{
b.inc(1); b.norm(); b.shr(2);
return pow(b);
}
}
/* return jacobi symbol (this/Modulus) */
public int jacobi()
{
BIG w=redc();
return w.jacobi(p);
}
/*
public static void main(String[] args) {
BIG m=new BIG(ROM.Modulus);
BIG x=new BIG(3);
BIG e=new BIG(m);
e.dec(1);
System.out.println("m= "+m.nbits());
BIG r=x.powmod(e,m);
System.out.println("m= "+m.toString());
System.out.println("r= "+r.toString());
BIG.cswap(m,r,0);
System.out.println("m= "+m.toString());
System.out.println("r= "+r.toString());
// FP y=new FP(3);
// FP s=y.pow(e);
// System.out.println("s= "+s.toString());
} */
}