1
0
mirror of https://github.com/biergaizi/codecrypt synced 2024-06-27 09:18:16 +00:00
codecrypt/src/polynomial.cpp

259 lines
5.2 KiB
C++
Raw Normal View History

2012-04-01 11:51:59 +00:00
2012-11-05 21:45:35 +00:00
/*
* This file is part of Codecrypt.
*
2016-04-17 13:47:47 +00:00
* Copyright (C) 2013-2016 Mirek Kratochvil <exa.exa@gmail.com>
*
2012-11-05 21:45:35 +00:00
* 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 <http://www.gnu.org/licenses/>.
*/
2012-12-25 13:39:39 +00:00
#include "polynomial.h"
#include "gf2m.h"
#include "prng.h"
#include "matrix.h"
2012-04-01 11:51:59 +00:00
2012-04-01 22:44:19 +00:00
int polynomial::degree() const
{
int r;
2015-10-31 21:58:17 +00:00
for (r = ( (int) size()) - 1; r >= 0; --r) if (item (r)) break;
2012-04-01 21:44:18 +00:00
return r;
}
void polynomial::strip()
{
resize (degree() + 1);
}
2012-04-01 22:44:19 +00:00
bool polynomial::zero() const
{
2015-10-31 21:58:17 +00:00
for (uint i = 0; i < size(); ++i) if (item (i)) return false;
2012-04-01 22:44:19 +00:00
return true;
}
bool polynomial::one() const
{
if (degree() != 0) return false;
2012-05-15 12:00:41 +00:00
return (item (0) == 1) ? true : false;
}
2012-04-03 09:08:52 +00:00
void polynomial::add (const polynomial&f, gf2m&fld)
2012-04-01 21:44:18 +00:00
{
2012-04-01 22:44:19 +00:00
int df = f.degree();
2015-10-31 21:58:17 +00:00
if (df > degree()) resize (df + 1);
2012-04-03 10:13:51 +00:00
for (int i = 0; i <= df; ++i) item (i) = fld.add (item (i), f[i]);
2012-04-01 21:44:18 +00:00
}
2012-04-06 12:49:40 +00:00
void polynomial::add_mult (const polynomial&f, uint mult, gf2m&fld)
{
int df = f.degree();
2015-10-31 21:58:17 +00:00
if (df > degree()) resize (df + 1);
2012-04-06 12:49:40 +00:00
for (int i = 0; i <= df; ++i)
2015-10-31 21:58:17 +00:00
item (i) = fld.add (item (i), fld.mult (mult, f[i]));
2012-04-06 12:49:40 +00:00
}
2012-04-03 09:08:52 +00:00
void polynomial::mod (const polynomial&f, gf2m&fld)
2012-04-01 21:44:18 +00:00
{
2012-04-01 22:44:19 +00:00
int df = f.degree();
2012-04-07 14:46:56 +00:00
if (df < 0) { //mod 0 -> 0
clear();
return;
}
2012-04-01 22:44:19 +00:00
int d;
2012-04-03 09:08:52 +00:00
uint hi = fld.inv (f[df]);
2012-04-01 21:44:18 +00:00
// while there's place to substract, reduce by x^(d-df)-multiply of f
2012-04-03 09:08:52 +00:00
for (d = degree(); d >= df; --d)
2015-10-31 21:58:17 +00:00
if (item (d)) {
2012-04-03 09:08:52 +00:00
uint t = fld.mult (item (d), hi);
2012-04-04 21:01:55 +00:00
2012-04-03 09:08:52 +00:00
for (int i = 0; i <= df; ++i)
2012-04-16 09:11:58 +00:00
item (i + d - df)
= fld.add (item (i + d - df),
2015-10-31 21:58:17 +00:00
fld.mult (t, f[i]));
2012-04-03 09:08:52 +00:00
}
2012-04-01 21:44:18 +00:00
strip();
}
2012-04-03 09:08:52 +00:00
void polynomial::mult (const polynomial&b, gf2m&fld)
2012-04-01 21:44:18 +00:00
{
polynomial a = *this;
2013-07-23 13:58:02 +00:00
int da, db, i, j;
2012-04-01 21:44:18 +00:00
da = a.degree();
db = b.degree();
2012-05-12 22:17:12 +00:00
clear();
2015-10-31 21:58:17 +00:00
if ( (da < 0) || (db < 0)) //multiply by zero, not much to do.
return;
2012-04-01 21:44:18 +00:00
resize (da + db + 1, 0);
for (i = 0; i <= da; ++i)
if (a[i]) for (j = 0; j <= db; ++j)
2012-04-03 09:08:52 +00:00
item (i + j) = fld.add (item (i + j),
2015-10-31 21:58:17 +00:00
fld.mult (a[i], b[j]));
2012-04-01 21:44:18 +00:00
}
2012-04-03 09:08:52 +00:00
polynomial polynomial::gcd (polynomial b, gf2m&fld)
2012-04-01 11:51:59 +00:00
{
2012-04-01 21:44:18 +00:00
polynomial a = *this;
2012-04-01 11:51:59 +00:00
2012-04-01 21:44:18 +00:00
//eukleides
if (a.degree() < 0) return b;
for (;;) {
2015-10-31 21:58:17 +00:00
if (b.zero()) return a;
2012-04-03 09:08:52 +00:00
a.mod (b, fld);
2015-10-31 21:58:17 +00:00
if (a.zero()) return b;
2012-04-03 09:08:52 +00:00
b.mod (a, fld);
2012-04-01 21:44:18 +00:00
}
//unreachable
return polynomial();
2012-04-01 11:51:59 +00:00
}
2012-04-04 21:01:55 +00:00
uint polynomial::eval (uint x, gf2m&fld) const
{
uint r = 0;
//horner
for (int i = degree(); i >= 0; --i)
2015-10-31 21:58:17 +00:00
r = fld.add (item (i), fld.mult (r, x));
2012-04-04 21:01:55 +00:00
return r;
}
2012-04-06 12:49:40 +00:00
void polynomial::shift (uint n)
{
if (degree() < 0) return;
insert (begin(), n, 0);
}
void polynomial::square (gf2m&fld)
{
polynomial a = *this;
2012-05-12 22:17:12 +00:00
mult (a, fld);
2012-04-06 12:49:40 +00:00
}
2013-06-21 18:35:40 +00:00
void polynomial::sqrt (std::vector<polynomial>& sqInv, gf2m&fld)
2012-04-06 12:49:40 +00:00
{
polynomial a = *this;
clear();
2012-04-20 08:11:21 +00:00
uint s = sqInv.size();
2012-04-16 09:11:58 +00:00
resize (s, 0);
for (uint i = 0; i < s; ++i) {
for (uint j = 0; j < s; ++j) {
2015-10-31 21:58:17 +00:00
if (j >= a.size()) break;
if (i >= sqInv[j].size()) continue;
item (i) = fld.add (item (i), fld.mult (sqInv[j][i], a[j]));
2012-04-16 09:11:58 +00:00
}
}
strip();
for (uint i = 0; i < size(); ++i)
2015-10-31 21:58:17 +00:00
item (i) = fld.sq_root (item (i));
2012-04-06 12:49:40 +00:00
}
void polynomial::div (polynomial&p, polynomial&m, gf2m&fld)
{
2012-05-13 22:03:35 +00:00
polynomial r0, r1, s0, s1, s2, q0, q1;
2012-04-06 12:49:40 +00:00
2012-04-07 14:46:56 +00:00
r0 = m;
r1 = p;
r1.mod (m, fld);
s0.clear();
2012-05-15 20:09:19 +00:00
s1.swap (*this);
2012-04-07 14:46:56 +00:00
s1.mod (m, fld);
while (r1.degree() >= 0) {
2012-05-13 22:03:35 +00:00
r0.divmod (r1, q0, q1, fld);
2012-04-07 14:46:56 +00:00
r0.swap (r1);
2012-05-13 22:03:35 +00:00
r1.swap (q1);
2012-04-07 14:46:56 +00:00
s2 = s0;
2012-05-13 22:03:35 +00:00
q0.mult (s1, fld);
q0.mod (m, fld);
s2.add (q0, fld);
2012-04-07 14:46:56 +00:00
s0.swap (s1);
s1.swap (s2);
}
2012-05-15 20:09:19 +00:00
this->swap (s0);
2012-05-13 22:03:35 +00:00
//scalar divide by r0 head
2012-05-15 20:09:19 +00:00
if (r0.degree() < 0) return;
uint c = r0[r0.degree() ];
c = fld.inv (c);
for (uint i = 0; i < size(); ++i) item (i) = fld.mult (item (i), c);
2012-04-06 12:49:40 +00:00
}
void polynomial::divmod (polynomial&d, polynomial&res, polynomial&rem, gf2m&fld)
{
int degd = d.degree();
if (degd < 0) return;
uint headInv = fld.inv (d[degd]);
rem = *this;
res.clear();
int t;
2015-10-31 21:58:17 +00:00
while ( (t = rem.degree()) >= degd) {
2012-04-06 12:49:40 +00:00
int rp = t - degd;
2013-07-23 13:58:02 +00:00
if ( (int) res.size() < rp + 1) res.resize (rp + 1, 0);
2012-04-06 12:49:40 +00:00
res[rp] = fld.mult (headInv, rem[t]);
2013-07-23 13:58:02 +00:00
for (int i = 0; i <= degd; ++i)
2015-10-31 21:58:17 +00:00
rem[i + rp] = fld.add (rem[i + rp], fld.mult (res[rp], d[i]));
2012-04-06 12:49:40 +00:00
}
2012-05-13 22:03:35 +00:00
rem.strip();
2012-04-06 12:49:40 +00:00
}
void polynomial::inv (polynomial&m, gf2m&fld)
{
polynomial a = *this;
2012-05-12 22:17:12 +00:00
resize (1);
2012-04-16 10:15:44 +00:00
item (0) = 1;
2012-04-06 12:49:40 +00:00
div (a, m, fld);
}
2012-11-05 20:30:08 +00:00
void polynomial::ext_euclid (polynomial&a_out, polynomial&b_out,
polynomial&m, gf2m&fld, int deg)
{
//TODO: speed this up (spare degree calculations)
polynomial A, B, a, b, tmp;
uint h;
A = *this;
a = m;
B.clear();
B.resize (1, 1);
b.clear();
while (a.degree() > deg) {
if (A.degree() < 0)
break;
A.swap (a);
B.swap (b);
int j;
2015-10-31 21:58:17 +00:00
while ( (j = A.degree() - a.degree()) >= 0) {
h = fld.div (A.head(), a.head());
2012-11-05 20:30:08 +00:00
tmp = a;
tmp.shift (j);
A.add_mult (tmp, h, fld);
tmp = b;
tmp.shift (j);
B.add_mult (tmp, h, fld);
}
}
a.swap (a_out);
b.swap (b_out);
}