mce_qd: decoding work, along with some fixes

- vector functions
- decoding function simplification
This commit is contained in:
Mirek Kratochvil 2012-10-22 12:10:26 +02:00
parent 5b69b38e09
commit 9620632e84
12 changed files with 169 additions and 83 deletions

View file

@ -43,17 +43,18 @@ public:
void add (const bvector&); void add (const bvector&);
void add_range (const bvector&, uint, uint); void add_range (const bvector&, uint, uint);
void add_offset (const bvector&, uint); void add_offset (const bvector&, uint);
void get_block (uint, uint, bvector&) const;
bool operator* (const bvector&); //dot product bool operator* (const bvector&); //dot product
bool zero() const; bool zero() const;
void to_poly (polynomial&, gf2m&); void to_poly (polynomial&, gf2m&) const;
void from_poly (const polynomial&, gf2m&); void from_poly (const polynomial&, gf2m&);
void to_poly_cotrace (polynomial&, gf2m&); void to_poly_cotrace (polynomial&, gf2m&) const;
void from_poly_cotrace (const polynomial&, gf2m&); void from_poly_cotrace (const polynomial&, gf2m&);
void colex_rank (bvector&); void colex_rank (bvector&) const;
void colex_unrank (bvector&, uint n, uint k); void colex_unrank (bvector&, uint n, uint k) const;
}; };
/* /*
@ -380,6 +381,7 @@ public:
gf2m fld; //we fix q=2^fld.m=fld.n, n=q/2 gf2m fld; //we fix q=2^fld.m=fld.n, n=q/2
uint T; //the QD's t parameter is 2^T. uint T; //the QD's t parameter is 2^T.
permutation block_perm; //order of blocks permutation block_perm; //order of blocks
//TODO this is derivable from hperm.
uint block_count; //blocks >= block_count are shortened-out uint block_count; //blocks >= block_count are shortened-out
permutation hperm; //block permutation of H block used to get G permutation hperm; //block permutation of H block used to get G
std::vector<uint> block_perms; //dyadic permutations of blocks std::vector<uint> block_perms; //dyadic permutations of blocks
@ -390,6 +392,8 @@ public:
polynomial g; //computed goppa polynomial polynomial g; //computed goppa polynomial
std::vector<polynomial> sqInv; std::vector<polynomial> sqInv;
std::vector<bvector> Hc; //signature lines of pre-permuted check matrix
std::vector<uint> support_pos; //pre-permuted positions of support rows
int decrypt (const bvector&, bvector&); int decrypt (const bvector&, bvector&);
int prepare(); int prepare();
@ -427,9 +431,9 @@ int generate (pubkey&, privkey&, prng&, uint m, uint T, uint b);
* Similar to Hamdi's Chained BCH Codes, but with improvement. * Similar to Hamdi's Chained BCH Codes, but with improvement.
* *
* This is experimental, unverified, probably insecure, but practical scheme * This is experimental, unverified, probably insecure, but practical scheme
* that achieves good speed, probability and key size for full decoding that is * that achieves good speed, probability and non-exponential key size for full
* needed to produce signatures. Technique is described in documentation, with * decoding that is needed to produce signatures. Technique is described in
* some (probably sufficient) notes in source code. * documentation, with some (probably sufficient) notes in source code.
* *
* Note that encryption using this scheme is impossible, as there is only an * Note that encryption using this scheme is impossible, as there is only an
* extremely tiny probability of successful decoding. * extremely tiny probability of successful decoding.

View file

@ -30,6 +30,13 @@ void bvector::add_offset (const bvector&a, uint offset)
item (offset + i) = item (offset + i) ^ a[i]; item (offset + i) = item (offset + i) ^ a[i];
} }
void bvector::get_block (uint offset, uint bs, bvector&out) const
{
if (offset + bs > size() ) return;
out.resize (bs);
for (uint i = 0; i < bs; ++i) out[i] = item (offset + i);
}
bool bvector::operator* (const bvector&a) bool bvector::operator* (const bvector&a)
{ {
bool r = 0; bool r = 0;
@ -45,13 +52,13 @@ bool bvector::zero() const
return true; return true;
} }
void bvector::to_poly (polynomial&r, gf2m&fld) void bvector::to_poly (polynomial&r, gf2m&fld) const
{ {
r.clear(); r.clear();
if (size() % fld.m) return; //impossible if (size() % fld.m) return; //impossible
r.resize (size() / fld.m, 0); r.resize (size() / fld.m, 0);
for (uint i = 0; i < size(); ++i) for (uint i = 0; i < size(); ++i)
if (item (i) ) r[i/fld.m] |= (1 << (i % fld.m) ); if (item (i) ) r[i / fld.m] |= (1 << (i % fld.m) );
} }
void bvector::from_poly (const polynomial&r, gf2m&fld) void bvector::from_poly (const polynomial&r, gf2m&fld)
@ -59,17 +66,17 @@ void bvector::from_poly (const polynomial&r, gf2m&fld)
clear(); clear();
resize (r.size() *fld.m, 0); resize (r.size() *fld.m, 0);
for (uint i = 0; i < size(); ++i) for (uint i = 0; i < size(); ++i)
item (i) = (r[i/fld.m] >> (i % fld.m) ) & 1; item (i) = (r[i / fld.m] >> (i % fld.m) ) & 1;
} }
void bvector::to_poly_cotrace (polynomial&r, gf2m&fld) void bvector::to_poly_cotrace (polynomial&r, gf2m&fld) const
{ {
r.clear(); r.clear();
if (size() % fld.m) return; //impossible if (size() % fld.m) return; //impossible
uint s = size() / fld.m; uint s = size() / fld.m;
r.resize (s, 0); r.resize (s, 0);
for (uint i = 0; i < size(); ++i) for (uint i = 0; i < size(); ++i)
if (item (i) ) r[i%s] |= (1 << (i / s) ); if (item (i) ) r[i % s] |= (1 << (i / s) );
} }
void bvector::from_poly_cotrace (const polynomial&r, gf2m&fld) void bvector::from_poly_cotrace (const polynomial&r, gf2m&fld)
@ -78,7 +85,7 @@ void bvector::from_poly_cotrace (const polynomial&r, gf2m&fld)
uint s = r.size(); uint s = r.size();
resize (s * fld.m, 0); resize (s * fld.m, 0);
for (uint i = 0; i < size(); ++i) for (uint i = 0; i < size(); ++i)
item (i) = (r[i%s] >> (i / s) ) & 1; item (i) = (r[i % s] >> (i / s) ) & 1;
} }
/* /*
@ -117,7 +124,7 @@ static void combination_number (uint n, uint k, mpz_t& r)
mpz_clear (t); mpz_clear (t);
} }
static void bvector_to_mpz (bvector&v, mpz_t&r) static void bvector_to_mpz (const bvector&v, mpz_t&r)
{ {
mpz_set_ui (r, 0); mpz_set_ui (r, 0);
mpz_realloc2 (r, v.size() ); mpz_realloc2 (r, v.size() );
@ -134,7 +141,7 @@ static void mpz_to_bvector (mpz_t&x, bvector&r)
r[i] = mpz_tstbit (x, i); r[i] = mpz_tstbit (x, i);
} }
void bvector::colex_rank (bvector&r) void bvector::colex_rank (bvector&r) const
{ {
mpz_t res, t, t2; mpz_t res, t, t2;
mpz_init_set_ui (res, 0); mpz_init_set_ui (res, 0);
@ -158,8 +165,7 @@ void bvector::colex_rank (bvector&r)
mpz_clear (res); mpz_clear (res);
} }
#include <stdio.h> void bvector::colex_unrank (bvector&res, uint n, uint k) const
void bvector::colex_unrank (bvector&res, uint n, uint k)
{ {
mpz_t r, t, t2; mpz_t r, t, t2;
mpz_init (r); mpz_init (r);
@ -185,7 +191,7 @@ void bvector::colex_unrank (bvector&res, uint n, uint k)
mpz_swap (t2, r); mpz_swap (t2, r);
mpz_sub (r, t2, t); mpz_sub (r, t2, t);
if (p > n) continue; //overflow protection if (p > n) continue; //overflow protection
res[p-1] = 1; res[p - 1] = 1;
} }
mpz_clear (r); mpz_clear (r);

View file

@ -1,7 +1,7 @@
#include "decoding.h" #include "decoding.h"
void compute_error_locator (bvector&syndrome, gf2m&fld, polynomial& goppa, void compute_error_locator (polynomial&syndrome, gf2m&fld, polynomial& goppa,
std::vector<polynomial>& sqInv, polynomial&out) std::vector<polynomial>& sqInv, polynomial&out)
{ {
if (syndrome.zero() ) { if (syndrome.zero() ) {
@ -11,9 +11,7 @@ void compute_error_locator (bvector&syndrome, gf2m&fld, polynomial& goppa,
return; return;
} }
polynomial v; polynomial v = syndrome;
syndrome.to_poly (v, fld);
v.inv (goppa, fld); // v=Synd^-1 mod goppa v.inv (goppa, fld); // v=Synd^-1 mod goppa
if (v.size() < 2) v.resize (2, 0); if (v.size() < 2) v.resize (2, 0);
@ -90,7 +88,7 @@ bool evaluate_error_locator_trace (polynomial&sigma, bvector&ev, gf2m&fld)
trace[0] = trace_aux[0]; //trace[0] = x trace[0] = trace_aux[0]; //trace[0] = x
for (uint i = 1; i < fld.m; ++i) { for (uint i = 1; i < fld.m; ++i) {
trace_aux[i] = trace_aux[i-1]; trace_aux[i] = trace_aux[i - 1];
trace_aux[i].square (fld); trace_aux[i].square (fld);
trace_aux[i].mod (sigma, fld); trace_aux[i].mod (sigma, fld);
trace[0].add (trace_aux[i], fld); trace[0].add (trace_aux[i], fld);

View file

@ -6,7 +6,7 @@
using namespace ccr; using namespace ccr;
void compute_error_locator (bvector&syndrome, void compute_error_locator (polynomial&syndrome,
gf2m&fld, gf2m&fld,
polynomial&goppa, polynomial&goppa,
std::vector<polynomial>& sqInv, std::vector<polynomial>& sqInv,

View file

@ -21,9 +21,9 @@ static void fwht (vector<int> x, vector<int>&r)
x.swap (r); x.swap (r);
for (uint i = 0; i < s; ++i) { for (uint i = 0; i < s; ++i) {
if ( (i / bs) & 1) if ( (i / bs) & 1)
r[i] = x[i-bs] - x[i]; r[i] = x[i - bs] - x[i];
else else
r[i] = x[i] + x[i+bs]; r[i] = x[i] + x[i + bs];
} }
bs >>= 1; bs >>= 1;
} }

View file

@ -102,7 +102,7 @@ bool gf2m::create (uint M)
log.resize (n, 0); log.resize (n, 0);
antilog.resize (n, 0); antilog.resize (n, 0);
log[0] = n - 1; log[0] = n - 1;
antilog[n-1] = 0; antilog[n - 1] = 0;
uint i, xi = 1; //x^0 uint i, xi = 1; //x^0
for (i = 0; i < n - 1; ++i) { for (i = 0; i < n - 1; ++i) {
@ -165,7 +165,7 @@ uint gf2m::exp (int k)
uint gf2m::inv (uint a) uint gf2m::inv (uint a)
{ {
if (!a) return 0; if (!a) return 0;
return antilog[ (n-1-log[a]) % (n - 1) ]; return antilog[ (n - 1 - log[a]) % (n - 1) ];
} }
uint gf2m::sq_root (uint a) uint gf2m::sq_root (uint a)

View file

@ -98,13 +98,13 @@ bool matrix::compute_inversion (matrix&res, bool upper_tri, bool lower_tri)
if (upper_tri) { if (upper_tri) {
for (i = s; i > 0; --i) for (i = s; i > 0; --i)
for (j = i - 1; j > 0; --j) for (j = i - 1; j > 0; --j)
if (m[j-1][i-1]) if (m[j - 1][i - 1])
r[j-1].add_range (r[i-1], i - 1, s); r[j - 1].add_range (r[i - 1], i - 1, s);
} else { } else {
for (i = s; i > 0; --i) for (i = s; i > 0; --i)
for (j = i - 1; j > 0; --j) for (j = i - 1; j > 0; --j)
if (m[j-1][i-1]) if (m[j - 1][i - 1])
r[j-1].add (r[i-1]); r[j - 1].add (r[i - 1]);
} }
} }
@ -214,7 +214,7 @@ void matrix::extend_left_compact (matrix&r)
r[i][i] = 1; r[i][i] = 1;
} }
for (i = 0; i < w; ++i) { for (i = 0; i < w; ++i) {
r[h+i] = item (i); r[h + i] = item (i);
} }
} }
@ -233,6 +233,7 @@ bool matrix::create_goppa_generator (matrix&g, const permutation&p)
t.get_right_square (sinv); t.get_right_square (sinv);
if (!sinv.compute_inversion (s) ) return false; //meant to be retried. if (!sinv.compute_inversion (s) ) return false; //meant to be retried.
//TODO why multiply and THEN strip?
s.mult (t); s.mult (t);
s.strip_right_square (t); //matrix pingpong for the result s.strip_right_square (t); //matrix pingpong for the result
t.compute_transpose (s); t.compute_transpose (s);

View file

@ -78,8 +78,9 @@ int privkey::decrypt (const bvector&in, bvector&out)
h.mult_vec_right (canonical, syndrome); h.mult_vec_right (canonical, syndrome);
//decode //decode
polynomial loc; polynomial synd, loc;
compute_error_locator (syndrome, fld, g, sqInv, loc); syndrome.to_poly (synd, fld);
compute_error_locator (synd, fld, g, sqInv, loc);
bvector ev; bvector ev;
if (!evaluate_error_locator_trace (loc, ev, fld) ) if (!evaluate_error_locator_trace (loc, ev, fld) )
@ -113,7 +114,7 @@ int privkey::sign (const bvector&in, bvector&out, uint delta, uint attempts, prn
bvector p, e, synd, synd_orig, e2; bvector p, e, synd, synd_orig, e2;
std::vector<uint> epos; std::vector<uint> epos;
permutation hpermInv; permutation hpermInv;
polynomial loc; polynomial loc, Synd;
s = hash_size(); s = hash_size();
@ -142,7 +143,8 @@ int privkey::sign (const bvector&in, bvector&out, uint delta, uint attempts, prn
e[epos[i]] = 1; e[epos[i]] = 1;
} }
compute_error_locator (synd, fld, g, sqInv, loc); synd.to_poly (Synd, fld);
compute_error_locator (Synd, fld, g, sqInv, loc);
if (evaluate_error_locator_trace (loc, e2, fld) ) { if (evaluate_error_locator_trace (loc, e2, fld) ) {

View file

@ -74,7 +74,7 @@ int privkey::sign (const bvector&in, bvector&out,
bvector e, e2, synd, synd_orig, cw, cwc, plain, overlap; bvector e, e2, synd, synd_orig, cw, cwc, plain, overlap;
std::vector<uint> epos; std::vector<uint> epos;
permutation hpermInv; permutation hpermInv;
polynomial loc; polynomial loc, Synd;
uint i, t; uint i, t;
uint mt = fld.m * codes[0].g.degree(), uint mt = fld.m * codes[0].g.degree(),
@ -123,7 +123,8 @@ int privkey::sign (const bvector&in, bvector&out,
e[epos[i]] = 1; e[epos[i]] = 1;
} }
compute_error_locator (synd, fld, synd.to_poly (Synd, fld);
compute_error_locator (Synd, fld,
codes[ci].g, codes[ci].g,
codes[ci].sqInv, loc); codes[ci].sqInv, loc);

View file

@ -5,6 +5,7 @@ using namespace ccr;
using namespace ccr::mce_qd; using namespace ccr::mce_qd;
#include "decoding.h" #include "decoding.h"
#include "fwht.h"
#include <set> #include <set>
@ -37,6 +38,7 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng,
priv.T = T; priv.T = T;
uint t = 1 << T; uint t = 1 << T;
std::cout << "generate" << std::endl;
//convenience //convenience
gf2m&fld = priv.fld; gf2m&fld = priv.fld;
std::vector<uint>&Hsig = priv.Hsig; std::vector<uint>&Hsig = priv.Hsig;
@ -56,37 +58,39 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng,
std::set<uint> used; std::set<uint> used;
used.clear(); used.clear();
std::cout << "attempt..." << std::endl;
//first off, compute the H signature //first off, compute the H signature
Hsig[0] = choose_random (fld.n, rng, used); Hsig[0] = choose_random (fld.n, rng, used);
essence[m-1] = fld.inv (Hsig[0]); essence[m - 1] = fld.inv (Hsig[0]);
//essence[m-1] is now used as precomputed 1/h_0 //essence[m-1] is now used as precomputed 1/h_0
for (uint s = 0; s < m - 1; ++s) { for (uint s = 0; s < m - 1; ++s) {
uint i = 1 << s; //i = 2^s uint i = 1 << s; //i = 2^s
Hsig[i] = choose_random (fld.n, rng, used); Hsig[i] = choose_random (fld.n, rng, used);
essence[s] = fld.add (essence[m-1], fld.inv (Hsig[i]) ); essence[s] = fld.add (essence[m - 1], fld.inv (Hsig[i]) );
used.insert (fld.inv (essence[s]) ); used.insert (fld.inv (essence[s]) );
for (uint j = 1; j < i; ++j) { for (uint j = 1; j < i; ++j) {
Hsig[i+j] = fld.inv Hsig[i + j] = fld.inv
(fld.add (fld.add
(fld.inv (Hsig[i]), (fld.inv (Hsig[i]),
fld.add ( fld.add (
fld.inv (Hsig[j]), fld.inv (Hsig[j]),
essence[m-1] essence[m - 1]
) ) ); ) ) );
used.insert (Hsig[i+j]); used.insert (Hsig[i + j]);
used.insert (fld.inv used.insert (fld.inv
(fld.add (fld.add
(fld.inv (Hsig[i+j]), (fld.inv (Hsig[i + j]),
essence[m-1]) ) ); essence[m - 1]) ) );
} }
} }
//from now on, we fix 'omega' from the paper to zero. //from now on, we fix 'omega' from the paper to zero.
std::cout << "goppa..." << std::endl;
//assemble goppa polynomial. //assemble goppa polynomial.
g.clear(); g.clear();
g.resize (1, 1); //g(x)=1 so we can multiply it g.resize (1, 1); //g(x)=1 so we can multiply it
@ -96,15 +100,19 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng,
//tmp(x)=x-z=x-(1/h_i) //tmp(x)=x-z=x-(1/h_i)
tmp[0] = fld.inv (Hsig[i]); tmp[0] = fld.inv (Hsig[i]);
g.mult (tmp, fld); g.mult (tmp, fld);
std::cout << "computing g... " << g;
} }
std::cout << "Goppa poly " << g;
std::cout << "support..." << std::endl;
//compute the support, retry if it has two equal elements. //compute the support, retry if it has two equal elements.
used.clear(); used.clear();
bool consistent = true; bool consistent = true;
for (uint i = 0; i < fld.n / 2; ++i) { for (uint i = 0; i < fld.n / 2; ++i) {
support[i] = fld.add ( support[i] = fld.add (
fld.inv (Hsig[i]), fld.inv (Hsig[i]),
essence[m-1]); essence[m - 1]);
if (used.count (support[i]) ) { if (used.count (support[i]) ) {
consistent = false; consistent = false;
@ -112,15 +120,18 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng,
} }
if (g.eval (support[i], fld) == 0) { if (g.eval (support[i], fld) == 0) {
std::cout << "support zero!" << std::endl;
consistent = false; consistent = false;
break; break;
} }
std::cout << "support at " << i << ": " << support[i] << std::endl;
used.insert (support[i]); used.insert (support[i]);
} }
if (!consistent) continue; //retry if (!consistent) continue; //retry
std::cout << "blocks..." << std::endl;
//now the blocks. //now the blocks.
uint block_size = 1 << T, uint block_size = 1 << T,
h_block_count = (fld.n / 2) / block_size; h_block_count = (fld.n / 2) / block_size;
@ -135,13 +146,16 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng,
(Hsig.begin() + i * block_size, (Hsig.begin() + i * block_size,
Hsig.begin() + (i + 1) * block_size); Hsig.begin() + (i + 1) * block_size);
std::cout << "permuting blocks..." << std::endl;
//permute them //permute them
priv.block_perm.generate_random (h_block_count, rng); priv.block_perm.generate_random (h_block_count, rng);
priv.block_perm.permute (bl, blp); priv.block_perm.permute (bl, blp);
std::cout << "discarding blocks..." << std::endl;
//discard blocks //discard blocks
blp.resize (block_count); blp.resize (block_count);
std::cout << "permuting dyadic blocks..." << std::endl;
//permute individual blocks //permute individual blocks
priv.block_perms.resize (block_count); priv.block_perms.resize (block_count);
bl.resize (blp.size() ); bl.resize (blp.size() );
@ -158,14 +172,17 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng,
matrix r, ri, l; matrix r, ri, l;
for (;;) { //try several permutations to construct G
uint attempts = 0;
for (attempts = 0; attempts < block_count; ++attempts) {
std::cout << "generating G..." << std::endl;
priv.hperm.generate_random (block_count, rng); priv.hperm.generate_random (block_count, rng);
for (uint i = 0; i < block_count; ++i) for (uint i = 0; i < block_count; ++i)
for (uint j = 0; j < block_size; ++j) { for (uint j = 0; j < block_size; ++j) {
permutation::permute_dyadic permutation::permute_dyadic
(j, bl[priv.hperm[i]], col); (j, bl[priv.hperm[i]], col);
Hc[i*block_size + j].from_poly_cotrace Hc[i * block_size + j].from_poly_cotrace
(col, fld); (col, fld);
} }
@ -177,22 +194,29 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng,
*/ */
Hc.get_right_square (r); Hc.get_right_square (r);
std::cout << "RIGHT SQUARE " << r;
if (!r.compute_inversion (ri) ) if (!r.compute_inversion (ri) )
continue; //retry with other hperm continue; //retry with other code
std::cout << "Rinv " << ri;
Hc.strip_right_square (l); Hc.strip_right_square (l);
ri.mult (l); ri.mult (l);
std::cout << "l " << ri;
break; break;
} }
if (attempts == block_count) //generating G failed, retry all
continue;
/* /*
* Redundancy-checking part of G is now (transposed) in ri. * Redundancy-checking part of G is now (transposed) in ri.
* Get QD signatures by getting every t'th row (transposed). * Get QD signatures by getting every t'th row (transposed).
*/ */
std::cout << "pubkey..." << std::endl;
pub.T = T; pub.T = T;
pub.qd_sigs.resize (ri.width() / t); pub.qd_sigs.resize (ri.width() / t);
for (uint i = 0; i < ri.width(); i += t) for (uint i = 0; i < ri.width(); i += t)
pub.qd_sigs[i/t] = ri[i]; pub.qd_sigs[i / t] = ri[i];
return 0; return 0;
} }
@ -200,23 +224,23 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng,
int privkey::prepare() int privkey::prepare()
{ {
std::cout << "prepare" << std::endl;
//compute H signature from essence //compute H signature from essence
Hsig.resize (fld.n / 2); Hsig.resize (fld.n / 2);
Hsig[0] = fld.inv (essence[fld.m-1]); Hsig[0] = fld.inv (essence[fld.m - 1]);
for (uint s = 0; s < fld.m - 1; ++s) { for (uint s = 0; s < fld.m - 1; ++s) {
uint i = 1 << s; //i = 2^s uint i = 1 << s; //i = 2^s
//TODO verify this Hsig[i] = fld.inv (fld.add (essence[s], essence[fld.m - 1]) );
Hsig[i] = fld.inv (fld.add (essence[s], essence[fld.m-1]) );
for (uint j = 1; j < i; ++j) for (uint j = 1; j < i; ++j)
Hsig[i+j] = fld.inv Hsig[i + j] = fld.inv
(fld.add (fld.add
(fld.inv (Hsig[i]), (fld.inv (Hsig[i]),
fld.add ( fld.add (
fld.inv (Hsig[j]), fld.inv (Hsig[j]),
essence[fld.m-1] essence[fld.m - 1]
) ) ); ) ) );
} }
//compute the support //compute the support
@ -224,10 +248,15 @@ int privkey::prepare()
for (uint i = 0; i < fld.n / 2; ++i) { for (uint i = 0; i < fld.n / 2; ++i) {
support[i] = fld.add support[i] = fld.add
(fld.inv (Hsig[i]), (fld.inv (Hsig[i]),
essence[fld.m-1]); essence[fld.m - 1]);
} }
//TODO prepare permuted Hsig (that can be applied to the ciphertext)
//TODO prepare function that converts a support zero to ciphertext
//position
//goppa polynomial //goppa polynomial
g.clear(); g.clear();
g.resize (1, 1); g.resize (1, 1);
@ -245,12 +274,11 @@ int privkey::prepare()
return 0; return 0;
} }
#include "fwht.h"
int pubkey::encrypt (const bvector& in, bvector&out, prng&rng) int pubkey::encrypt (const bvector& in, bvector&out, prng&rng)
{ {
uint t = 1 << T; uint t = 1 << T;
bvector p, g, r, cksum; bvector p, g, r, cksum;
uint i, j, k;
/* /*
* shortened checksum pair of G is computed blockwise accordingly to * shortened checksum pair of G is computed blockwise accordingly to
@ -268,17 +296,23 @@ int pubkey::encrypt (const bvector& in, bvector&out, prng&rng)
g.resize (t); g.resize (t);
r.resize (t); r.resize (t);
for (uint i = 0; i < qd_sigs.size(); ++i) { for (i = 0; i < qd_sigs.size(); ++i) {
//plaintext block std::cout << "Signature line " << i << ": " << qd_sigs[i];
for (uint k = 0; k < t; ++k) p[k] = in[k+i*t]; }
for (uint j = 0; j < blocks; ++j) { for (i = 0; i < qd_sigs.size(); ++i) {
//plaintext block
in.get_block (i * t, t, p);
for (j = 0; j < blocks; ++j) {
//checksum block //checksum block
for (uint k = 0; k < t; ++k) g[k] = qd_sigs[i][k+j*t]; qd_sigs[i].get_block (j * t, t, g);
//block result //block result
fwht_dyadic_multiply (p, g, r); fwht_dyadic_multiply (p, g, r);
//std::cout << "DYADIC MULTIPLY: " << p << g << r << "---" << std::endl;
cksum.add_offset (r, t * j); cksum.add_offset (r, t * j);
//std::cout << "CKSUM NOW: " << cksum;
} }
} }
@ -296,6 +330,7 @@ int pubkey::encrypt (const bvector& in, bvector&out, prng&rng)
//compute ciphertext //compute ciphertext
out = in; out = in;
out.insert (out.end(), cksum.begin(), cksum.end() ); out.insert (out.end(), cksum.begin(), cksum.end() );
std::cout << "without errors: " << out;
out.add (e); out.add (e);
return 0; return 0;
@ -303,7 +338,45 @@ int pubkey::encrypt (const bvector& in, bvector&out, prng&rng)
int privkey::decrypt (const bvector&in, bvector&out) int privkey::decrypt (const bvector&in, bvector&out)
{ {
//TODO decoding if (in.size() != cipher_size() ) return 2;
//multiply line-by-line block-by-block by H
uint block_size = 1 << T;
bvector synd_vec;
bvector hp, cp, res;
uint i, j, k;
synd_vec.resize (block_size * fld.m);
hp.resize (block_size);
cp.resize (block_size);
res.resize (block_size);
for (i = 0; i < block_count; ++i) {
in.get_block (i * block_size, block_size, cp);
for (j = 0; j < fld.m; ++j) {
Hc[j].get_block (i * block_size, block_size, hp);
fwht_dyadic_multiply (hp, cp, res);
synd_vec.add_offset (res, j * block_size);
}
}
//decoding
polynomial synd, loc;
synd_vec.to_poly_cotrace (synd, fld);
compute_error_locator (synd, fld, g, sqInv, loc);
bvector ev;
if (!evaluate_error_locator_trace (loc, ev, fld) )
return 1; //couldn't decode
//TODO evaluator should return error positions, not bvector. fix it everywhere!
out = in;
//flip error positions of out.
for (i = 0; i < ev.size(); ++i) if (ev[i]) {
if (support_pos[i] == -1) return 1; //couldn't decode TODO is it true?
out[i] = !out[i];
}
return 0; return 0;
} }

View file

@ -57,8 +57,9 @@ int privkey::decrypt (const bvector&in, bvector&out)
bvector unsc; //unscrambled bvector unsc; //unscrambled
Sinv.mult_vec_right (in, unsc); Sinv.mult_vec_right (in, unsc);
polynomial loc; polynomial loc, synd;
compute_error_locator (unsc, fld, g, sqInv, loc); unsc.to_poly (synd, fld);
compute_error_locator (synd, fld, g, sqInv, loc);
bvector ev; bvector ev;
if (!evaluate_error_locator_trace (loc, ev, fld) ) if (!evaluate_error_locator_trace (loc, ev, fld) )
@ -76,8 +77,7 @@ int privkey::sign (const bvector&in, bvector&out, uint delta, uint attempts, prn
uint i, s, t; uint i, s, t;
bvector synd_unsc, synd, e; bvector synd_unsc, synd, e;
polynomial loc, Synd;
polynomial loc;
s = hash_size(); s = hash_size();
if (in.size() != s) return 2; if (in.size() != s) return 2;
@ -92,7 +92,8 @@ int privkey::sign (const bvector&in, bvector&out, uint delta, uint attempts, prn
Sinv.mult_vec_right (synd, synd_unsc); Sinv.mult_vec_right (synd, synd_unsc);
compute_error_locator (synd_unsc, fld, g, sqInv, loc); synd_unsc.to_poly (Synd, fld);
compute_error_locator (Synd, fld, g, sqInv, loc);
if (evaluate_error_locator_trace (loc, e, fld) ) { if (evaluate_error_locator_trace (loc, e, fld) ) {

View file

@ -58,8 +58,8 @@ void polynomial::mod (const polynomial&f, gf2m&fld)
for (int i = 0; i <= df; ++i) for (int i = 0; i <= df; ++i)
item (i + d - df) item (i + d - df)
= fld.add (item (i + d - df), = fld.add (item (i + d - df),
fld.mult (t, f[i]) ); fld.mult (t, f[i]) );
} }
strip(); strip();
} }
@ -326,7 +326,7 @@ void polynomial::divmod (polynomial&d, polynomial&res, polynomial&rem, gf2m&fld)
if (res.size() < rp + 1) res.resize (rp + 1, 0); if (res.size() < rp + 1) res.resize (rp + 1, 0);
res[rp] = fld.mult (headInv, rem[t]); res[rp] = fld.mult (headInv, rem[t]);
for (uint i = 0; i <= degd; ++i) for (uint i = 0; i <= degd; ++i)
rem[i+rp] = fld.add (rem[i+rp], fld.mult (res[rp], d[i]) ); rem[i + rp] = fld.add (rem[i + rp], fld.mult (res[rp], d[i]) );
} }
rem.strip(); rem.strip();
} }