-
Notifications
You must be signed in to change notification settings - Fork 364
/
modp.h
141 lines (108 loc) · 4.37 KB
/
modp.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// (C) 2018 University of Bristol. See License.txt
#ifndef _Modp
#define _Modp
/*
* Currently we only support an MPIR based implementation.
*
* What ever is type-def'd to bigint is assumed to have
* operator overloading for all standard operators, has
* comparison operations and istream/ostream operators >>/<<.
*
* All "integer" operations will be done using operator notation
* all "modp" operations should be done using the function calls
* below (interchange with Montgomery arithmetic).
*
*/
#include "Tools/octetStream.h"
#include "Tools/random.h"
#include "Math/bigint.h"
#include "Math/Zp_Data.h"
void to_bigint(bigint& ans,const modp& x,const Zp_Data& ZpD,bool reduce=true);
class modp
{
static bool rewind;
mp_limb_t x[MAX_MOD_SZ];
public:
// NEXT FUNCTION IS FOR DEBUG PURPOSES ONLY
mp_limb_t get_limb(int i) const { return x[i]; }
// use mem* functions instead of mpn_*, so the compiler can optimize
modp()
{ avx_memzero(x, sizeof(x)); }
modp(const modp& y)
{ memcpy(x, y.x, sizeof(x)); }
modp& operator=(const modp& y)
{ if (this!=&y) { memcpy(x, y.x, sizeof(x)); }
return *this;
}
void assign(const char* buffer, int t) { memcpy(x, buffer, t * sizeof(mp_limb_t)); }
void convert_destroy(bigint& source, const Zp_Data& ZpD);
void convert_destroy(int source, const Zp_Data& ZpD) { to_modp(*this, source, ZpD); }
void randomize(PRNG& G, const Zp_Data& ZpD);
// Pack and unpack in native format
// i.e. Dont care about conversion to human readable form
// i.e. When we do montgomery we dont care about decoding
void pack(octetStream& o,const Zp_Data& ZpD) const;
void unpack(octetStream& o,const Zp_Data& ZpD);
bool operator==(const modp& other) const { return 0 == mpn_cmp(x, other.x, MAX_MOD_SZ); }
bool operator!=(const modp& other) const { return not (*this == other); }
/**********************************
* Modp Operations *
**********************************/
// Convert representation to and from a modp number
friend void to_bigint(bigint& ans,const modp& x,const Zp_Data& ZpD,bool reduce);
friend void to_modp(modp& ans,int x,const Zp_Data& ZpD);
friend void to_modp(modp& ans,const bigint& x,const Zp_Data& ZpD);
template <int T>
friend void Add(modp& ans,const modp& x,const modp& y,const Zp_Data& ZpD);
friend void Add(modp& ans,const modp& x,const modp& y,const Zp_Data& ZpD)
{ ZpD.Add(ans.x, x.x, y.x); }
friend void Sub(modp& ans,const modp& x,const modp& y,const Zp_Data& ZpD);
friend void Mul(modp& ans,const modp& x,const modp& y,const Zp_Data& ZpD);
friend void Sqr(modp& ans,const modp& x,const Zp_Data& ZpD);
friend void Negate(modp& ans,const modp& x,const Zp_Data& ZpD);
friend void Inv(modp& ans,const modp& x,const Zp_Data& ZpD);
friend void Power(modp& ans,const modp& x,int exp,const Zp_Data& ZpD);
friend void Power(modp& ans,const modp& x,const bigint& exp,const Zp_Data& ZpD);
friend void assignOne(modp& x,const Zp_Data& ZpD);
friend void assignZero(modp& x,const Zp_Data& ZpD);
friend bool isZero(const modp& x,const Zp_Data& ZpD);
friend bool isOne(const modp& x,const Zp_Data& ZpD);
friend bool areEqual(const modp& x,const modp& y,const Zp_Data& ZpD);
// Input and output from a stream
// - Can do in human or machine only format (later should be faster)
// - If human output appends a space to help with reading
// and also convert back/forth from Montgomery if needed
void output(ostream& s,const Zp_Data& ZpD,bool human) const;
void input(istream& s,const Zp_Data& ZpD,bool human);
friend class gfp;
};
inline void assignZero(modp& x,const Zp_Data& ZpD)
{
if (sizeof(x.x) <= 3 * 16)
// use memset to allow the compiler to optimize
// if x.x is at most 3*128 bits
avx_memzero(x.x, sizeof(x.x));
else
inline_mpn_zero(x.x, ZpD.t);
}
template <int T>
inline void Add(modp& ans,const modp& x,const modp& y,const Zp_Data& ZpD)
{
ZpD.Add<T>(ans.x, x.x, y.x);
}
inline void Sub(modp& ans,const modp& x,const modp& y,const Zp_Data& ZpD)
{
ZpD.Sub(ans.x, x.x, y.x);
}
inline 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);
}
}
#endif