diff --git a/src/algo_suite.cpp b/src/algo_suite.cpp index 31ab93c..238afdf 100644 --- a/src/algo_suite.cpp +++ b/src/algo_suite.cpp @@ -28,16 +28,6 @@ void fill_algorithm_suite (algorithm_suite&s) #define do_alg(x) static x var_##x ; var_##x.register_into_suite(s); #if HAVE_CRYPTOPP==1 - do_alg (algo_mceqd128); - do_alg (algo_mceqd192); - do_alg (algo_mceqd256); - do_alg (algo_mceqd128cha); - do_alg (algo_mceqd192cha); - do_alg (algo_mceqd256cha); - do_alg (algo_mceqd128xs); - do_alg (algo_mceqd192xs); - do_alg (algo_mceqd256xs); - do_alg (algo_mceqcmdpc128); do_alg (algo_mceqcmdpc256); do_alg (algo_mceqcmdpc128cha); @@ -52,17 +42,6 @@ void fill_algorithm_suite (algorithm_suite&s) do_alg (algo_fmtseq192h20); do_alg (algo_fmtseq256h20); #endif //HAVE_CRYPTOPP==1 - - do_alg (algo_mceqd128cube); - do_alg (algo_mceqd192cube); - do_alg (algo_mceqd256cube); - do_alg (algo_mceqd128cubecha); - do_alg (algo_mceqd192cubecha); - do_alg (algo_mceqd256cubecha); - do_alg (algo_mceqd128cubexs); - do_alg (algo_mceqd192cubexs); - do_alg (algo_mceqd256cubexs); - do_alg (algo_mceqcmdpc128cube); do_alg (algo_mceqcmdpc256cube); do_alg (algo_mceqcmdpc128cubecha); diff --git a/src/algos_enc.cpp b/src/algos_enc.cpp index b13bc13..b48b26c 100644 --- a/src/algos_enc.cpp +++ b/src/algos_enc.cpp @@ -20,7 +20,6 @@ #include "algos_enc.h" -#include "mce_qd.h" #include "mce_qcmdpc.h" #include "arcfour.h" #include "chacha.h" @@ -38,20 +37,6 @@ typedef arcfour arcfour_fo_cipher; * keygen */ -template -static int mceqd_create_keypair (sencode**pub, sencode**priv, prng&rng) -{ - mce_qd::pubkey Pub; - mce_qd::privkey Priv; - - if (mce_qd::generate (Pub, Priv, rng, m, T, b, d)) - return 1; - - *pub = Pub.serialize(); - *priv = Priv.serialize(); - return 0; -} - template static int mceqcmdpc_create_keypair (sencode**pub, sencode**priv, prng&rng) { @@ -488,88 +473,3 @@ mceqcmdpc_create_encdec_func (128cubecha, 9857, 2, 134, cube256hash, cube128hash mceqcmdpc_create_encdec_func (256cubecha, 32771, 2, 264, cube512hash, cube256hash, chacha20, 2475) mceqcmdpc_create_encdec_func (128cubexs, 9857, 2, 134, cube256hash, cube128hash, xsynd, 1152) mceqcmdpc_create_encdec_func (256cubexs, 32771, 2, 264, cube512hash, cube256hash, xsynd, 2475) - -/* - * Instances for MCE-QD algorithms - */ - -#define mceqd_create_keypair_func(name,m,T,b,d) \ -int algo_mceqd##name::create_keypair (sencode**pub, sencode**priv, prng&rng) \ -{ \ - return mceqd_create_keypair (pub, priv, rng); \ -} - -#if HAVE_CRYPTOPP==1 - -mceqd_create_keypair_func (128, 16, 7, 32, 4) -mceqd_create_keypair_func (192, 16, 8, 27, 4) -mceqd_create_keypair_func (256, 16, 8, 32, 4) -mceqd_create_keypair_func (128cha, 16, 7, 32, 4) -mceqd_create_keypair_func (192cha, 16, 8, 27, 4) -mceqd_create_keypair_func (256cha, 16, 8, 32, 4) -mceqd_create_keypair_func (128xs, 16, 7, 32, 4) -mceqd_create_keypair_func (192xs, 16, 8, 27, 4) -mceqd_create_keypair_func (256xs, 16, 8, 32, 4) - -#endif //HAVE_CRYPTOPP==1 - -mceqd_create_keypair_func (128cube, 16, 7, 32, 4) -mceqd_create_keypair_func (192cube, 16, 8, 27, 4) -mceqd_create_keypair_func (256cube, 16, 8, 32, 4) -mceqd_create_keypair_func (128cubecha, 16, 7, 32, 4) -mceqd_create_keypair_func (192cubecha, 16, 8, 27, 4) -mceqd_create_keypair_func (256cubecha, 16, 8, 32, 4) -mceqd_create_keypair_func (128cubexs, 16, 7, 32, 4) -mceqd_create_keypair_func (192cubexs, 16, 8, 27, 4) -mceqd_create_keypair_func (256cubexs, 16, 8, 32, 4) - -#define mceqd_create_encdec_func(name,plainsize,ciphersize,errcount, hash_type,pad_hash_type,scipher,ranksize) \ -int algo_mceqd##name::encrypt (const bvector&plain, bvector&cipher, \ - sencode* pubkey, prng&rng) \ -{ \ - return fo_encrypt \ - < mce_qd::pubkey, \ - plainsize, ciphersize, errcount, \ - hash_type, \ - pad_hash_type, \ - scipher, \ - ranksize > \ - (plain, cipher, pubkey, rng); \ -} \ -int algo_mceqd##name::decrypt (const bvector&cipher, bvector&plain, \ - sencode* privkey) \ -{ \ - return fo_decrypt \ - < mce_qd::privkey, \ - plainsize, ciphersize, errcount, \ - hash_type, \ - pad_hash_type, \ - scipher, \ - ranksize > \ - (cipher, plain, privkey); \ -} - - -#if HAVE_CRYPTOPP==1 - -mceqd_create_encdec_func (128, 2048, 4096, 128, sha256hash, rmd128hash, arcfour_fo_cipher, 816) -mceqd_create_encdec_func (192, 2816, 6912, 256, sha384hash, rmd128hash, arcfour_fo_cipher, 1574) -mceqd_create_encdec_func (256, 4096, 8192, 256, sha512hash, rmd128hash, arcfour_fo_cipher, 1638) -mceqd_create_encdec_func (128cha, 2048, 4096, 128, sha256hash, rmd128hash, chacha20, 816) -mceqd_create_encdec_func (192cha, 2816, 6912, 256, sha384hash, rmd128hash, chacha20, 1574) -mceqd_create_encdec_func (256cha, 4096, 8192, 256, sha512hash, rmd128hash, chacha20, 1638) -mceqd_create_encdec_func (128xs, 2048, 4096, 128, sha256hash, rmd128hash, xsynd, 816) -mceqd_create_encdec_func (192xs, 2816, 6912, 256, sha384hash, rmd128hash, xsynd, 1574) -mceqd_create_encdec_func (256xs, 4096, 8192, 256, sha512hash, rmd128hash, xsynd, 1638) - -#endif //HAVE_CRYPTOPP==1 - -mceqd_create_encdec_func (128cube, 2048, 4096, 128, cube256hash, cube128hash, arcfour_fo_cipher, 816) -mceqd_create_encdec_func (192cube, 2816, 6912, 256, cube384hash, cube128hash, arcfour_fo_cipher, 1574) -mceqd_create_encdec_func (256cube, 4096, 8192, 256, cube512hash, cube128hash, arcfour_fo_cipher, 1638) -mceqd_create_encdec_func (128cubecha, 2048, 4096, 128, cube256hash, cube128hash, chacha20, 816) -mceqd_create_encdec_func (192cubecha, 2816, 6912, 256, cube384hash, cube128hash, chacha20, 1574) -mceqd_create_encdec_func (256cubecha, 4096, 8192, 256, cube512hash, cube128hash, chacha20, 1638) -mceqd_create_encdec_func (128cubexs, 2048, 4096, 128, cube256hash, cube128hash, xsynd, 816) -mceqd_create_encdec_func (192cubexs, 2816, 6912, 256, cube384hash, cube128hash, xsynd, 1574) -mceqd_create_encdec_func (256cubexs, 4096, 8192, 256, cube512hash, cube128hash, xsynd, 1638) diff --git a/src/algos_enc.h b/src/algos_enc.h index ea6fcb4..cb63445 100644 --- a/src/algos_enc.h +++ b/src/algos_enc.h @@ -49,16 +49,6 @@ public: \ * SHA-based variants */ -mce_alg_class (qd128, "MCEQD128FO-SHA256-ARCFOUR"); -mce_alg_class (qd192, "MCEQD192FO-SHA384-ARCFOUR"); -mce_alg_class (qd256, "MCEQD256FO-SHA512-ARCFOUR"); -mce_alg_class (qd128cha, "MCEQD128FO-SHA256-CHACHA20"); -mce_alg_class (qd192cha, "MCEQD192FO-SHA384-CHACHA20"); -mce_alg_class (qd256cha, "MCEQD256FO-SHA512-CHACHA20"); -mce_alg_class (qd128xs, "MCEQD128FO-SHA256-XSYND"); -mce_alg_class (qd192xs, "MCEQD192FO-SHA384-XSYND"); -mce_alg_class (qd256xs, "MCEQD256FO-SHA512-XSYND"); - mce_alg_class (qcmdpc128, "MCEQCMDPC128FO-SHA256-ARCFOUR"); mce_alg_class (qcmdpc256, "MCEQCMDPC256FO-SHA512-ARCFOUR"); mce_alg_class (qcmdpc128cha, "MCEQCMDPC128FO-SHA256-CHACHA20"); @@ -72,16 +62,6 @@ mce_alg_class (qcmdpc256xs, "MCEQCMDPC256FO-SHA512-XSYND"); * Cubehash-based variants */ -mce_alg_class (qd128cube, "MCEQD128FO-CUBE256-ARCFOUR"); -mce_alg_class (qd192cube, "MCEQD192FO-CUBE384-ARCFOUR"); -mce_alg_class (qd256cube, "MCEQD256FO-CUBE512-ARCFOUR"); -mce_alg_class (qd128cubecha, "MCEQD128FO-CUBE256-CHACHA20"); -mce_alg_class (qd192cubecha, "MCEQD192FO-CUBE384-CHACHA20"); -mce_alg_class (qd256cubecha, "MCEQD256FO-CUBE512-CHACHA20"); -mce_alg_class (qd128cubexs, "MCEQD128FO-CUBE256-XSYND"); -mce_alg_class (qd192cubexs, "MCEQD192FO-CUBE384-XSYND"); -mce_alg_class (qd256cubexs, "MCEQD256FO-CUBE512-XSYND"); - mce_alg_class (qcmdpc128cube, "MCEQCMDPC128FO-CUBE256-ARCFOUR"); mce_alg_class (qcmdpc256cube, "MCEQCMDPC256FO-CUBE512-ARCFOUR"); mce_alg_class (qcmdpc128cubecha, "MCEQCMDPC128FO-CUBE256-CHACHA20"); diff --git a/src/decoding.cpp b/src/decoding.cpp deleted file mode 100644 index ba9708d..0000000 --- a/src/decoding.cpp +++ /dev/null @@ -1,123 +0,0 @@ - -/* - * This file is part of Codecrypt. - * - * Copyright (C) 2013-2016 Mirek Kratochvil - * - * Codecrypt is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Codecrypt is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Codecrypt. If not, see . - */ - -#include "decoding.h" - -void compute_alternant_error_locator (polynomial&syndrome, gf2m&fld, - uint t, polynomial&out) -{ - if (syndrome.zero()) { - //ensure no roots - out.resize (1); - out[0] = 1; - return; - } - - polynomial a, b; - - polynomial x2t; //should be x^2t - x2t.clear(); - x2t.resize (1, 1); - x2t.shift (2 * t); - - syndrome.ext_euclid (a, b, x2t, fld, t - 1); - uint b0inv = fld.inv (b[0]); - for (uint i = 0; i < b.size(); ++i) b[i] = fld.mult (b[i], b0inv); - out = b; - //we don't care about error evaluator -} - -/* - * berlekamp trace algorithm - we puncture roots of incoming polynomial into - * the vector of size fld.n - * - * Inspired by implementation from HyMES. - */ - -#include - -bool evaluate_error_locator_trace (polynomial&sigma, bvector&ev, gf2m&fld) -{ - ev.clear(); - ev.resize (fld.n, 0); - - std::vector trace_aux, trace; //trace cache - trace_aux.resize (fld.m); - trace.resize (fld.m); - - trace_aux[0] = polynomial(); - trace_aux[0].resize (2, 0); - trace_aux[0][1] = 1; //trace_aux[0] = x - trace[0] = trace_aux[0]; //trace[0] = x - - for (uint i = 1; i < fld.m; ++i) { - trace_aux[i] = trace_aux[i - 1]; - trace_aux[i].square (fld); - trace_aux[i].mod (sigma, fld); - trace[0].add (trace_aux[i], fld); - } - - std::set > stk; //"stack" - - stk.insert (make_pair (0, sigma)); - - bool failed = false; - - while (!stk.empty()) { - - uint i = stk.begin()->first; - polynomial cur = stk.begin()->second; - - stk.erase (stk.begin()); - - int deg = cur.degree(); - - if (deg <= 0) continue; - if (deg == 1) { //found a linear factor - ev[fld.mult (cur[0], fld.inv (cur[1])) ] = 1; - continue; - } - - if (i >= fld.m) { - failed = true; - continue; - } - - if (trace[i].zero()) { - //compute the trace if it isn't cached - uint a = fld.exp (i); - for (uint j = 0; j < fld.m; ++j) { - trace[i].add_mult (trace_aux[j], a, fld); - a = fld.mult (a, a); - } - } - - polynomial t; - t = cur.gcd (trace[i], fld); - polynomial q, r; - cur.divmod (t, q, r, fld); - - stk.insert (make_pair (i + 1, t)); - stk.insert (make_pair (i + 1, q)); - } - - return !failed; -} - diff --git a/src/mce_qd.cpp b/src/mce_qd.cpp deleted file mode 100644 index 741fffd..0000000 --- a/src/mce_qd.cpp +++ /dev/null @@ -1,470 +0,0 @@ - -/* - * This file is part of Codecrypt. - * - * Copyright (C) 2013-2016 Mirek Kratochvil - * - * Codecrypt is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Codecrypt is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Codecrypt. If not, see . - */ - -#include "mce_qd.h" - -using namespace mce_qd; - -#include "decoding.h" -#include "qd_utils.h" -#include "iohelpers.h" - -#include - -static void print_attack_warning() -{ - static bool printed = false; - if (printed) return; - err ("\n***MCEQD SECURITY WARNING***\n\n" - "Security of the QD-McEliece variant was greatly reduced to less than 2^30\n" - "by an algebraic attack! The functions are kept only for compatibility\n" - "and will be removed soon. Use `-g help' for other encryption variants."); - printed = true; -} - -int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng, - uint m, uint T, uint block_count, uint block_discard) -{ - print_attack_warning(); - - //convenience - gf2m&fld = priv.fld; - std::vector&essence = priv.essence; - - //initial stuff and sizes - fld.create (m); - priv.T = T; - uint t = 1 << T, - block_size = t, - h_block_count = block_count + block_discard, - n = h_block_count * t; - - if (block_count <= m) return 2; //lower bound on block_count - if (n > fld.n / 2) return 2; //n <= q/2 - - std::vector support, Hsig; - polynomial g; - uint i, j; - - //prepare data arrays - Hsig.resize (n); - support.resize (n); - essence.resize (m); - - //retry generating until goppa code is produced. - for (;;) { - - std::set 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; ( (uint) 1 << s) < n; ++s) { - 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 (j = 1; j < i; ++j) { - if (i + j >= n) break; - 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]))); - } - } - - //assemble goppa polynomial. - used.clear(); - - g.clear(); - g.resize (1, 1); //g(x)=1 so we can multiply it - polynomial tmp; - tmp.resize (2, 1); //tmp(x)=x-1 - bool consistent = true; - for (i = 0; i < t; ++i) { - //tmp(x)=x-z=x-(1/h_i) - tmp[0] = fld.inv (Hsig[i]); - if (used.count (tmp[0])) { - consistent = false; - break; - } - used.insert (tmp[0]); - - g.mult (tmp, fld); - } - if (!consistent) continue; //retry - - //compute the support, retry if it has two equal elements. - for (i = 0; i < n; ++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 - - //now the blocks. First assemble blocks to bl - std::vector bl, blp; - bl.resize (h_block_count); - for (i = 0; i < h_block_count; ++i) { - bl[i].resize (block_size); - for (j = 0; j < block_size; ++j) - bl[i][j] = Hsig[i * block_size + j]; - } - - //permute them - priv.block_perm.generate_random (h_block_count, rng); - priv.block_perm.permute (bl, blp); - - //discard blocks - blp.resize (block_count); - - //permute individual blocks - priv.block_perms.resize (block_count); - bl.resize (blp.size()); - for (i = 0; i < block_count; ++i) { - priv.block_perms[i] = rng.random (block_size); - permutation::permute_dyadic (priv.block_perms[i], - blp[i], bl[i]); - } - - //try several permutations to construct G - uint attempts = 0; - for (attempts = 0; attempts < block_count; ++attempts) { - - priv.hperm.generate_random (block_count, rng); - permutation hpermInv; - priv.hperm.compute_inversion (hpermInv); - - std::vector > hblocks; - bvector col; - - //prepare blocks of h - hblocks.resize (block_count); - for (i = 0; i < block_count; ++i) - hblocks[i].resize (fld.m); - - //fill them from Hsig - for (i = 0; i < block_count; ++i) { - col.from_poly_cotrace (bl[hpermInv[i]], fld); - for (j = 0; j < fld.m; ++j) - col.get_block (j * block_size, - block_size, - hblocks[i][j]); - } - - /* do a modified QD-blockwise gaussian elimination on hblocks. - * If it fails, retry. */ - if (!qd_to_right_echelon_form (hblocks)) continue; - - pub.qd_sigs.resize2 (block_count - fld.m, - block_size * fld.m, 0); - for (i = 0; i < block_count - fld.m; ++i) { - for (j = 0; j < fld.m; ++j) - pub.qd_sigs[i].set_block - (hblocks[i][j], block_size * j); - } - - break; - } - - if (attempts == block_count) //generating G failed, retry all - continue; - - //finish the pubkey - pub.T = T; - - return 0; - } -} - -int privkey::prepare() -{ - print_attack_warning(); - - uint s, i, j; - std::vector Hsig, support; - uint omega; - - uint block_size = 1 << T, - block_count = hperm.size(), - h_block_count = block_perm.size(), - n = h_block_count * block_size; - - //compute H signature from essence - Hsig.resize (n); - Hsig[0] = fld.inv (essence[fld.m - 1]); - for (s = 0; ( (uint) 1 << s) < n; ++s) { - i = 1 << s; //i = 2^s - - Hsig[i] = fld.inv (fld.add (essence[s], essence[fld.m - 1])); - - for (j = 1; j < i; ++j) { - if (i + j >= n) break; - Hsig[i + j] = fld.inv - (fld.add - (fld.inv (Hsig[i]), - fld.add ( - fld.inv (Hsig[j]), - essence[fld.m - 1] - ))); - } - } - - //goppa polynomial with omega=0 - std::set used; - used.clear(); - - polynomial tmp; - g.clear(); - g.resize (1, 1); //g(x)=1 - tmp.clear(); - tmp.resize (2, 1); //tmp(x)=x+1 - for (i = 0; i < block_size; ++i) { - tmp[0] = fld.inv (Hsig[i]); //tmp(x)=x+1/h_i - if (used.count (tmp[0])) - return 1; - used.insert (tmp[0]); - g.mult (tmp, fld); - } - - //compute the support with omega=0 - support.resize (n); - for (i = 0; i < n; ++i) { - //don't check discarded support - if (block_perm[i / block_size] >= block_count) continue; - support[i] = fld.add - (fld.inv (Hsig[i]), - essence[fld.m - 1]); - //support consistency check - if (used.count (support[i])) - return 1; - used.insert (support[i]); - } - - //choose some omega - omega = fld.n; - for (i = 0; i < fld.n; ++i) - if (!used.count (i)) { - omega = i; - break; - } - if (omega == fld.n) return 1; - - //modify support to omega-ized version - for (i = 0; i < support.size(); ++i) - support[i] = fld.add (support[i], omega); - - //modify g to omega-ized version - g.clear(); - tmp.clear(); - g.resize (1, 1); //g(x)=1 - tmp.resize (2, 1); //tmp(x)=x+1 - for (i = 0; i < block_size; ++i) { - tmp[0] = fld.add (fld.inv (Hsig[i]), omega); - g.mult (tmp, fld); - } - - // prepare permuted support, from that prepare permuted check matrix - // (so that it can be applied directly) - uint pos, blk_perm; - std::vector sbl1, sbl2; - - sbl1.resize (block_size); - sbl2.resize (block_size); - permuted_support.resize (block_size * block_count); - - //permute support - for (i = 0; i < h_block_count; ++i) { - pos = block_perm[i]; - if (pos >= block_count) continue; //was discarded - blk_perm = block_perms[pos]; - pos = hperm[pos]; - - //permute i-th block of support - for (j = 0; j < block_size; ++j) - sbl1[j] = support[j + i * block_size]; - - permutation::permute_dyadic (blk_perm, sbl1, sbl2); - - //store support to permuted support - for (j = 0; j < block_size; ++j) - permuted_support[j + pos * block_size] = sbl2[j]; - } - - //convert the permuted support to actual lookup - support_pos.clear(); - //fld.n in support lookup means that it isn't there (we don't have -1) - support_pos.resize (fld.n, fld.n); - for (i = 0; i < block_size * block_count; ++i) - support_pos[permuted_support[i]] = i; - - return 0; -} - -int pubkey::encrypt (const bvector& in, bvector&out, prng&rng) -{ - uint s = cipher_size(), - t = 1 << T; - if (t > s) return 1; - - //create error vector - bvector e; - e.resize (s, 0); - for (uint n = t; n > 0;) { - uint p = rng.random (s); - if (!e[p]) { - e[p] = 1; - --n; - } - } - return encrypt (in, out, e); -} - -int pubkey::encrypt (const bvector & in, bvector & out, const bvector&errors) -{ - print_attack_warning(); - - uint t = 1 << T; - bvector p, g, r, cksum; - uint i, j; - - /* - * shortened checksum pair of G is computed blockwise accordingly to - * the t-sized square dyadic blocks. - */ - - //some checks - if (!qd_sigs.width()) return 1; - if (qd_sigs.height() % t) return 1; - if (in.size() != plain_size()) return 2; - if (errors.size() != cipher_size()) return 2; - - uint blocks = qd_sigs.height() / t; - cksum.resize (qd_sigs.height(), 0); - - p.resize (t); - g.resize (t); - r.resize (t); - - std::vector c1, c2, c3; - c1.resize (t); - c2.resize (t); - c3.resize (t); - - 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 - qd_sigs[i].get_block (j * t, t, g); - - //block result - fwht_dyadic_multiply (p, g, r, c1, c2, c3); - cksum.add_offset (r, t * j); - } - } - - //compute ciphertext - out = in; - out.append (cksum); - out.add (errors); - - return 0; -} - -int privkey::decrypt (const bvector & in, bvector & out) -{ - bvector tmp_errors; - return decrypt (in, out, tmp_errors); -} - -int privkey::decrypt (const bvector & in, bvector & out, bvector & errors) -{ - print_attack_warning(); - - if (in.size() != cipher_size()) return 2; - polynomial synd; - uint i, tmp; - - /* - * compute the syndrome from alternant check matrix - * that is H_alt = Vdm(L) * Diag(g(L_i)^{-2}) - */ - uint h_size = 1 << (T + 1); //= 2*block_size - synd.clear(); - synd.resize (h_size, 0); - for (i = 0; i < cipher_size(); ++i) if (in[i]) { - tmp = fld.inv_square //g(Li)^{-2} - (g.eval (permuted_support[i], fld)); - fld.add_mults (tmp, permuted_support[i], - synd.begin(), synd.end()); - } - - //decoding - polynomial loc; - compute_alternant_error_locator (synd, fld, 1 << T, loc); - - bool failed = false; - bvector ev; - if (!evaluate_error_locator_trace (loc, ev, fld)) - failed = true; - - out = in; - out.resize (plain_size()); - errors.clear(); - errors.resize (cipher_size(), 0); - //flip error positions of out. - for (i = 0; i < ev.size(); ++i) if (ev[i]) { - uint epos = support_pos[fld.inv (i)]; - if (epos == fld.n || epos >= cipher_size()) { - //found unexpected/wrong support, die. - failed = true; - continue; - } - errors[epos] = 1; - if (epos < plain_size()) - out[epos] = !out[epos]; - } - - return failed ? 1 : 0; -} - diff --git a/src/mce_qd.h b/src/mce_qd.h deleted file mode 100644 index 89f14fe..0000000 --- a/src/mce_qd.h +++ /dev/null @@ -1,104 +0,0 @@ - -/* - * This file is part of Codecrypt. - * - * Copyright (C) 2013-2016 Mirek Kratochvil - * - * Codecrypt is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Codecrypt is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Codecrypt. If not, see . - */ - -#ifndef _ccr_mce_qd_h_ -#define _ccr_mce_qd_h_ - -#include - -#include "bvector.h" -#include "gf2m.h" -#include "matrix.h" -#include "permutation.h" -#include "polynomial.h" -#include "prng.h" -#include "sencode.h" -#include "types.h" - -/* - * compact Quasi-dyadic McEliece - * according to Misoczki, Barreto, Compact McEliece Keys from Goppa Codes. - * - * Needs plaintext conversion. Unfortunately broken by an algebraic attack, do - * not use this. - */ -namespace mce_qd -{ -class privkey -{ -public: - std::vector essence; - gf2m fld; //we fix q=2^fld.m=fld.n, n=q/2 - uint T; //the QD's t parameter is 2^T. - permutation block_perm; //order of blocks - std::vector block_perms; //dyadic permutations of blocks - permutation hperm; //block permutation of H block used to get G - - //derivable stuff - //pre-permuted positions of support rows and support content - std::vector support_pos, permuted_support; - //generating polynomial - polynomial g; - - int decrypt (const bvector&, bvector&); - int decrypt (const bvector&, bvector&, bvector&); - int prepare(); - - uint cipher_size() { - return (1 << T) * hperm.size(); - } - uint plain_size() { - return (1 << T) * (hperm.size() - fld.m); - } - uint error_count() { - return 1 << T; - } - - sencode* serialize(); - bool unserialize (sencode*); -}; - -class pubkey -{ -public: - uint T; - matrix qd_sigs; - - int encrypt (const bvector&, bvector&, prng&); - int encrypt (const bvector&, bvector&, const bvector&); - - uint cipher_size() { - return plain_size() + qd_sigs[0].size(); - } - uint plain_size() { - return (1 << T) * qd_sigs.size(); - } - uint error_count() { - return 1 << T; - } - - sencode* serialize(); - bool unserialize (sencode*); -}; - -int generate (pubkey&, privkey&, prng&, uint m, uint T, uint b, uint bd); -} - -#endif diff --git a/src/qd_utils.cpp b/src/qd_utils.cpp deleted file mode 100644 index eea1807..0000000 --- a/src/qd_utils.cpp +++ /dev/null @@ -1,216 +0,0 @@ - -/* - * This file is part of Codecrypt. - * - * Copyright (C) 2013-2016 Mirek Kratochvil - * - * Codecrypt is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Codecrypt is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Codecrypt. If not, see . - */ - -#include "qd_utils.h" - -#include - -/* - * we count on that all integers are sufficiently large. - * They should be, largest value occuring should be O(k*n) if initial vector is - * consisted only from {0,1}^n, and we don't usually have codes of this size. - */ - -static void fwht (std::vector x, std::vector&r) -{ - uint bs, s; - s = x.size(); - bs = s >> 1; - r.swap (x); - while (bs) { - x.swap (r); - for (uint i = 0; i < s; ++i) { - if ( (i / bs) & 1) - r[i] = x[i - bs] - x[i]; - else - r[i] = x[i] + x[i + bs]; - } - bs >>= 1; - } -} - -/* - * we expect correct parameter size and preallocated out. Last 3 parameters are - * used as a cache - just supply the same vectors everytime when you're doing - * this multiple times. - */ -void fwht_dyadic_multiply (const bvector& a, const bvector& b, bvector& out, - std::vector&t, - std::vector&A, - std::vector&B) -{ - - uint i; - - //lift everyting to Z. - for (i = 0; i < a.size(); ++i) t[i] = a[i]; - fwht (t, A); - - for (i = 0; i < b.size(); ++i) t[i] = b[i]; - fwht (t, B); - - //multiply diagonals to A - for (i = 0; i < A.size(); ++i) A[i] *= B[i]; - fwht (A, t); - - uint bitpos = a.size(); //no problem as a.size() == 1< >&mat) -{ - uint w = mat.size(); - if (!w) return false; - uint h = mat[0].size(); - if (!h) return false; - uint bs = mat[0][0].size(); - - uint i, j, k, l; - - /* - * Inversion is done the quasi-dyadic way: - * - * - because for QD matrix m=delta(h) the product - * m*m = sum(h) * I, binary QD matrix m is either - * inversion of itself (m*m=I) or isn't invertible - * and m*m=0. sum(h), the "count of ones in QD - * signature mod 2", easily determines the result. - * - * - Using blockwise invertions/multiplications, - * gaussian elimination needed to invert the right - * square of H can be performed in O(m^2*block_count) - * matrix operations. Matrix operations are either - * addition (O(t) on QDs), multiplication(O(t log t) - * on QDs) or inversion (O(t), as shown above). - * Whole proces is therefore quite fast. - * - * Gaussian elimination on the QD signature should - * result in something like this: (for m=3, t=4) - * - * 1010 0101 1001 1000 0000 0000 - * 0101 1100 1110 0000 1000 0000 - * 0111 1110 0100 0000 0000 1000 - */ - - bvector tmp; - tmp.resize (bs); - - std::vector c1, c2, c3; - c1.resize (bs); - c2.resize (bs); - c3.resize (bs); - - for (i = 0; i < h; ++i) { //gauss step - //first, find a nonsingular matrix in the column - for (j = i; j < h; ++j) - if (mat[w - h + i][j] - .hamming_weight() % 2) break; - if (j >= h) //none found, die! - return false; - - //bring it to correct position (swap it to i-th row) - if (j > i) for (k = 0; k < w; ++k) - mat[k][i].swap - (mat[k][j]); - - //now normalize the row - for (j = i; j < h; ++j) { - l = mat [w - h + i] - [j].hamming_weight(); - if (l == 0) continue; //zero is just okay :] - if (! (l % 2)) //singular, make it regular by adding the i-th row - for (k = 0; - k < w; - ++k) - mat[k][j].add - (mat[k][i]); - - //now a matrix is regular, we can easily make it I. - //first, multiply the row - for (k = 0; k < w; ++k) { - //don't overwrite the matrix we're counting with - if (k == w - h + i) continue; - fwht_dyadic_multiply - (mat[w - h + i][j], - mat[k][j], tmp, c1, c2, c3); - mat[k][j] = tmp; - } - //change the block on the diagonal - fwht_dyadic_multiply - (mat[w - h + i][j], - mat[w - h + i][j], tmp, c1, c2, c3); - mat[w - h + i][j] = tmp; - - //and zero the column below diagonal - if (j > i) for (k = 0; k < w; ++k) - mat[k][j].add - (mat[k][i]); - } - } - - for (i = 0; i < h; ++i) { //jordan step - //normalize diagonal - for (k = 0; k < w - i; ++k) { - //we can safely rewrite the diagonal here (nothing's behind it) - fwht_dyadic_multiply - (mat[w - i - 1][h - i - 1], - mat[k][h - i - 1], tmp, c1, c2, c3); - mat[k][h - i - 1] = tmp; - } - - //now make zeroes above - for (j = i + 1; j < h; ++j) { - l = mat[w - i - 1] - [h - j - 1].hamming_weight(); - if (l == 0) continue; //already zero - if (! (l % 2)) { //nonsingular, fix it by adding diagonal - for (k = 0; k < w; ++k) - mat[k][h - j - 1].add - (mat[k][h - i - 1]); - } - for (k = 0; k < w - i; ++k) { - //overwrite is also safe here - fwht_dyadic_multiply - (mat[w - i - 1] - [h - j - 1], - mat[k][h - j - 1], tmp, c1, c2, c3); - mat[k][h - j - 1] = tmp; - } - //I+I=0 - for (k = 0; k < w; ++k) - mat[k][h - j - 1].add - (mat[k][h - i - 1]); - } - } - - return true; -} - -uint choose_random (uint limit, prng&rng, std::set&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; - } -} - diff --git a/src/serialization.cpp b/src/serialization.cpp index 89891a0..292a2fe 100644 --- a/src/serialization.cpp +++ b/src/serialization.cpp @@ -25,7 +25,6 @@ #include "gf2m.h" #include "polynomial.h" #include "permutation.h" -#include "mce_qd.h" #include "mce_qcmdpc.h" #include "fmtseq.h" #include "message.h" @@ -167,95 +166,6 @@ bool polynomial::unserialize (sencode* s) #define PUBKEY_IDENT "CCR-PUBLIC-KEY-" #define PRIVKEY_IDENT "CCR-PRIVATE-KEY-" -sencode* mce_qd::privkey::serialize() -{ - sencode_list*l = new sencode_list; - l->items.resize (7); - l->items[0] = new sencode_bytes (PRIVKEY_IDENT "QD-MCE"); - l->items[1] = fld.serialize(); - l->items[2] = new sencode_int (T); - l->items[3] = serialize_uint_vector (&essence); - l->items[4] = block_perm.serialize(); - l->items[5] = serialize_uint_vector (&block_perms); - l->items[6] = hperm.serialize(); - return l; -} - -bool mce_qd::privkey::unserialize (sencode* s) -{ - sencode_list*CAST_LIST (s, l); - if (l->items.size() != 7) return false; - - sencode_bytes*CAST_BYTES (l->items[0], ident); - if (ident->b.compare (PRIVKEY_IDENT "QD-MCE")) return false; - - sencode_int*CAST_INT (l->items[2], p); - T = p->i; - - if (! (fld.unserialize (l->items[1]) && - unserialize_uint_vector (&essence, l->items[3]) && - block_perm.unserialize (l->items[4]) && - unserialize_uint_vector (&block_perms, l->items[5]) && - hperm.unserialize (l->items[6]))) return false; - - return true; -} - -sencode* mce_qd::pubkey::serialize() -{ - sencode_list*l = new sencode_list; - l->items.resize (3); - l->items[0] = new sencode_bytes (PUBKEY_IDENT "QD-MCE"); - l->items[1] = new sencode_int (T); - l->items[2] = qd_sigs.serialize(); - return l; -} - -bool mce_qd::pubkey::unserialize (sencode*s) -{ - sencode_list*CAST_LIST (s, l); - if (l->items.size() != 3) return false; - - sencode_bytes*CAST_BYTES (l->items[0], ident); - if (ident->b.compare (PUBKEY_IDENT "QD-MCE")) return false; - - sencode_int*CAST_INT (l->items[1], p); - T = p->i; - - if (!qd_sigs.unserialize (l->items[2])) return false; - - return true; -} - -sencode* fmtseq::privkey::tree_stk_item::serialize() -{ - sencode_list*l = new sencode_list; - l->items.resize (3); - l->items[0] = new sencode_int (level); - l->items[1] = new sencode_int (pos); - l->items[2] = new sencode_bytes (item); - return l; -} - -bool fmtseq::privkey::tree_stk_item::unserialize (sencode*s) -{ - sencode_list*CAST_LIST (s, l); - if (l->items.size() != 3) return false; - - sencode_int*p; - CAST_INT (l->items[0], p); - level = p->i; - - CAST_INT (l->items[1], p); - pos = p->i; - - sencode_bytes* CAST_BYTES (l->items[2], a); - item = std::vector (a->b.begin(), a->b.end()); - - return true; - -} - sencode* mce_qcmdpc::pubkey::serialize() { sencode_list*l = new sencode_list; @@ -316,6 +226,34 @@ bool mce_qcmdpc::privkey::unserialize (sencode*s) return true; } +sencode* fmtseq::privkey::tree_stk_item::serialize() +{ + sencode_list*l = new sencode_list; + l->items.resize (3); + l->items[0] = new sencode_int (level); + l->items[1] = new sencode_int (pos); + l->items[2] = new sencode_bytes (item); + return l; +} + +bool fmtseq::privkey::tree_stk_item::unserialize (sencode*s) +{ + sencode_list*CAST_LIST (s, l); + if (l->items.size() != 3) return false; + + sencode_int*p; + CAST_INT (l->items[0], p); + level = p->i; + + CAST_INT (l->items[1], p); + pos = p->i; + + sencode_bytes* CAST_BYTES (l->items[2], a); + item = std::vector (a->b.begin(), a->b.end()); + + return true; + +} sencode* fmtseq::privkey::serialize() {