mce_qd: code generation

This commit is contained in:
Mirek Kratochvil 2012-09-25 09:27:56 +02:00
parent 8162d6979c
commit b04c1508ee
4 changed files with 187 additions and 44 deletions

View file

@ -49,6 +49,9 @@ public:
void to_poly (polynomial&, gf2m&);
void from_poly (const polynomial&, gf2m&);
void to_poly_cotrace (polynomial&, gf2m&);
void from_poly_cotrace (const polynomial&, gf2m&);
void colex_rank (bvector&);
void colex_unrank (bvector&, uint n, uint k);
};
@ -127,8 +130,12 @@ public:
void compute_inversion (permutation&) const;
void generate_random (uint n, prng&);
void permute (const bvector&, bvector&) const;
void permute (const matrix&, matrix&) const;
template<class V> void permute (const V&a, V&r) const {
r.resize (a.size() );
for (uint i = 0; i < size(); ++i) r[item (i) ] = a[i];
}
void permute_rows (const matrix&, matrix&) const;
};
@ -324,13 +331,27 @@ int generate (pubkey&, privkey&, prng&, uint m, uint t);
* according to Misoczki, Barreto, Compact McEliece Keys from Goppa Codes.
*
* Good security, extremely good speed with extremely reduced key size.
* Recommended for encryption.
* Recommended for encryption, but needs some plaintext conversion -- either
* Fujisaki-Okamoto or Kobara-Imai are known to work good.
*/
namespace mce_qd
{
class privkey
{
public:
std::vector<uint> essence;
gf2m fld; //we fix q=2^fld.m=fld.n, n=q/2
uint T; //the QD's t parameter is 2^T.
uint hperm; //dyadic permutation of H to G
permutation block_perm; //order of blocks
uint block_count; //blocks >= block_count are shortened-out
std::vector<uint> block_perms; //dyadic permutations of blocks
//derivable stuff
std::vector<uint> Hsig; //signature of canonical H matrix
std::vector<uint> support; //computed goppa support
polynomial g; //computed goppa polynomial
int decrypt (const bvector&, bvector&);
int prepare();
@ -340,37 +361,25 @@ public:
uint plain_size() {
return 0; //TODO
}
uint hash_size() {
return 0; //TODO
}
uint signature_size() {
return 0; //TODO
}
};
class pubkey
{
public:
matrix G;
uint t;
uint T;
matrix M;
int encrypt (const bvector&, bvector&, prng&);
uint cipher_size() {
return G.height();
return 0; //TODO
}
uint plain_size() {
return G.width();
}
uint hash_size() {
return cipher_size();
}
uint signature_size() {
return plain_size();
return 0; //TODO
}
};
int generate (pubkey&, privkey&, prng&, uint m, uint t);
int generate (pubkey&, privkey&, prng&, uint m, uint T, uint b);
}
/*

View file

@ -62,6 +62,23 @@ void bvector::from_poly (const polynomial&r, gf2m&fld)
item (i) = (r[i/fld.m] >> (i % fld.m) ) & 1;
}
void bvector::to_poly_cotrace (polynomial&r, gf2m&fld)
{
r.clear();
if (size() % fld.m) return; //impossible
r.resize (size() / fld.m, 0);
for (uint i = 0; i < size(); ++i)
if (item (i) ) r[i%fld.m] |= (1 << (i / fld.m) );
}
void bvector::from_poly_cotrace (const polynomial&r, gf2m&fld)
{
clear();
resize (r.size() *fld.m, 0);
for (uint i = 0; i < size(); ++i)
item (i) = (r[i%fld.m] >> (i / fld.m) ) & 1;
}
/*
* utility colex (un)ranking for niederreiter and workalikes.
* see Ruskey's Combinatorial Generation, algorithm 4.10

View file

@ -6,28 +6,157 @@ using namespace ccr::mce_qd;
#include "decoding.h"
int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng, uint m, uint t)
#include <set>
static uint sample_from_u (gf2m&fld, prng&rng, std::set<uint>&used)
{
uint x;
for (;;) {
x = rng.random (fld.n);
if (used.count (x) ) continue;
used.insert (x);
return x;
}
}
static uint choose_random (uint limit, prng&rng, std::set<uint>used)
{
if (used.size() >= limit - 1) return 0; //die
for (;;) {
uint a = 1 + rng.random (limit - 1);
if (used.count (a) ) continue;
used.insert (a);
return a;
}
}
int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng,
uint m, uint T, uint block_count)
{
priv.fld.create (m);
priv.T = T;
uint t = 1 << T;
//convenience
gf2m&fld = priv.fld;
std::vector<uint>&Hsig = priv.Hsig;
std::vector<uint>&essence = priv.essence;
std::vector<uint>&support = priv.support;
polynomial&g = priv.g;
//prepare for data
Hsig.resize (fld.n / 2);
support.resize (fld.n / 2);
essence.resize (m);
//note that q=2^m, algo. n=q/2, log n = m-1
//retry generating until goppa code is produced.
for (;;) {
std::set<uint> used;
used.clear();
//first off, compute the H signature
Hsig[0] = choose_random (fld.n, rng, used);
essence[m-1] = fld.inv (Hsig[0]);
//essence[m-1] is now used as precomputed 1/h_0
for (uint s = 0; s < m - 1; ++s) {
uint i = 1 << s; //i = 2^s
Hsig[i] = choose_random (fld.n, rng, used);
essence[s] = fld.add (essence[m-1], fld.inv (Hsig[i]) );
used.insert (fld.inv (essence[s]) );
for (uint j = 1; j < i; ++j) {
Hsig[i+j] = fld.inv (
fld.add (
fld.inv (Hsig[i]),
fld.add (
fld.inv (Hsig[j]),
essence[m-1]
) ) );
used.insert (Hsig[i+j]);
used.insert (fld.inv (
fld.add (
fld.inv (Hsig[i+j]),
essence[m-1]) ) );
}
}
//from now on, we fix 'omega' from the paper to zero.
//compute the support, retry if it has two equal elements.
used.clear();
bool consistent = true;
for (uint i = 0; i < fld.n / 2; ++i) {
support[i] = fld.add (
fld.inv (Hsig[i]),
essence[m-1]);
if (used.count (support[i]) ) {
consistent = false;
break;
}
used.insert (support[i]);
}
if (!consistent) continue; //retry
//assemble goppa polynomial.
g.clear();
g.resize (1, 1); //g(x)=1 so we can multiply it
polynomial tmp;
tmp.resize (2, 1); //tmp(x)=x-1
for (uint i = 0; i < t; ++i) {
//tmp(x)=x-z=x-(1/h_i)
tmp[0] = fld.inv (Hsig[i]);
g.mult (tmp, fld);
}
//now the blocks.
uint block_size = 1 << T,
h_block_count = (fld.n / 2) / block_size;
//assemble blocks to bl
std::vector<std::vector<uint> > bl, blp;
bl.resize (block_size);
for (uint i = 0; i < h_block_count; ++i)
bl[i] = std::vector<uint>
(Hsig.begin() + i * block_size,
Hsig.begin() + (i + 1) * block_size);
//permute them
permutation bp;
bp.generate_random (h_block_count, rng);
bp.permute (bl, blp);
//discard blocks
blp.resize (block_count);
//TODO permute individual blocks
//TODO co-trace to binary H^
//TODO systematic H
//TODO systematic G
//TODO signature of G
return 0;
}
}
int privkey::prepare()
{
return 0;
}
int pubkey::encrypt (const bvector& in, bvector&out, prng&rng)
{
uint s = cipher_size();
if (t > s) return 1;
if (in.size() != plain_size() ) return 2;
return 0;
}
int privkey::decrypt (const bvector&in, bvector&out)
{
if (in.size() != cipher_size() ) return 2;
return 0;
}
int privkey::prepare ()
{
return 0;
}

View file

@ -27,18 +27,6 @@ void permutation::generate_random (uint size, prng&rng)
}
}
void permutation::permute (const bvector&a, bvector&r) const
{
r.resize (a.size() );
for (uint i = 0; i < size(); ++i) r[item (i) ] = a[i];
}
void permutation::permute (const matrix&a, matrix&r) const
{
r.resize (a.size() );
for (uint i = 0; i < size(); ++i) r[item (i) ] = a[i];
}
void permutation::permute_rows (const matrix&a, matrix&r) const
{
r.resize (a.size() );