|
|
|
@ -179,7 +179,6 @@ struct ElgamalT { |
|
|
|
|
|
|
|
|
|
class PublicKey { |
|
|
|
|
size_t bitSize; |
|
|
|
|
Ec f; |
|
|
|
|
Ec g; |
|
|
|
|
Ec h; |
|
|
|
|
bool enableWindowMethod_; |
|
|
|
@ -196,8 +195,6 @@ struct ElgamalT { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
template<class N> |
|
|
|
|
void mulF(Ec& z, const N& n) const { mulDispatch(z, f, n, wm_f); } |
|
|
|
|
template<class N> |
|
|
|
|
void mulG(Ec& z, const N& n) const { mulDispatch(z, g, n, wm_g); } |
|
|
|
|
template<class N> |
|
|
|
|
void mulH(Ec& z, const N& n) const { mulDispatch(z, h, n, wm_h); } |
|
|
|
@ -209,16 +206,14 @@ struct ElgamalT { |
|
|
|
|
} |
|
|
|
|
void enableWindowMethod(size_t winSize = 10) |
|
|
|
|
{ |
|
|
|
|
wm_f.init(f, bitSize, winSize); |
|
|
|
|
wm_g.init(g, bitSize, winSize); |
|
|
|
|
wm_h.init(h, bitSize, winSize); |
|
|
|
|
enableWindowMethod_ = true; |
|
|
|
|
} |
|
|
|
|
const Ec& getF() const { return f; } |
|
|
|
|
void init(size_t bitSize, const Ec& f, const Ec& g, const Ec& h) |
|
|
|
|
const Ec& getG() const { return g; } |
|
|
|
|
void init(size_t bitSize, const Ec& g, const Ec& h) |
|
|
|
|
{ |
|
|
|
|
this->bitSize = bitSize; |
|
|
|
|
this->f = f; |
|
|
|
|
this->g = g; |
|
|
|
|
this->h = h; |
|
|
|
|
enableWindowMethod_ = false; |
|
|
|
@ -227,7 +222,7 @@ struct ElgamalT { |
|
|
|
|
/*
|
|
|
|
|
encode message |
|
|
|
|
input : m |
|
|
|
|
output : c = (c1, c2) = (g^u, h^u f^m) |
|
|
|
|
output : c = (c1, c2) = (g^u, h^u g^m) |
|
|
|
|
*/ |
|
|
|
|
void enc(CipherText& c, const Zn& m, fp::RandGen rg = fp::RandGen()) const |
|
|
|
|
{ |
|
|
|
@ -236,7 +231,7 @@ struct ElgamalT { |
|
|
|
|
mulG(c.c1, u); |
|
|
|
|
mulH(c.c2, u); |
|
|
|
|
Ec t; |
|
|
|
|
mulF(t, m); |
|
|
|
|
mulG(t, m); |
|
|
|
|
Ec::add(c.c2, c.c2, t); |
|
|
|
|
} |
|
|
|
|
/*
|
|
|
|
@ -254,7 +249,7 @@ struct ElgamalT { |
|
|
|
|
mulG(c.c1, u); |
|
|
|
|
mulH(c.c2, u); |
|
|
|
|
if (m) { |
|
|
|
|
Ec::add(c.c2, c.c2, f); |
|
|
|
|
Ec::add(c.c2, c.c2, g); |
|
|
|
|
Zn r1; |
|
|
|
|
r1.setRand(rg); |
|
|
|
|
zkp.c0.setRand(rg); |
|
|
|
@ -270,7 +265,7 @@ struct ElgamalT { |
|
|
|
|
mulG(R11, r1); |
|
|
|
|
mulH(R12, r1); |
|
|
|
|
std::ostringstream os; |
|
|
|
|
os << R01 << R02 << R11 << R12 << c.c1 << c.c2 << f << g << h; |
|
|
|
|
os << R01 << R02 << R11 << R12 << c.c1 << c.c2 << g << h; |
|
|
|
|
Zn cc; |
|
|
|
|
cc.setHashOf(os.str()); |
|
|
|
|
zkp.c1 = cc - zkp.c0; |
|
|
|
@ -288,11 +283,11 @@ struct ElgamalT { |
|
|
|
|
Ec::mul(t2, c.c1, zkp.c1); |
|
|
|
|
Ec::sub(R11, t1, t2); |
|
|
|
|
mulH(t1, zkp.s1); |
|
|
|
|
Ec::sub(t2, c.c2, f); |
|
|
|
|
Ec::sub(t2, c.c2, g); |
|
|
|
|
Ec::mul(t2, t2, zkp.c1); |
|
|
|
|
Ec::sub(R12, t1, t2); |
|
|
|
|
std::ostringstream os; |
|
|
|
|
os << R01 << R02 << R11 << R12 << c.c1 << c.c2 << f << g << h; |
|
|
|
|
os << R01 << R02 << R11 << R12 << c.c1 << c.c2 << g << h; |
|
|
|
|
Zn cc; |
|
|
|
|
cc.setHashOf(os.str()); |
|
|
|
|
zkp.c0 = cc - zkp.c1; |
|
|
|
@ -316,11 +311,11 @@ struct ElgamalT { |
|
|
|
|
Ec::mul(t2, c.c1, zkp.c1); |
|
|
|
|
Ec::sub(R11, t1, t2); |
|
|
|
|
mulH(t1, zkp.s1); |
|
|
|
|
Ec::sub(t2, c.c2, f); |
|
|
|
|
Ec::sub(t2, c.c2, g); |
|
|
|
|
Ec::mul(t2, t2, zkp.c1); |
|
|
|
|
Ec::sub(R12, t1, t2); |
|
|
|
|
std::ostringstream os; |
|
|
|
|
os << R01 << R02 << R11 << R12 << c.c1 << c.c2 << f << g << h; |
|
|
|
|
os << R01 << R02 << R11 << R12 << c.c1 << c.c2 << g << h; |
|
|
|
|
Zn cc; |
|
|
|
|
cc.setHashOf(os.str()); |
|
|
|
|
return cc == zkp.c0 + zkp.c1; |
|
|
|
@ -343,13 +338,13 @@ struct ElgamalT { |
|
|
|
|
/*
|
|
|
|
|
add encoded message with plain message |
|
|
|
|
input : c = Enc(m1) = (c1, c2), m2 |
|
|
|
|
ouput : c = Enc(m1 + m2) = (c1, c2 f^m2) |
|
|
|
|
ouput : c = Enc(m1 + m2) = (c1, c2 g^m2) |
|
|
|
|
*/ |
|
|
|
|
template<class N> |
|
|
|
|
void add(CipherText& c, const N& m) const |
|
|
|
|
{ |
|
|
|
|
Ec fm; |
|
|
|
|
mulF(fm, m); |
|
|
|
|
mulG(fm, m); |
|
|
|
|
Ec::add(c.c2, c.c2, fm); |
|
|
|
|
} |
|
|
|
|
template<class InputStream> |
|
|
|
@ -358,10 +353,9 @@ struct ElgamalT { |
|
|
|
|
std::string s; |
|
|
|
|
mcl::fp::local::loadWord(s, is); |
|
|
|
|
bitSize = cybozu::atoi(s); |
|
|
|
|
f.load(is, ioMode); |
|
|
|
|
g.load(is, ioMode); |
|
|
|
|
h.load(is, ioMode); |
|
|
|
|
init(bitSize, f, g, h); |
|
|
|
|
init(bitSize, g, h); |
|
|
|
|
} |
|
|
|
|
template<class OutputStream> |
|
|
|
|
void save(OutputStream& os, int ioMode = IoSerialize) const |
|
|
|
@ -371,7 +365,6 @@ struct ElgamalT { |
|
|
|
|
cybozu::writeChar(os, ' '); |
|
|
|
|
|
|
|
|
|
const char sep = *fp::getIoSeparator(ioMode); |
|
|
|
|
f.save(os, ioMode); |
|
|
|
|
if (sep) cybozu::writeChar(os, sep); |
|
|
|
|
g.save(os, ioMode); |
|
|
|
|
if (sep) cybozu::writeChar(os, sep); |
|
|
|
@ -410,7 +403,7 @@ struct ElgamalT { |
|
|
|
|
void fromStr(const std::string& str) { setStr(str); } |
|
|
|
|
}; |
|
|
|
|
/*
|
|
|
|
|
create table f^i for i in [rangeMin, rangeMax] |
|
|
|
|
create table g^i for i in [rangeMin, rangeMax] |
|
|
|
|
*/ |
|
|
|
|
struct PowerCache { |
|
|
|
|
#if (CYBOZU_CPP_VERSION > CYBOZU_CPP_VERSION_CP03) |
|
|
|
@ -419,18 +412,18 @@ struct ElgamalT { |
|
|
|
|
typedef std::map<Ec, int> Cache; |
|
|
|
|
#endif |
|
|
|
|
Cache cache; |
|
|
|
|
void init(const Ec& f, int rangeMin, int rangeMax) |
|
|
|
|
void init(const Ec& g, int rangeMin, int rangeMax) |
|
|
|
|
{ |
|
|
|
|
if (rangeMin > rangeMax) throw cybozu::Exception("mcl:ElgamalT:PowerCache:bad range") << rangeMin << rangeMax; |
|
|
|
|
Ec x; |
|
|
|
|
x.clear(); |
|
|
|
|
cache[x] = 0; |
|
|
|
|
for (int i = 1; i <= rangeMax; i++) { |
|
|
|
|
Ec::add(x, x, f); |
|
|
|
|
Ec::add(x, x, g); |
|
|
|
|
cache[x] = i; |
|
|
|
|
} |
|
|
|
|
Ec nf; |
|
|
|
|
Ec::neg(nf, f); |
|
|
|
|
Ec::neg(nf, g); |
|
|
|
|
x.clear(); |
|
|
|
|
for (int i = -1; i >= rangeMin; i--) { |
|
|
|
|
Ec::add(x, x, nf); |
|
|
|
@ -438,17 +431,17 @@ struct ElgamalT { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
/*
|
|
|
|
|
return m such that f^m = g |
|
|
|
|
return m such that g^m = y |
|
|
|
|
*/ |
|
|
|
|
int getExponent(const Ec& g, bool *b = 0) const |
|
|
|
|
int getExponent(const Ec& y, bool *b = 0) const |
|
|
|
|
{ |
|
|
|
|
typename Cache::const_iterator i = cache.find(g); |
|
|
|
|
typename Cache::const_iterator i = cache.find(y); |
|
|
|
|
if (i == cache.end()) { |
|
|
|
|
if (b) { |
|
|
|
|
*b = false; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
throw cybozu::Exception("Elgamal:PowerCache:getExponent:not found") << g; |
|
|
|
|
throw cybozu::Exception("Elgamal:PowerCache:getExponent:not found") << y; |
|
|
|
|
} |
|
|
|
|
if (b) *b = true; |
|
|
|
|
return i->second; |
|
|
|
@ -469,20 +462,17 @@ struct ElgamalT { |
|
|
|
|
public: |
|
|
|
|
/*
|
|
|
|
|
init |
|
|
|
|
input : f |
|
|
|
|
output : (g, h, z) |
|
|
|
|
Ec = <f> |
|
|
|
|
g in Ec |
|
|
|
|
input : g |
|
|
|
|
output : (h, z) |
|
|
|
|
Ec = <g> |
|
|
|
|
h = g^z |
|
|
|
|
*/ |
|
|
|
|
void init(const Ec& f, size_t bitSize, fp::RandGen rg = fp::RandGen()) |
|
|
|
|
void init(const Ec& g, size_t bitSize, fp::RandGen rg = fp::RandGen()) |
|
|
|
|
{ |
|
|
|
|
Ec g, h; |
|
|
|
|
z.setRand(rg); |
|
|
|
|
Ec::mul(g, f, z); |
|
|
|
|
Ec h; |
|
|
|
|
z.setRand(rg); |
|
|
|
|
Ec::mul(h, g, z); |
|
|
|
|
pub.init(bitSize, f, g, h); |
|
|
|
|
pub.init(bitSize, g, h); |
|
|
|
|
} |
|
|
|
|
const PublicKey& getPublicKey() const { return pub; } |
|
|
|
|
/*
|
|
|
|
@ -490,12 +480,12 @@ struct ElgamalT { |
|
|
|
|
input : c = (c1, c2) |
|
|
|
|
output : m |
|
|
|
|
M = c2 / c1^z |
|
|
|
|
find m such that M = f^m and |m| < limit |
|
|
|
|
find m such that M = g^m and |m| < limit |
|
|
|
|
@memo 7sec@core i3 for m = 1e6 |
|
|
|
|
*/ |
|
|
|
|
void dec(Zn& m, const CipherText& c, int limit = 100000) const |
|
|
|
|
{ |
|
|
|
|
const Ec& f = pub.getF(); |
|
|
|
|
const Ec& g = pub.getG(); |
|
|
|
|
Ec c1z; |
|
|
|
|
Ec::mul(c1z, c.c1, z); |
|
|
|
|
if (c1z == c.c2) { |
|
|
|
@ -505,12 +495,12 @@ struct ElgamalT { |
|
|
|
|
Ec t1(c1z); |
|
|
|
|
Ec t2(c.c2); |
|
|
|
|
for (int i = 1; i < limit; i++) { |
|
|
|
|
Ec::add(t1, t1, f); |
|
|
|
|
Ec::add(t1, t1, g); |
|
|
|
|
if (t1 == c.c2) { |
|
|
|
|
m = i; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
Ec::add(t2, t2, f); |
|
|
|
|
Ec::add(t2, t2, g); |
|
|
|
|
if (t2 == c1z) { |
|
|
|
|
m = -i; |
|
|
|
|
return; |
|
|
|
@ -519,20 +509,20 @@ struct ElgamalT { |
|
|
|
|
throw cybozu::Exception("elgamal:PrivateKey:dec:overflow"); |
|
|
|
|
} |
|
|
|
|
/*
|
|
|
|
|
powfm = c2 / c1^z = f^m |
|
|
|
|
powgm = c2 / c1^z = g^m |
|
|
|
|
*/ |
|
|
|
|
void getPowerf(Ec& powfm, const CipherText& c) const |
|
|
|
|
void getPowerg(Ec& powgm, const CipherText& c) const |
|
|
|
|
{ |
|
|
|
|
Ec c1z; |
|
|
|
|
Ec::mul(c1z, c.c1, z); |
|
|
|
|
Ec::sub(powfm, c.c2, c1z); |
|
|
|
|
Ec::sub(powgm, c.c2, c1z); |
|
|
|
|
} |
|
|
|
|
/*
|
|
|
|
|
set range of message to decode quickly |
|
|
|
|
*/ |
|
|
|
|
void setCache(int rangeMin, int rangeMax) |
|
|
|
|
{ |
|
|
|
|
cache.init(pub.getF(), rangeMin, rangeMax); |
|
|
|
|
cache.init(pub.getG(), rangeMin, rangeMax); |
|
|
|
|
} |
|
|
|
|
/*
|
|
|
|
|
clear cache |
|
|
|
@ -550,9 +540,9 @@ struct ElgamalT { |
|
|
|
|
*/ |
|
|
|
|
int dec(const CipherText& c, bool *b = 0) const |
|
|
|
|
{ |
|
|
|
|
Ec powfm; |
|
|
|
|
getPowerf(powfm, c); |
|
|
|
|
return cache.getExponent(powfm, b); |
|
|
|
|
Ec powgm; |
|
|
|
|
getPowerg(powgm, c); |
|
|
|
|
return cache.getExponent(powgm, b); |
|
|
|
|
} |
|
|
|
|
/*
|
|
|
|
|
check whether c is encrypted zero message |
|
|
|
|