提交 4be88b6f 编辑于 作者: wang's avatar wang
浏览文件

Finish Basic Functionality

上级
#include "BasicSAS.h"
BasicSAS::BasicSAS(const PP& pp):publicParameters(pp), prng{}, sk(k+1, Integer::Zero()), pk(k+1, Integer::Zero()), ma{this->publicParameters.getN()} {}
void
BasicSAS::Keygen()
{
for (int i = 0; i <= this->k; ++i) {
sk[i] = Integer{prng, Integer::One(), this->publicParameters.getN()};
pk[i] = ma.Exponentiate(this->publicParameters.getY(), sk[i]);
}
}
Integer
BasicSAS::sign(const string& msg, unsigned time)
{
assert(time >= 1 && time <= this->publicParameters.getT());
// The message is L bits which will be broken into k chunks each of l bits
vector<Integer> msg_frag{this->dismantleMsg(msg)};
// Now we need to caculate the prime number from public parameters
vector<Integer> es(this->publicParameters.getT() - 1, Integer::Zero());
for (unsigned i = 1, ind = 0; i <= this->publicParameters.getT(); ++i) {
if (i != time) {
es[ind++] = this->publicParameters.hashToPrime(i);
}
}
// Sign the message
Integer sigma{ma.Exponentiate(this->publicParameters.get_g(), this->sk.front())};
Integer eMul{Integer::One()};
for (auto &i: es) {
eMul *= i;
}
for (int i = 1; i <= this->k; ++i) {
sigma = ma.Multiply(sigma, ma.Exponentiate(this->publicParameters.get_g(), sk[i]*msg_frag[i-1]));
}
sigma = ma.Exponentiate(sigma, eMul);
return sigma;
}
bool
BasicSAS::verify(const string& msg, unsigned time, const Integer& signautre)
{
vector<Integer> msg_frag{this->dismantleMsg(msg)};
Integer e_t{this->publicParameters.hashToPrime(time)};
Integer left{ma.Exponentiate(signautre, e_t)};
Integer right{this->pk.front()};
for (unsigned i = 1; i <= this->k; ++i) {
right = ma.Multiply(right, ma.Exponentiate(pk[i], msg_frag[i-1]));
}
return left == right;
}
vector<Integer>
BasicSAS::dismantleMsg(const string& msg)
{ // The message is L bits which will be broken into k chunks each of l bits
unsigned l = this->L / this->k;
SecByteBlock mB{(const CryptoPP::byte*)msg.data(), msg.size()};
Integer m{mB, mB.size()};
// Check the bit size
assert(m.BitCount() <= this->L);
// The following step is to convert message to chunks of Integers
SecByteBlock block{this->L};
vector<SecByteBlock> ms(this->k, SecByteBlock{l});
m.Encode(block, this->L);
for (unsigned i = 0, ind=0; i < this->L; i += l, ++ind) {
ms[ind].Assign(block.BytePtr()+i, l);
}
vector<Integer> msg_frag;
for (auto begin = ms.begin(); begin != ms.end(); ++begin) {
msg_frag.push_back(Integer{*begin, begin->size()});
}
assert(msg_frag.size() == this->k);
return msg_frag;
}
int
main(int argc, char** argv)
{
const unsigned lambda = 256;
const unsigned timePeriod = 10;
Setup pp{lambda, timePeriod};
BasicSAS sas{pp};
cout << "Setup Done." << endl;
cout << pp.getN() << endl;
sas.Keygen();
string msg{"Hello, World."};
string msgFake{"Hello."};
const unsigned time = 2;
const unsigned timeFake = 3;
Integer s{sas.sign(msg, time)};
cout << "Signature: " << s << endl;
cout << "Verify: " << sas.verify(msg, time, s) << endl;
cout << "False Verify: " << sas.verify(msgFake, time, s) << endl;
cout << "False Verify: " << sas.verify(msg, timeFake, s) << endl;
cout << "False Verify: " << sas.verify(msg, time, Integer::One()) << endl;
}
\ No newline at end of file
#include "cryptopp/modarith.h"
#include "Setup.h"
#include <vector>
#include <string>
class Setup;
using PP=Setup;
using std::vector;
using std::string;
using CryptoPP::ModularArithmetic;
class BasicSAS
{
public:
BasicSAS(const PP&);
void Keygen();
Integer sign(const string&, unsigned);
bool verify(const string&, unsigned, const Integer&);
inline vector<Integer>
BasicSAS::publicKey()
{
return this->pk;
}
private:
BasicSAS();
const unsigned k = 4;
const unsigned L = 1024;
AutoSeededRandomPool prng;
PP publicParameters;
vector<Integer> sk;
vector<Integer> pk;
ModularArithmetic ma;
vector<Integer> dismantleMsg(const string&);
};
\ No newline at end of file
#include "Setup.h"
class Setup;
Setup::Setup(const Setup& s):Setup{s.lambda, s.timePeriod} {}
Setup::Setup(unsigned lambda, unsigned timePeriod):lambda{lambda},timePeriod{timePeriod}, rng{}, Ks{this->rng, Integer::Zero(), Integer::Power2(lambda+1).Minus(Integer::One())}, c{this->rng, Integer::Zero(), Integer::Power2(lambda).Minus(Integer::One())}, T{timePeriod} {
unsigned primeBits = lambda / 2;
Integer p, q, subp, subq;
while (true) {
PrimeAndGenerator pgP{this->delta, this->rng, primeBits};
PrimeAndGenerator pgQ{this->delta, this->rng, primeBits};
Integer phi{pgP.SubPrime()*pgQ.SubPrime()*Integer::Power2(2)};
if (phi.BitCount() == lambda) {
p = pgP.Prime();
q = pgQ.Prime();
subp = pgP.SubPrime();
subq = pgQ.SubPrime();
break;
}
}
PrimeAndGenerator pgD{this->delta, this->rng, primeBits, primeBits/2};
this->e_default = pgD.Prime();
this->N = p*q;
assert(N.BitCount() == lambda && N.BitCount() < lambda+1);
Integer a{this->rng, Integer::One(), N-Integer::One()};
while(!this->isGoodNumber(a, p, q)) {
a.Randomize(this->rng, Integer::One(), N-Integer::One());
}
this->g = a.Squared().Modulo(N); // Now we have the generator of the group of quadratic residues
Integer E{Integer::One()};
for (unsigned t = 1; t <= timePeriod; ++t) {
Integer e{hashToPrime(t)};
E = E * e;
primes.push_back(e);
}
E = E.Modulo(Integer{4}*subp*subq);
this->Y = ModularExponentiation(this->g, E, N);
}
bool
Setup::isGoodNumber(const Integer& a, const Integer& q, const Integer& p)
{
Integer aModp{a.Modulo(p)};
if (aModp.IsZero() || aModp.IsUnit() || aModp+Integer::One() == p) {
return false;
}
Integer aModq{a.Modulo(q)};
if (aModq.IsZero() || aModq.IsUnit() || aModq+Integer::One() == q) {
return false;
}
return true;
}
Integer
Setup::PRF(const unsigned& t, const unsigned& i)
{
Integer tI{t}, iI{i};
Integer s{iI + tI*Integer::Power2(iI.BitCount())+this->e_default*Integer::Power2(iI.BitCount()+tI.BitCount())+
this->c*Integer::Power2(iI.BitCount()+tI.BitCount()+this->e_default.BitCount())+this->Ks*Integer::Power2(iI.BitCount()+
tI.BitCount()+this->e_default.BitCount() + this->c.BitCount())};
auto enCodeSize = s.MinEncodedSize();
SecByteBlock seed{enCodeSize};
s.Encode(seed, enCodeSize);
RandomPool prng;
prng.IncorporateEntropy(seed, seed.size());
SecByteBlock rndBytes{this->lambda / 8-1};
prng.GenerateBlock(rndBytes, rndBytes.size());
return Integer{rndBytes, rndBytes.size()};
}
Integer
Setup::hashToPrime(unsigned& t)
{
// The porpose of this step is to ensure the code always get the same probably prime
// Because the IsPrime of CryptoPP is probabilistic test
if (this->primes.size() >= t) {
return this->primes[t-1];
}
auto end = this->lambda*(this->lambda*this->lambda+this->lambda);
for (auto i = 1; i <= end; ++i) {
auto y = this->PRF(t, i);
assert(y.BitCount() <= this->lambda);
Integer e{Integer::Power2(this->lambda)+this->c.Xor(y)};
if (CryptoPP::IsPrime(e)) {
return e;
}
}
return this->e_default;
}
\ No newline at end of file
#include "cryptopp/nbtheory.h"
#include <iostream>
#include "cryptopp/osrng.h"
#include <cassert>
#include <vector>
#include "cryptopp/integer.h"
using CryptoPP::PrimeAndGenerator;
using CryptoPP::AutoSeededRandomPool;
using CryptoPP::Integer;
using CryptoPP::ModularExponentiation;
using CryptoPP::SecByteBlock;
using CryptoPP::RandomPool;
using std::cout;
using std::endl;
using std::vector;
class Setup
{
public:
Setup(unsigned lambda, unsigned timePeriod);
Setup(const Setup&);
inline unsigned getT();
inline Integer getN();
inline Integer get_g();
inline Integer getY();
inline Integer get_e_default();
inline Integer getKs();
inline Integer get_c();
Integer hashToPrime(unsigned&);
private:
unsigned lambda;
unsigned timePeriod;
const int delta = 1;
AutoSeededRandomPool rng;
// The following three form a key for PRF K=(Ks, c, default_prime)
Integer e_default;
Integer Ks;
Integer c;
unsigned T;
Integer Y;
Integer N;
Integer g;
vector<Integer> primes;
/**
* Using to find the generator of the group of quadratic residues
* of N=pq, which has q=2q'+1 and p=2p'+1 with both q' and p' are
* primes.
*
* For achieve this, we need to find a number satisfy gcd(a^2+1, N) = 1
* and gcd(a^2-1, N) = 1. Then the generator g=a^2 (mod N).
*
* Reference: https://math.stackexchange.com/questions/167478/how-to-compute-a-generator-of-this-cyclic-quadratic-residue-group
**/
bool isGoodNumber(const Integer&, const Integer&, const Integer&);
Integer PRF(const unsigned&, const unsigned&);
};
inline unsigned Setup::getT() {return this->T;}
inline Integer Setup::get_e_default() {return this->e_default;}
inline Integer Setup::getN() {return this->N;}
inline Integer Setup::getY() {return this->Y;}
inline Integer Setup::get_g() {return this->g;}
inline Integer Setup::get_c() {return this->c;}
inline Integer Setup::getKs() {return this->Ks;}
\ No newline at end of file
支持 Markdown
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册