From c9df69a83fe73620d60b46918e8e327d1fd53e88 Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Fri, 1 Jun 2012 23:49:07 +0200 Subject: [PATCH] niederreiter + various related fixes --- include/codecrypt.h | 47 ++++++++++++++++++++++--- lib/decoding.cpp | 5 +++ lib/mce.cpp | 38 +++++++++++--------- lib/nd.cpp | 85 +++++++++++++++++++++++++++++++++++++++------ src/main.cpp | 8 +++-- 5 files changed, 149 insertions(+), 34 deletions(-) diff --git a/include/codecrypt.h b/include/codecrypt.h index acf78fd..3990c39 100644 --- a/include/codecrypt.h +++ b/include/codecrypt.h @@ -4,7 +4,7 @@ #include -//STL wraparound, because writing (*this)[i] everywhere is clumsy +//little STL helper, because writing (*this)[i] everywhere is clumsy #define _ccr_declare_vector_item \ inline reference item(size_type n) \ { return (*this)[n]; }; \ @@ -233,10 +233,33 @@ namespace nd class privkey { public: - // TODO + matrix Sinv; + permutation Pinv; + polynomial g; + gf2m fld; + + //derivable. + std::vector sqInv; int decrypt (const bvector&, bvector&); int sign (const bvector&, bvector&, uint, uint, prng&); + int prepare(); + + uint cipher_size() { + return Pinv.size(); + } + uint plain_size() { + return Sinv.width(); + } + uint plain_weight() { + return g.degree(); + } + uint hash_size() { + return cipher_size(); + } + uint signature_size() { + return plain_size(); + } }; class pubkey @@ -245,11 +268,27 @@ public: matrix H; uint t; - int encrypt (const bvector&, bvector&, prng&); + int encrypt (const bvector&, bvector&); int verify (const bvector&, const bvector&, uint); + + uint cipher_size() { + return H.height(); + } + uint plain_size() { + return H.width(); + } + uint plain_weight() { + return t; + } + uint hash_size() { + return cipher_size(); + } + uint signature_size() { + return plain_size(); + } }; -int generate (pubkey&, privkey&, prng&); +int generate (pubkey&, privkey&, prng&, uint m, uint t); } } //namespace ccr diff --git a/lib/decoding.cpp b/lib/decoding.cpp index 60712e3..fe3db95 100644 --- a/lib/decoding.cpp +++ b/lib/decoding.cpp @@ -50,5 +50,10 @@ bool syndrome_decode (bvector&syndrome, gf2m&fld, polynomial& goppa, } } + if (check_failure && a.degree() > 0) { + ev.clear(); + return false; + } + return true; } diff --git a/lib/mce.cpp b/lib/mce.cpp index 9f8bc07..f239e49 100644 --- a/lib/mce.cpp +++ b/lib/mce.cpp @@ -6,7 +6,7 @@ using namespace ccr::mce; #include "decoding.h" -int ccr::mce::generate (pubkey&pub, privkey&priv, prng&rng, uint m, uint t) +int mce::generate (pubkey&pub, privkey&priv, prng&rng, uint m, uint t) { //finite field priv.fld.create (m); @@ -80,9 +80,8 @@ int privkey::decrypt (const bvector&in, bvector&out) //decode bvector ev; - if (!syndrome_decode (syndrome, fld, g, sqInv, ev) ) { + if (!syndrome_decode (syndrome, fld, g, sqInv, ev) ) return 1; //if decoding somehow failed, fail as well. - } // check the error vector, it should have exactly t == deg (g) errors if ( (int) ev.hamming_weight() != g.degree() ) @@ -112,8 +111,8 @@ int privkey::prepare () int privkey::sign (const bvector&in, bvector&out, uint delta, uint attempts, prng&rng) { - uint i, t, s; - bvector p, e, synd, synd2, e2; + uint i, s, t; + bvector p, e, synd, synd_orig, e2; std::vector epos; permutation hpermInv; @@ -130,33 +129,38 @@ int privkey::sign (const bvector&in, bvector&out, uint delta, uint attempts, prn e.resize (s, 0); epos.resize (delta, 0); - h.mult_vec_right (p, synd); + h.mult_vec_right (p, synd_orig); for (t = 0; t < attempts; ++t) { + + synd = synd_orig; + for (i = 0; i < delta; ++i) { epos[i] = rng.random (s); /* we don't care about (unlikely) error bit collisions (they actually don't harm anything) */ e[epos[i]] = 1; + synd.add (h[epos[i]]); } - //abuse linearity of p+e; it is usually faster. - h.mult_vec_right (e, synd2); - synd2.add (synd); + if (syndrome_decode (synd, fld, g, sqInv, e2, true) ) { - if (syndrome_decode (synd2, fld, g, sqInv, e2) ) { - //decoding success! - p.add (e); //add original errors - hperm.permute (p, e2); //back to systematic (e2 is tmp) - e2.resize (signature_size() ); //strip redundancy - Sinv.mult_vecT_left (e2, out); //get a signature - return 0; //OK lol + //create the decodable message + p.add(e); + p.add(e2); + + hperm.permute (p, e2); //back to systematic + e2.resize (signature_size() ); //strip checks + Sinv.mult_vecT_left (e2, out); //signature + return 0; } //if this round failed, we try a new error pattern. - for (i = 0; i < delta; ++i) //clear the errors for the next cycle + for (i = 0; i < delta; ++i) { + //clear the errors for next cycle e[epos[i]] = 0; + } } return 1; //couldn't decode } diff --git a/lib/nd.cpp b/lib/nd.cpp index 2ea7f86..a552d54 100644 --- a/lib/nd.cpp +++ b/lib/nd.cpp @@ -1,35 +1,100 @@ #include "codecrypt.h" +#include "decoding.h" + using namespace ccr; using namespace ccr::nd; -int nd::generate (pubkey&pub, privkey&priv, prng&rng) +int nd::generate (pubkey&pub, privkey&priv, prng&rng, uint m, uint t) { + //galois field + priv.fld.create (m); - return -1; //TODO + //goppa polynomial + priv.g.generate_random_irreducible (t, priv.fld, rng); + + matrix h; + priv.g.compute_goppa_check_matrix (h, priv.fld); + + //scrambler + matrix S; + S.generate_random_invertible (h.height(), rng); + S.compute_inversion (priv.Sinv); + + //permutation + permutation P; + P.generate_random (h.width(), rng); + P.compute_inversion (priv.Pinv); + + //pubkey + pub.t = t; + S.mult (h); + P.permute (S, pub.H); + + return 0; } -int pubkey::encrypt (const bvector& in, bvector&out, prng&rng) +int pubkey::encrypt (const bvector& in, bvector&out) { - - return -1; //TODO + if (in.size() != plain_size() ) return 1; + H.mult_vec_right (in, out); + return 0; } int privkey::decrypt (const bvector&in, bvector&out) { + if (in.size() != cipher_size() ) return 2; - return -1; //TODO + bvector unsc; //unscrambled + Sinv.mult_vec_right (in, unsc); + + bvector ev; + if (!syndrome_decode (unsc, fld, g, sqInv, ev) ) + return 1; + + if ( (int) ev.hamming_weight() != g.degree() ) + return 1; + + Pinv.permute (ev, out); + return 0; } -int privkey::sign (const bvector&in, bvector&out, uint delta, uint h, prng&rng) +int privkey::sign (const bvector&in, bvector&out, uint delta, uint attempts, prng&rng) { + uint i, s, t; - return -1; //TODO + bvector synd_orig, synd, e; + + s = hash_size(); + if (in.size() != s) return 2; + + Sinv.mult_vec_right (in, synd_orig); + + for (t = 0; t < attempts; ++t) { + + synd = synd_orig; + for (i = 0; i < delta; ++i) { + uint pos = rng.random (s); + synd[pos] = !synd[pos]; //flip a bit + } + + if (syndrome_decode (synd, fld, g, sqInv, e, true) ) { + + Pinv.permute (e, out); + return 0; + } + } + + return 1; } int pubkey::verify (const bvector&in, const bvector&hash, uint delta) { - - return -1; //TODO + bvector tmp; + if (!H.mult_vec_right (in, tmp) ) return 2; + if (hash.size() != tmp.size() ) return 1; + tmp.add (hash); + if (tmp.hamming_weight() > delta) return 1; + return 0; } diff --git a/src/main.cpp b/src/main.cpp index fb062e7..078d675 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,7 +26,7 @@ int main() ccr::mce::privkey priv; ccr::mce::pubkey pub; - ccr::mce::generate (pub, priv, r, 7, 4); + ccr::mce::generate (pub, priv, r, 7, 2); cout << "PRIVATE KEY" << endl; cout << priv.fld; @@ -38,6 +38,8 @@ int main() cout << pub.t << endl; cout << pub.G; + /* mce encryption test */ + ccr::bvector plain; plain.resize (pub.plain_size(), 0); plain[0] = 1; @@ -71,9 +73,9 @@ int main() hash[2] = 1; cout << "SIGNING" << endl << hash; - priv.sign (hash, signature, 2, priv.hash_size() *priv.hash_size(), r); + priv.sign (hash, signature, 3, priv.hash_size() *priv.hash_size(), r); cout << "SIGNATURE" << endl << signature; - if (pub.verify (signature, hash, 2) ) + if (pub.verify (signature, hash, 3) ) cout << "VERIFY FAIL" << endl; else cout << "VERIFY OK" << endl; return 0;