mirror of
https://github.com/data61/MP-SPDZ.git
synced 2026-01-10 14:08:09 -05:00
329 lines
7.2 KiB
C++
329 lines
7.2 KiB
C++
#include "Zp_Data.h"
|
|
#include "modp.h"
|
|
#include "Z2k.hpp"
|
|
|
|
#include "Tools/Exceptions.h"
|
|
|
|
/***********************************************************************
|
|
* The following functions remain the same in Real and Montgomery rep *
|
|
***********************************************************************/
|
|
|
|
template<int L>
|
|
void modp_<L>::randomize(PRNG& G, const Zp_Data& ZpD)
|
|
{
|
|
const int M = sizeof(mp_limb_t) * L;
|
|
switch (ZpD.pr_byte_length)
|
|
{
|
|
#define X(LL) case LL: G.randomBnd<LL>(x, ZpD.get_prA(), ZpD.overhang_mask()); break;
|
|
X(M) X(M-1) X(M-2) X(M-3) X(M-4) X(M-5) X(M-6) X(M-7)
|
|
#undef X
|
|
default:
|
|
G.randomBnd(x, ZpD.get_prA(), ZpD.pr_byte_length, ZpD.overhang_mask());
|
|
}
|
|
}
|
|
|
|
template<int L>
|
|
void modp_<L>::unpack(octetStream& o,const Zp_Data& ZpD)
|
|
{
|
|
o.consume((octet*) x,ZpD.t*sizeof(mp_limb_t));
|
|
}
|
|
|
|
template<int L>
|
|
void modp_<L>::unpack(octetStream& o)
|
|
{
|
|
o.consume((octet*) x,L*sizeof(mp_limb_t));
|
|
}
|
|
|
|
template<int L>
|
|
void modp_<L>::pack(octetStream& o) const
|
|
{
|
|
o.append((octet*) x,L*sizeof(mp_limb_t));
|
|
}
|
|
|
|
template<int L>
|
|
void Negate(modp_<L>& ans,const modp_<L>& x,const Zp_Data& ZpD)
|
|
{
|
|
if (isZero(x,ZpD)) { ans=x; return; }
|
|
mpn_sub_n(ans.x,ZpD.prA,x.x,ZpD.t);
|
|
}
|
|
|
|
|
|
template<int L>
|
|
bool areEqual(const modp_<L>& x,const modp_<L>& y,const Zp_Data& ZpD)
|
|
{ if (mpn_cmp(x.x,y.x,ZpD.t)!=0)
|
|
{ return false; }
|
|
return true;
|
|
}
|
|
|
|
template<int L>
|
|
bool isZero(const modp_<L>& 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 *
|
|
***********************************************************************/
|
|
|
|
|
|
template<int L>
|
|
void assignOne(modp_<L>& x,const Zp_Data& ZpD)
|
|
{ if (ZpD.montgomery)
|
|
{ mpn_copyi(x.x,ZpD.R,ZpD.t); }
|
|
else
|
|
{ assignZero(x,ZpD);
|
|
x.x[0]=1;
|
|
}
|
|
}
|
|
|
|
|
|
template<int L>
|
|
bool isOne(const modp_<L>& 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<min(ZpD.t, L); i++)
|
|
{ if (x.x[i]!=0) { return false; } }
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
template<int L>
|
|
void modp_<L>::to_bigint(bigint& ans,const Zp_Data& ZpD,bool reduce) const
|
|
{
|
|
auto& x = *this;
|
|
mpz_ptr a = ans.get_mpz_t();
|
|
if (a->_mp_alloc < ZpD.t)
|
|
mpz_realloc(a, ZpD.t);
|
|
if (ZpD.montgomery)
|
|
{
|
|
mp_limb_t one[MAX_MOD_SZ];
|
|
inline_mpn_zero(one,L);
|
|
one[0]=1;
|
|
ZpD.Mont_Mult(a->_mp_d,x.x,one);
|
|
}
|
|
else
|
|
{ inline_mpn_copyi(a->_mp_d,x.x,ZpD.t); }
|
|
a->_mp_size=ZpD.t;
|
|
if (reduce)
|
|
while (a->_mp_size>=1 && (a->_mp_d)[a->_mp_size-1]==0)
|
|
{ a->_mp_size--; }
|
|
}
|
|
|
|
|
|
template<int L>
|
|
template<int M>
|
|
void modp_<L>::to_bigint(bigint& ans,const Zp_Data& ZpD,bool reduce) const
|
|
{
|
|
assert(M == ZpD.t);
|
|
auto& x = *this;
|
|
mpz_ptr a = ans.get_mpz_t();
|
|
if (a->_mp_alloc < M)
|
|
mpz_realloc(a, M);
|
|
if (ZpD.montgomery)
|
|
{
|
|
mp_limb_t one[M];
|
|
inline_mpn_zero(one,M);
|
|
one[0]=1;
|
|
ZpD.Mont_Mult_<M>(a->_mp_d,x.x,one);
|
|
}
|
|
else
|
|
{ inline_mpn_copyi(a->_mp_d,x.x,M); }
|
|
a->_mp_size=M;
|
|
if (reduce)
|
|
while (a->_mp_size>=1 && (a->_mp_d)[a->_mp_size-1]==0)
|
|
{ a->_mp_size--; }
|
|
}
|
|
|
|
|
|
template<int L>
|
|
void to_modp(modp_<L>& ans,int x,const Zp_Data& ZpD)
|
|
{
|
|
inline_mpn_zero(ans.x,ZpD.t);
|
|
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 = bigint::tmp = ZpD.pr+x;
|
|
to_modp(ans,xx,ZpD);
|
|
return;
|
|
}
|
|
}
|
|
if (ZpD.montgomery)
|
|
{ ZpD.Mont_Mult(ans.x,ans.x,ZpD.R2); }
|
|
}
|
|
|
|
|
|
template<int L>
|
|
void to_modp(modp_<L>& ans,const mpz_class& x,const Zp_Data& ZpD)
|
|
{
|
|
if (x == 0)
|
|
{
|
|
assignZero(ans, ZpD);
|
|
return;
|
|
}
|
|
else if (x == 1)
|
|
{
|
|
assignOne(ans, ZpD);
|
|
return;
|
|
}
|
|
bigint::tmp = x;
|
|
ans.convert_destroy(bigint::tmp, ZpD);
|
|
}
|
|
|
|
|
|
template<int L>
|
|
void modp_<L>::convert_destroy(bigint& xx,
|
|
const Zp_Data& ZpD)
|
|
{
|
|
xx %= ZpD.pr;
|
|
//mpz_mod(xx.get_mpz_t(),x.get_mpz_t(),ZpD.pr.get_mpz_t());
|
|
convert(xx.get_mpz_t()->_mp_d, abs(xx.get_mpz_t()->_mp_size), ZpD, xx < 0);
|
|
}
|
|
|
|
template<int L>
|
|
template<int M>
|
|
void modp_<L>::convert_destroy(const fixint<M>& xx,
|
|
const Zp_Data& ZpD)
|
|
{
|
|
assert(xx.size_in_limbs() <= L);
|
|
SignedZ2<64 * L> tmp = xx;
|
|
if (xx.negative())
|
|
tmp += ZpD.pr;
|
|
convert(tmp.get(), ZpD.t, ZpD, false);
|
|
}
|
|
|
|
template<int L>
|
|
void modp_<L>::convert(const mp_limb_t* source, mp_size_t size, const Zp_Data& ZpD, bool negative)
|
|
{
|
|
assert(size <= ZpD.t);
|
|
if (negative)
|
|
mpn_sub(x, ZpD.prA, ZpD.t, source, size);
|
|
else
|
|
{
|
|
inline_mpn_zero(x + size, ZpD.t - size);
|
|
inline_mpn_copyi(x, source, size);
|
|
}
|
|
if (ZpD.montgomery)
|
|
ZpD.Mont_Mult(x, x, ZpD.R2);
|
|
}
|
|
|
|
|
|
|
|
template<int L>
|
|
void Sqr(modp_<L>& ans,const modp_<L>& 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*L],q[2*L];
|
|
mpn_sqr(aa,x.x,ZpD.t);
|
|
mpn_tdiv_qr(q,ans.x,0,aa,2*ZpD.t,ZpD.prA,ZpD.t);
|
|
}
|
|
}
|
|
|
|
|
|
template<int L>
|
|
void Inv(modp_<L>& ans,const modp_<L>& x,const Zp_Data& ZpD)
|
|
{
|
|
mp_limb_t g[L],xx[L],yy[L];
|
|
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
|
|
template<int L>
|
|
void Power(modp_<L>& ans,const modp_<L>& 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_<L> 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
|
|
template<int L>
|
|
void Power(modp_<L>& ans,const modp_<L>& 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 = bigint::tmp = exp;
|
|
while (e!=0)
|
|
{ if ((e&1)==1) { Mul(ans,ans,t,ZpD); }
|
|
e>>=1;
|
|
Sqr(t,t,ZpD);
|
|
}
|
|
}
|
|
|
|
|
|
template<int L>
|
|
void modp_<L>::output(ostream& s,const Zp_Data& ZpD,bool human) const
|
|
{
|
|
if (human)
|
|
{ bigint te;
|
|
to_bigint(te, ZpD);
|
|
if (te < ZpD.pr / 2)
|
|
s << te;
|
|
else
|
|
s << (te - ZpD.pr);
|
|
}
|
|
else
|
|
{ s.write((char*) x,ZpD.t*sizeof(mp_limb_t)); }
|
|
}
|
|
|
|
template<int L>
|
|
void modp_<L>::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("modp input");
|
|
}
|
|
throw end_of_file("modp");
|
|
}
|
|
|
|
if (human)
|
|
{ bigint te;
|
|
s >> te;
|
|
to_modp(*this,te,ZpD);
|
|
}
|
|
else
|
|
{ s.read((char*) x,ZpD.t*sizeof(mp_limb_t)); }
|
|
}
|