-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
paillier.hpp
162 lines (154 loc) · 3.78 KB
/
paillier.hpp
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#pragma once
/**
@file
@brief paillier encryption
@author MITSUNARI Shigeo(@herumi)
@license modified new BSD license
http://www.opensource.org/licenses/bsd-license.php
*/
#include <fstream>
#include <vector>
#include <mie/gmp_util.hpp>
#include <cybozu/random_generator.hpp>
namespace mie { namespace paillier {
template<class T>
struct LoadSave {
void load(const std::string& fileName)
{
std::ifstream ifs(fileName.c_str(), std::ios::binary);
if (!ifs) throw cybozu::Exception("load:can't open") << fileName;
ifs >> static_cast<T&>(*this);
}
void save(const std::string& fileName) const
{
std::ofstream ofs(fileName.c_str(), std::ios::binary);
if (!ofs) throw cybozu::Exception("save:can't open") << fileName;
ofs << static_cast<const T&>(*this);
}
};
class PublicKey : public LoadSave<PublicKey> {
mpz_class n;
size_t nLen;
mpz_class nn; // n^2
mpz_class g; // n + 1
// call finish after setting n
void finish()
{
nLen = Gmp::getBitLen(n);
nn = n * n;
g = n + 1;
}
friend class PrivateKey;
public:
const mpz_class& getN() const { return n; }
friend inline std::istream& operator>>(std::istream& is, PublicKey& self)
{
is >> std::hex >> self.n;
self.finish();
return is;
}
friend inline std::ostream& operator<<(std::ostream& os, const PublicKey& self)
{
os << std::hex << self.n;
return os;
}
void L(mpz_class& y, const mpz_class& x) const
{
y = x - 1;
y /= n;
}
void mul(mpz_class& z, const mpz_class& x, const mpz_class &y) const
{
z = x * y;
z %= nn;
}
void pow(mpz_class& z, const mpz_class& x, const mpz_class& y) const
{
Gmp::powMod(z, x, y, nn);
}
/*
encMsg = (g^msg) (r^n) mod n^2
*/
template<class RG>
void enc(mpz_class& encMsg, const mpz_class& msg, RG& rg) const
{
if (msg >= n) throw cybozu::Exception("too large msg");
mpz_class r;
Gmp::getRand(r, nLen * 2 - 2, rg);
Gmp::powMod(r, r, n, nn);
Gmp::powMod(encMsg, g, msg, nn);
mul(encMsg, encMsg, r);
}
void enc(mpz_class& encMsg, const mpz_class& msg) const
{
cybozu::RandomGenerator rg;
enc(encMsg, msg, rg);
}
bool operator==(const PublicKey& rhs) const
{
return n == rhs.n && nLen == rhs.nLen && nn == rhs.nn && g == rhs.g;
}
bool operator!=(const PublicKey& rhs) const { return !operator==(rhs); }
};
class PrivateKey : public LoadSave<PrivateKey> {
mpz_class p;
mpz_class q;
mpz_class lambda; // lcm(p-1, q-1)
PublicKey pub;
mpz_class x; // 1 / L(g^lambda mod n^2) mod n
// call finish after setting p, q
void finish()
{
pub.n = p * q;
pub.finish();
Gmp::lcm(lambda, p - 1, q - 1);
// x = (n + 1)^lambda mod n^2
Gmp::powMod(x, pub.g, lambda, pub.nn);
pub.L(x, x);
// 1 / L() mod n
Gmp::invMod(x, x, pub.n);
}
public:
template<class RG>
void init(size_t keyLen, RG& rg)
{
Gmp::getRandPrime(p, (keyLen + 1) / 2, rg, true);
Gmp::getRandPrime(q, (keyLen + 1) / 2, rg, true);
pub.n = p * q;
finish();
pub.finish();
}
void init(size_t keyLen)
{
cybozu::RandomGenerator rg;
init(keyLen, rg);
}
const PublicKey& getPublicKey() const { return pub; }
friend inline std::istream& operator>>(std::istream& is, PrivateKey& self)
{
is >> std::hex >> self.p >> self.q;
self.finish();
return is;
}
friend inline std::ostream& operator<<(std::ostream& os, const PrivateKey& self)
{
os << std::hex << self.p << ' ' << self.q;
return os;
}
/*
decMsg = L(encMsg^lambda mod n^2) / L(g^lambda mod n^2) mod n
*/
void dec(mpz_class& decMsg, const mpz_class& encMsg) const
{
Gmp::powMod(decMsg, encMsg, lambda, pub.nn);
pub.L(decMsg, decMsg);
decMsg *= x;
decMsg %= pub.n;
}
bool operator==(const PrivateKey& rhs) const
{
return p == rhs.p && q == rhs.q && lambda == rhs.lambda && pub == rhs.pub && x == rhs.x;
}
bool operator!=(const PrivateKey& rhs) const { return !operator==(rhs); }
};
} } // mie::paillier