summaryrefslogtreecommitdiffstats
path: root/botan/src/math/gfpmath/gfp_element.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'botan/src/math/gfpmath/gfp_element.cpp')
-rw-r--r--botan/src/math/gfpmath/gfp_element.cpp699
1 files changed, 699 insertions, 0 deletions
diff --git a/botan/src/math/gfpmath/gfp_element.cpp b/botan/src/math/gfpmath/gfp_element.cpp
new file mode 100644
index 0000000..b718093
--- /dev/null
+++ b/botan/src/math/gfpmath/gfp_element.cpp
@@ -0,0 +1,699 @@
+/******
+ * Arithmetic for prime fields GF(p) (source file)
+ *
+ * (C) 2007 Martin Doering
+ * doering@cdc.informatik.tu-darmstadt.de
+ * Christoph Ludwig
+ * ludwig@fh-worms.de
+ * Falko Strenzke
+ * strenzke@flexsecure.de
+ ******/
+
+#include <botan/gfp_element.h>
+#include <botan/numthry.h>
+#include <botan/def_powm.h>
+#include <botan/mp_types.h>
+#include <botan/mp_asm.h>
+#include <botan/mp_asmi.h>
+#include <assert.h>
+#include <ostream>
+
+namespace Botan {
+
+namespace {
+
+void inner_montg_mult_sos(word result[], const word* a_bar, const word* b_bar, const word* n, const word* n_dash, u32bit s)
+ {
+ SecureVector<word> t;
+ t.grow_to(2*s+1);
+
+ // t = a_bar * b_bar
+ for (u32bit i=0; i<s; i++)
+ {
+ word C = 0;
+ word S = 0;
+ for (u32bit j=0; j<s; j++)
+ {
+ // we use:
+ // word word_madd3(word a, word b, word c, word d, word* carry)
+ // returns a * b + c + d and resets the carry (not using it as input)
+
+ S = word_madd3(a_bar[j], b_bar[i], t[i+j], &C);
+ t[i+j] = S;
+ }
+ t[i+s] = C;
+ }
+
+ // ???
+ for (u32bit i=0; i<s; i++)
+ {
+ // word word_madd2(word a, word b, word c, word* carry)
+ // returns a * b + c, resets the carry
+
+ word C = 0;
+ word zero = 0;
+ word m = word_madd2(t[i], n_dash[0], &zero);
+
+ for (u32bit j=0; j<s; j++)
+ {
+ word S = word_madd3(m, n[j], t[i+j], &C);
+ t[i+j] = S;
+ }
+
+ //// mp_mulop.cpp:
+ ////word bigint_mul_add_words(word z[], const word x[], u32bit x_size, word y)
+ u32bit cnt = 0;
+ while (C > 0)
+ {
+ // we need not worry here about C > 1, because the other operand is zero
+ word tmp = word_add(t[i+s+cnt], 0, &C);
+ t[i+s+cnt] = tmp;
+ cnt++;
+ }
+ }
+
+ // u = t
+ SecureVector<word> u;
+ u.grow_to(s+1);
+ for (u32bit j=0; j<s+1; j++)
+ {
+ u[j] = t[j+s];
+ }
+
+ // t = u - n
+ word B = 0;
+ word D = 0;
+ for (u32bit i=0; i<s; i++)
+ {
+ D = word_sub(u[i], n[i], &B);
+ t[i] = D;
+ }
+ D = word_sub(u[s], 0, &B);
+ t[s] = D;
+
+ // if t >= 0 (B == 0 -> no borrow), return t
+ if(B == 0)
+ {
+ for (u32bit i=0; i<s; i++)
+ {
+ result[i] = t[i];
+ }
+ }
+ else // else return u
+ {
+ for (u32bit i=0; i<s; i++)
+ {
+ result[i] = u[i];
+ }
+ }
+ }
+
+void montg_mult(BigInt& result, BigInt& a_bar, BigInt& b_bar, const BigInt& m, const BigInt& m_dash, const BigInt)
+ {
+ if(m.is_zero() || m_dash.is_zero())
+ throw Invalid_Argument("montg_mult(): neither modulus nor m_dash may be zero (and one of them was)");
+
+ if(a_bar.is_zero() || b_bar.is_zero())
+ result = 0;
+
+ u32bit s = m.sig_words();
+ a_bar.grow_to(s);
+ b_bar.grow_to(s);
+ result.grow_to(s);
+
+ inner_montg_mult_sos(result.get_reg(), a_bar.data(), b_bar.data(),
+ m.data(), m_dash.data(), s);
+ }
+
+/**
+*calculates R=b^n (here b=2) with R>m (and R beeing as small as possible) for an odd modulus m.
+* no check for oddity is performed!
+*
+* Distributed under the terms of the Botan license
+*/
+BigInt montgm_calc_r_oddmod(const BigInt& prime)
+ {
+ u32bit n = prime.sig_words();
+ BigInt result(1);
+ result <<= n*BOTAN_MP_WORD_BITS;
+ return result;
+ }
+
+/**
+*calculates m' with r*r^-1 - m*m' = 1
+* where r^-1 is the multiplicative inverse of r to the modulus m
+*/
+BigInt montgm_calc_m_dash(const BigInt& r, const BigInt& m, const BigInt& r_inv)
+ {
+ BigInt result = ((r * r_inv) - BigInt(1))/m;
+ return result;
+ }
+
+BigInt montg_trf_to_mres(const BigInt& ord_res, const BigInt& r, const BigInt& m)
+ {
+ BigInt result(ord_res);
+ result *= r;
+ result %= m;
+ return result;
+ }
+
+BigInt montg_trf_to_ordres(const BigInt& m_res, const BigInt& m, const BigInt& r_inv)
+ {
+ BigInt result(m_res);
+ result *= r_inv;
+ result %= m;
+ return result;
+ }
+
+}
+
+GFpElement::GFpElement(const BigInt& p, const BigInt& value, bool use_montgm)
+ : mp_mod(),
+ m_value(value %p),
+ m_use_montgm(use_montgm),
+ m_is_trf(false)
+ {
+ assert(mp_mod.get() == 0);
+ mp_mod = std::tr1::shared_ptr<GFpModulus>(new GFpModulus(p));
+ assert(mp_mod->m_p_dash == 0);
+ if(m_use_montgm)
+ ensure_montgm_precomp();
+ }
+
+GFpElement::GFpElement(std::tr1::shared_ptr<GFpModulus> const mod, const BigInt& value, bool use_montgm)
+ : mp_mod(),
+ m_value(value % mod->m_p),
+ m_use_montgm(use_montgm),
+ m_is_trf(false)
+ {
+ assert(mp_mod.get() == 0);
+ mp_mod = mod;
+ }
+
+GFpElement::GFpElement(const GFpElement& other)
+ : m_value(other.m_value),
+ m_use_montgm(other.m_use_montgm),
+ m_is_trf(other.m_is_trf)
+
+ {
+ //creates an independent copy
+ assert((other.m_is_trf && other.m_use_montgm) || !other.m_is_trf);
+ mp_mod.reset(new GFpModulus(*other.mp_mod)); // copy-ctor of GFpModulus
+ }
+
+void GFpElement::turn_on_sp_red_mul() const
+ {
+ ensure_montgm_precomp();
+ m_use_montgm = true;
+ }
+
+void GFpElement::turn_off_sp_red_mul() const
+ {
+ if(m_is_trf)
+ {
+ trf_to_ordres();
+ // will happen soon anyway, so we can do it here already
+ // (this is not lazy but way more secure concerning our internal logic here)
+ }
+ m_use_montgm = false;
+ }
+
+void GFpElement::ensure_montgm_precomp() const
+ {
+ if((!mp_mod->m_r.is_zero()) && (!mp_mod->m_r_inv.is_zero()) && (!mp_mod->m_p_dash.is_zero()))
+ {
+ // values are already set, nothing more to do
+ }
+ else
+ {
+ BigInt tmp_r(montgm_calc_r_oddmod(mp_mod->m_p));
+
+ BigInt tmp_r_inv(inverse_mod(tmp_r, mp_mod->m_p));
+
+ BigInt tmp_p_dash(montgm_calc_m_dash(tmp_r, mp_mod->m_p, tmp_r_inv));
+
+ mp_mod->m_r.grow_reg(tmp_r.size());
+ mp_mod->m_r_inv.grow_reg(tmp_r_inv.size());
+ mp_mod->m_p_dash.grow_reg(tmp_p_dash.size());
+
+ mp_mod->m_r = tmp_r;
+ mp_mod->m_r_inv = tmp_r_inv;
+ mp_mod->m_p_dash = tmp_p_dash;
+
+ assert(!mp_mod->m_r.is_zero());
+ assert(!mp_mod->m_r_inv.is_zero());
+ assert(!mp_mod->m_p_dash.is_zero());
+ }
+
+ }
+
+void GFpElement::set_shrd_mod(std::tr1::shared_ptr<GFpModulus> const p_mod)
+ {
+ mp_mod = p_mod;
+ }
+
+void GFpElement::trf_to_mres() const
+ {
+ if(!m_use_montgm)
+ {
+ throw Illegal_Transformation("GFpElement is not allowed to be transformed to m-residue");
+ }
+ assert(m_is_trf == false);
+ assert(!mp_mod->m_r_inv.is_zero());
+ assert(!mp_mod->m_p_dash.is_zero());
+ m_value = montg_trf_to_mres(m_value, mp_mod->m_r, mp_mod->m_p);
+ m_is_trf = true;
+ }
+
+void GFpElement::trf_to_ordres() const
+ {
+ assert(m_is_trf == true);
+ m_value = montg_trf_to_ordres(m_value, mp_mod->m_p, mp_mod->m_r_inv);
+ m_is_trf = false;
+ }
+
+bool GFpElement::align_operands_res(const GFpElement& lhs, const GFpElement& rhs) //static
+ {
+ assert(lhs.mp_mod->m_p == rhs.mp_mod->m_p);
+ if(lhs.m_use_montgm && rhs.m_use_montgm)
+ {
+ assert(rhs.mp_mod->m_p_dash == lhs.mp_mod->m_p_dash);
+ assert(rhs.mp_mod->m_r == lhs.mp_mod->m_r);
+ assert(rhs.mp_mod->m_r_inv == lhs.mp_mod->m_r_inv);
+ if(!lhs.m_is_trf && !rhs.m_is_trf)
+ {
+ return false;
+ }
+ else if(lhs.m_is_trf && rhs.m_is_trf)
+ {
+ return true;
+ }
+ else // one is transf., the other not
+ {
+ if(!lhs.m_is_trf)
+ {
+ lhs.trf_to_mres();
+ assert(rhs.m_is_trf==true);
+ return true;
+ }
+ assert(rhs.m_is_trf==false);
+ assert(lhs.m_is_trf==true);
+ rhs.trf_to_mres(); // the only possibility left...
+ return true;
+ }
+ }
+ else // at least one of them does not use mm
+ // (so it is impossible that both use it)
+ {
+ if(lhs.m_is_trf)
+ {
+ lhs.trf_to_ordres();
+ assert(rhs.m_is_trf == false);
+ return false;
+ }
+ if(rhs.m_is_trf)
+ {
+ rhs.trf_to_ordres();
+ assert(lhs.m_is_trf == false);
+ return false;
+ }
+ return false;
+ }
+ assert(false);
+ }
+
+bool GFpElement::is_trf_to_mres() const
+ {
+ return m_is_trf;
+ }
+
+const BigInt& GFpElement::get_p() const
+ {
+ return (mp_mod->m_p);
+ }
+
+const BigInt& GFpElement::get_value() const
+ {
+ if(m_is_trf)
+ {
+ assert(m_use_montgm);
+ trf_to_ordres();
+ }
+ return m_value;
+ }
+
+const BigInt& GFpElement::get_mres() const
+ {
+ if(!m_use_montgm)
+ {
+ // does the following exception really make sense?
+ // wouldn´t it be better to simply turn on montg.mult. when
+ // this explicit request is made?
+ throw Illegal_Transformation("GFpElement is not allowed to be transformed to m-residue");
+ }
+ if(!m_is_trf)
+ {
+ trf_to_mres();
+ }
+
+ return m_value;
+ }
+
+const GFpElement& GFpElement::operator=(const GFpElement& other)
+ {
+ m_value.grow_reg(other.m_value.size()); // grow first for exception safety
+
+ //m_value = other.m_value;
+
+ // m_use_montgm = other.m_use_montgm;
+ // m_is_trf = other.m_is_trf;
+ // we want to keep the member pointers, which might be part of a "sharing group"
+ // but we may not simply overwrite the BigInt values with those of the argument!!
+ // if ours already contains precomputations, it would be hazardous to
+ // set them back to zero.
+ // thus we first check for equality of the moduli,
+ // then whether either of the two objects already contains
+ // precomputed values.
+
+ // we also deal with the case were the pointers themsevles are equal:
+ if(mp_mod.get() == other.mp_mod.get())
+ {
+ // everything ok, we are in the same sharing group anyway, nothing to do
+ m_value = other.m_value; // cannot throw
+ m_use_montgm = other.m_use_montgm;
+ m_is_trf = other.m_is_trf;
+ return *this;
+ }
+ if(mp_mod->m_p != other.mp_mod->m_p)
+ {
+ // the moduli are different, this is a special case
+ // which will not occur in usual applications,
+ // so we don´t hesitate to simply create new objects
+ // (we do want to create an independent copy)
+ mp_mod.reset(new GFpModulus(*other.mp_mod)); // this could throw,
+ // and because of this
+ // we haven't modified
+ // anything so far
+ m_value = other.m_value; // can't throw
+ m_use_montgm = other.m_use_montgm;
+ m_is_trf = other.m_is_trf;
+ return *this;
+ }
+ // exception safety note: from now on we are on the safe
+ // side with respect to the modulus,
+ // so we can assign the value now:
+ m_value = other.m_value;
+ m_use_montgm = other.m_use_montgm;
+ m_is_trf = other.m_is_trf;
+ // the moduli are equal, but we deal with different sharing groups.
+ // we will NOT fuse the sharing goups
+ // and we will NOT reset already precomputed values
+ if(mp_mod->has_precomputations())
+ {
+ // our own sharing group already has precomputed values,
+ // so nothing to do.
+ return *this;
+ }
+ else
+ {
+ // let´s see whether the argument has something for us...
+ if(other.mp_mod->has_precomputations())
+ {
+ // fetch them for our sharing group
+ // exc. safety note: grow first
+ mp_mod->m_p_dash.grow_reg(other.mp_mod->m_p_dash.size());
+ mp_mod->m_r.grow_reg(other.mp_mod->m_r.size());
+ mp_mod->m_r_inv.grow_reg(other.mp_mod->m_r_inv.size());
+
+ mp_mod->m_p_dash = other.mp_mod->m_p_dash;
+ mp_mod->m_r = other.mp_mod->m_r;
+ mp_mod->m_r_inv = other.mp_mod->m_r_inv;
+ return *this;
+ }
+ }
+ // our precomputations aren´t set, the arguments neither,
+ // so we let them alone
+ return *this;
+ }
+
+void GFpElement::share_assign(const GFpElement& other)
+ {
+ assert((other.m_is_trf && other.m_use_montgm) || !other.m_is_trf);
+
+ // use grow_to to make it exc safe
+ m_value.grow_reg(other.m_value.size());
+ m_value = other.m_value;
+
+ m_use_montgm = other.m_use_montgm;
+ m_is_trf = other.m_is_trf;
+ mp_mod = other.mp_mod; // cannot throw
+ }
+
+GFpElement& GFpElement::operator+=(const GFpElement& rhs)
+ {
+ GFpElement::align_operands_res(*this, rhs);
+
+ workspace = m_value;
+ workspace += rhs.m_value;
+ if(workspace >= mp_mod->m_p)
+ workspace -= mp_mod->m_p;
+
+ m_value = workspace;
+ assert(m_value < mp_mod->m_p);
+ assert(m_value >= 0);
+
+ return *this;
+ }
+
+GFpElement& GFpElement::operator-=(const GFpElement& rhs)
+ {
+ GFpElement::align_operands_res(*this, rhs);
+
+ workspace = m_value;
+
+ workspace -= rhs.m_value;
+
+ if(workspace.is_negative())
+ workspace += mp_mod->m_p;
+
+ m_value = workspace;
+ assert(m_value < mp_mod->m_p);
+ assert(m_value >= 0);
+ return *this;
+ }
+
+GFpElement& GFpElement::operator*= (u32bit rhs)
+ {
+ workspace = m_value;
+ workspace *= rhs;
+ workspace %= mp_mod->m_p;
+ m_value = workspace;
+ return *this;
+ }
+
+GFpElement& GFpElement::operator*=(const GFpElement& rhs)
+ {
+ assert(rhs.mp_mod->m_p == mp_mod->m_p);
+ // here, we do not use align_operands_res() for one simple reason:
+ // we want to enforce the transformation to an m-residue, otherwise it would
+ // never happen
+ if(m_use_montgm && rhs.m_use_montgm)
+ {
+ assert(rhs.mp_mod->m_p == mp_mod->m_p); // is montgm. mult is on, then precomps must be there
+ assert(rhs.mp_mod->m_p_dash == mp_mod->m_p_dash);
+ assert(rhs.mp_mod->m_r == mp_mod->m_r);
+ if(!m_is_trf)
+ {
+ trf_to_mres();
+ }
+ if(!rhs.m_is_trf)
+ {
+ rhs.trf_to_mres();
+ }
+ workspace = m_value;
+ montg_mult(m_value, workspace, rhs.m_value, mp_mod->m_p, mp_mod->m_p_dash, mp_mod->m_r);
+ }
+ else // ordinary multiplication
+ {
+ if(m_is_trf)
+ {
+ assert(m_use_montgm);
+ trf_to_ordres();
+ }
+ if(rhs.m_is_trf)
+ {
+ assert(rhs.m_use_montgm);
+ rhs.trf_to_ordres();
+ }
+
+ workspace = m_value;
+ workspace *= rhs.m_value;
+ workspace %= mp_mod->m_p;
+ m_value = workspace;
+ }
+ return *this;
+ }
+
+GFpElement& GFpElement::operator/=(const GFpElement& rhs)
+ {
+ bool use_mres = GFpElement::align_operands_res(*this, rhs);
+ assert((this->m_is_trf && rhs.m_is_trf) || !(this->m_is_trf && rhs.m_is_trf));
+ // (internal note: see C86)
+ if(use_mres)
+ {
+ assert(m_use_montgm && rhs.m_use_montgm);
+ GFpElement rhs_ordres(rhs);
+ rhs_ordres.trf_to_ordres();
+ rhs_ordres.inverse_in_place();
+ workspace = m_value;
+ workspace *= rhs_ordres.get_value();
+ workspace %= mp_mod->m_p;
+ m_value = workspace;
+
+ }
+ else
+ {
+ GFpElement inv_rhs(rhs);
+ inv_rhs.inverse_in_place();
+ *this *= inv_rhs;
+ }
+ return *this;
+ }
+
+bool GFpElement::is_zero()
+ {
+ return (m_value.is_zero());
+ // this is correct because x_bar = x * r = x = 0 for x = 0
+ }
+
+GFpElement& GFpElement::inverse_in_place()
+ {
+ m_value = inverse_mod(m_value, mp_mod->m_p);
+ if(m_is_trf)
+ {
+ assert(m_use_montgm);
+
+ m_value *= mp_mod->m_r;
+ m_value *= mp_mod->m_r;
+ m_value %= mp_mod->m_p;
+ }
+ assert(m_value <= mp_mod->m_p);
+ return *this;
+ }
+
+GFpElement& GFpElement::negate()
+ {
+ m_value = mp_mod->m_p - m_value;
+ assert(m_value <= mp_mod->m_p);
+ return *this;
+ }
+
+void GFpElement::swap(GFpElement& other)
+ {
+ m_value.swap(other.m_value);
+ mp_mod.swap(other.mp_mod);
+ std::swap<bool>(m_use_montgm,other.m_use_montgm);
+ std::swap<bool>(m_is_trf,other.m_is_trf);
+ }
+
+std::ostream& operator<<(std::ostream& output, const GFpElement& elem)
+ {
+ return output << '(' << elem.get_value() << "," << elem.get_p() << ')';
+ }
+
+bool operator==(const GFpElement& lhs, const GFpElement& rhs)
+ {
+ // for effeciency reasons we firstly check whether
+ //the modulus pointers are different in the first place:
+ if(lhs.get_ptr_mod() != rhs.get_ptr_mod())
+ {
+ if(lhs.get_p() != rhs.get_p())
+ {
+ return false;
+ }
+ }
+ // so the modulus is equal, now check the values
+ bool use_mres = GFpElement::align_operands_res(lhs, rhs);
+
+ if(use_mres)
+ {
+ return (lhs.get_mres() == rhs.get_mres());
+ }
+ else
+ {
+ return(lhs.get_value() == rhs.get_value());
+ }
+ }
+
+GFpElement operator+(const GFpElement& lhs, const GFpElement& rhs)
+ {
+ // consider the case that lhs and rhs both use montgm:
+ // then += returns an element which uses montgm.
+ // thus the return value of op+ here will be an element
+ // using montgm in this case
+ // NOTE: the rhs might be transformed when using op+, the lhs never
+ GFpElement result(lhs);
+ result += rhs;
+ return result;
+ }
+
+GFpElement operator-(const GFpElement& lhs, const GFpElement& rhs)
+ {
+ GFpElement result(lhs);
+ result -= rhs;
+ return result;
+ // NOTE: the rhs might be transformed when using op-, the lhs never
+ }
+
+GFpElement operator-(const GFpElement& lhs)
+ {
+ return(GFpElement(lhs)).negate();
+ }
+
+GFpElement operator*(const GFpElement& lhs, const GFpElement& rhs)
+ {
+ // consider the case that lhs and rhs both use montgm:
+ // then *= returns an element which uses montgm.
+ // thus the return value of op* here will be an element
+ // using montgm in this case
+ GFpElement result(lhs);
+ result *= rhs;
+ return result;
+ }
+
+GFpElement operator*(const GFpElement& lhs, u32bit rhs)
+ {
+ GFpElement result(lhs);
+ result *= rhs;
+ return result;
+ }
+
+GFpElement operator*(u32bit lhs, const GFpElement& rhs)
+ {
+ return rhs*lhs;
+ }
+
+GFpElement operator/(const GFpElement& lhs, const GFpElement& rhs)
+ {
+ GFpElement result (lhs);
+ result /= rhs;
+ return result;
+ }
+
+SecureVector<byte> FE2OSP(const GFpElement& elem)
+ {
+ return BigInt::encode_1363(elem.get_value(), elem.get_p().bytes());
+ }
+
+GFpElement OS2FEP(MemoryRegion<byte> const& os, BigInt p)
+ {
+ return GFpElement(p, BigInt::decode(os.begin(), os.size()));
+ }
+
+GFpElement inverse(const GFpElement& elem)
+ {
+ return GFpElement(elem).inverse_in_place();
+ }
+
+}
+