Files
MP-SPDZ/Math/modp.cpp
2016-09-02 19:16:51 +01:00

264 lines
5.8 KiB
C++

// (C) 2016 University of Bristol. See License.txt
#include "Zp_Data.h"
#include "modp.h"
#include "Exceptions/Exceptions.h"
bool modp::rewind = false;
/***********************************************************************
* The following functions remain the same in Real and Montgomery rep *
***********************************************************************/
void modp::randomize(PRNG& G, const Zp_Data& ZpD)
{
bigint x=G.randomBnd(ZpD.pr);
to_modp(*this,x,ZpD);
}
void modp::pack(octetStream& o,const Zp_Data& ZpD) const
{
o.append((octet*) x,ZpD.t*sizeof(mp_limb_t));
}
void modp::unpack(octetStream& o,const Zp_Data& ZpD)
{
o.consume((octet*) x,ZpD.t*sizeof(mp_limb_t));
}
void Sub(modp& ans,const modp& x,const modp& y,const Zp_Data& ZpD)
{
ZpD.Sub(ans.x, x.x, y.x);
}
void Negate(modp& ans,const modp& x,const Zp_Data& ZpD)
{
if (isZero(x,ZpD)) { ans=x; return; }
mpn_sub_n(ans.x,ZpD.prA,x.x,ZpD.t);
}
bool areEqual(const modp& x,const modp& y,const Zp_Data& ZpD)
{ if (mpn_cmp(x.x,y.x,ZpD.t)!=0)
{ return false; }
return true;
}
bool isZero(const modp& ans,const Zp_Data& ZpD)
{
for (int i=0; i<ZpD.t; i++)
{ if (ans.x[i]!=0) { return false; } }
return true;
}
/***********************************************************************
* All the remaining functions have Montgomery variants which we need *
* to deal with *
***********************************************************************/
void assignOne(modp& x,const Zp_Data& ZpD)
{ if (ZpD.montgomery)
{ mpn_copyi(x.x,ZpD.R,ZpD.t+1); }
else
{ assignZero(x,ZpD);
x.x[0]=1;
}
}
bool isOne(const modp& x,const Zp_Data& ZpD)
{ if (ZpD.montgomery)
{ if (mpn_cmp(x.x,ZpD.R,ZpD.t)!=0)
{ return false; }
}
else
{ if (x.x[0]!=1) { return false; }
for (int i=1; i<ZpD.t; i++)
{ if (x.x[i]!=0) { return false; } }
}
return true;
}
void to_bigint(bigint& ans,const modp& x,const Zp_Data& ZpD,bool reduce)
{
mpz_t a;
mpz_init2(a,MAX_MOD_SZ*sizeof(mp_limb_t)*8);
if (ZpD.montgomery)
{ mp_limb_t one[MAX_MOD_SZ];
mpn_zero(one,ZpD.t+1);
one[0]=1;
ZpD.Mont_Mult(a->_mp_d,x.x,one);
}
else
{ mpn_copyi(a->_mp_d,x.x,ZpD.t+1); }
a->_mp_size=ZpD.t;
if (reduce)
while (a->_mp_size>=1 && (a->_mp_d)[a->_mp_size-1]==0)
{ a->_mp_size--; }
ans=bigint(a);
mpz_clear(a);
}
void to_modp(modp& ans,int x,const Zp_Data& ZpD)
{
mpn_zero(ans.x,ZpD.t+1);
if (x>=0)
{ ans.x[0]=x;
if (ZpD.t==1) { ans.x[0]=ans.x[0]%ZpD.prA[0]; }
}
else
{ if (ZpD.t==1)
{ ans.x[0]=(ZpD.prA[0]+x)%ZpD.prA[0]; }
else
{ bigint xx=ZpD.pr+x;
to_modp(ans,xx,ZpD);
return;
}
}
if (ZpD.montgomery)
{ ZpD.Mont_Mult(ans.x,ans.x,ZpD.R2); }
}
void to_modp(modp& ans,const bigint& x,const Zp_Data& ZpD)
{
bigint xx=x%ZpD.pr;
if (xx<0) { xx+=ZpD.pr; }
//mpz_mod(xx.get_mpz_t(),x.get_mpz_t(),ZpD.pr.get_mpz_t());
mpn_zero(ans.x,ZpD.t+1);
mpn_copyi(ans.x,xx.get_mpz_t()->_mp_d,xx.get_mpz_t()->_mp_size);
if (ZpD.montgomery)
{ ZpD.Mont_Mult(ans.x,ans.x,ZpD.R2); }
}
void Mul(modp& ans,const modp& x,const modp& y,const Zp_Data& ZpD)
{
if (ZpD.montgomery)
{ ZpD.Mont_Mult(ans.x,x.x,y.x); }
else
{ //ans.x=(x.x*y.x)%ZpD.pr;
mp_limb_t aa[2*MAX_MOD_SZ],q[2*MAX_MOD_SZ];
mpn_mul_n(aa,x.x,y.x,ZpD.t);
mpn_tdiv_qr(q,ans.x,0,aa,2*ZpD.t,ZpD.prA,ZpD.t);
}
}
void Sqr(modp& ans,const modp& x,const Zp_Data& ZpD)
{
if (ZpD.montgomery)
{ ZpD.Mont_Mult(ans.x,x.x,x.x); }
else
{ //ans.x=(x.x*x.x)%ZpD.pr;
mp_limb_t aa[2*MAX_MOD_SZ],q[2*MAX_MOD_SZ];
mpn_sqr(aa,x.x,ZpD.t);
mpn_tdiv_qr(q,ans.x,0,aa,2*ZpD.t,ZpD.prA,ZpD.t);
}
}
void Inv(modp& ans,const modp& x,const Zp_Data& ZpD)
{
mp_limb_t g[MAX_MOD_SZ],xx[MAX_MOD_SZ+1],yy[MAX_MOD_SZ+1];
mp_size_t sz;
mpn_copyi(xx,x.x,ZpD.t);
mpn_copyi(yy,ZpD.prA,ZpD.t);
mpn_gcdext(g,ans.x,&sz,xx,ZpD.t,yy,ZpD.t);
if (sz<0)
{ mpn_sub(ans.x,ZpD.prA,ZpD.t,ans.x,-sz);
sz=-sz;
}
else
{ for (int i=sz; i<ZpD.t; i++) { ans.x[i]=0; } }
if (ZpD.montgomery)
{ ZpD.Mont_Mult(ans.x,ans.x,ZpD.R3); }
}
// XXXX This is a crap version. Hopefully this is not time critical
void Power(modp& ans,const modp& x,int exp,const Zp_Data& ZpD)
{
if (exp==1) { ans=x; return; }
if (exp==0) { assignOne(ans,ZpD); return; }
if (exp<0) { throw not_implemented(); }
modp t=x;
assignOne(ans,ZpD);
while (exp!=0)
{ if ((exp&1)==1) { Mul(ans,ans,t,ZpD); }
exp>>=1;
Sqr(t,t,ZpD);
}
}
// XXXX This is a crap version. Hopefully this is not time critical
void Power(modp& ans,const modp& x,const bigint& exp,const Zp_Data& ZpD)
{
if (exp==1) { ans=x; return; }
if (exp==0) { assignOne(ans,ZpD); return; }
if (exp<0) { throw not_implemented(); }
modp t=x;
assignOne(ans,ZpD);
bigint e=exp;
while (e!=0)
{ if ((e&1)==1) { Mul(ans,ans,t,ZpD); }
e>>=1;
Sqr(t,t,ZpD);
}
}
void modp::output(ostream& s,const Zp_Data& ZpD,bool human) const
{
if (human)
{ bigint te;
to_bigint(te,*this,ZpD);
if (te < ZpD.pr / 2)
s << te;
else
s << (te - ZpD.pr);
}
else
{ s.write((char*) x,ZpD.t*sizeof(mp_limb_t)); }
}
void modp::input(istream& s,const Zp_Data& ZpD,bool human)
{
if (s.peek() == EOF)
{ if (s.tellg() == 0)
{ cout << "IO problem. Empty file?" << endl;
throw file_error();
}
//throw end_of_file();
s.clear(); // unset EOF flag
s.seekg(0);
if (!rewind)
cout << "REWINDING - ONLY FOR BENCHMARKING" << endl;
rewind = true;
}
if (human)
{ bigint te;
s >> te;
to_modp(*this,te,ZpD);
}
else
{ s.read((char*) x,ZpD.t*sizeof(mp_limb_t)); }
}