int privkey::decrypt (const bvector & in, bvector & out, bvector & errors) { if (in.size() != cipher_size() ) return 2; polynomial synd; uint i, j, 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 (g.eval (permuted_support[i], fld) ); tmp = fld.mult (tmp, tmp); //g(Li)^{-2} synd[0] = fld.add (synd[0], tmp); for (j = 1; j < h_size; ++j) { tmp = fld.mult (tmp, permuted_support[i]); synd[j] = fld.add (synd[j], tmp); } } //decoding polynomial loc; compute_alternant_error_locator (synd, fld, 1 << T, 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; 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) { //found unexpected support, die. out.clear(); return 1; } if (epos >= cipher_size() ) return 1; errors[epos] = 1; if (epos < plain_size() ) out[epos] = !out[epos]; } return 0; }
bool evaluate_error_locator_trace (polynomial&sigma, bvector&ev, gf2m&fld) { ev.clear(); ev.resize (fld.n, 0); std::vector<polynomial> 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<std::pair<uint, polynomial> > 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; }