aboutsummaryrefslogtreecommitdiffstats
path: root/src/math/ec_gfp
diff options
context:
space:
mode:
Diffstat (limited to 'src/math/ec_gfp')
-rw-r--r--src/math/ec_gfp/curve_gfp.h162
-rw-r--r--src/math/ec_gfp/info.txt16
-rw-r--r--src/math/ec_gfp/point_gfp.cpp585
-rw-r--r--src/math/ec_gfp/point_gfp.h262
4 files changed, 1025 insertions, 0 deletions
diff --git a/src/math/ec_gfp/curve_gfp.h b/src/math/ec_gfp/curve_gfp.h
new file mode 100644
index 000000000..4f339126e
--- /dev/null
+++ b/src/math/ec_gfp/curve_gfp.h
@@ -0,0 +1,162 @@
+/*
+* Elliptic curves over GF(p)
+*
+* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke
+* 2010-2011 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_GFP_CURVE_H__
+#define BOTAN_GFP_CURVE_H__
+
+#include <botan/numthry.h>
+
+namespace Botan {
+
+/**
+* This class represents an elliptic curve over GF(p)
+*/
+class BOTAN_DLL CurveGFp
+ {
+ public:
+
+ /**
+ * Create an uninitialized CurveGFp
+ */
+ CurveGFp() {}
+
+ /**
+ * Construct the elliptic curve E: y^2 = x^3 + ax + b over GF(p)
+ * @param p prime number of the field
+ * @param a first coefficient
+ * @param b second coefficient
+ */
+ CurveGFp(const BigInt& p, const BigInt& a, const BigInt& b) :
+ p(p), a(a), b(b)
+ {
+ BigInt r(BigInt::Power2, p.sig_words() * BOTAN_MP_WORD_BITS);
+
+ p_dash = (((r * inverse_mod(r, p)) - 1) / p).word_at(0);
+
+ r2 = (r * r) % p;
+ a_r = (a * r) % p;
+ b_r = (b * r) % p;
+
+ p_words = p.sig_words();
+ }
+
+ // CurveGFp(const CurveGFp& other) = default;
+ // CurveGFp& operator=(const CurveGFp& other) = default;
+
+ /**
+ * @return curve coefficient a
+ */
+ const BigInt& get_a() const { return a; }
+
+ /**
+ * @return curve coefficient b
+ */
+ const BigInt& get_b() const { return b; }
+
+ /**
+ * Get prime modulus of the field of the curve
+ * @return prime modulus of the field of the curve
+ */
+ const BigInt& get_p() const { return p; }
+
+ /**
+ * @return Montgomery parameter r^2 % p
+ */
+ const BigInt& get_r2() const { return r2; }
+
+ /**
+ * @return a * r mod p
+ */
+ const BigInt& get_a_r() const { return a_r; }
+
+ /**
+ * @return b * r mod p
+ */
+ const BigInt& get_b_r() const { return b_r; }
+
+ /**
+ * @return Montgomery parameter p-dash
+ */
+ word get_p_dash() const { return p_dash; }
+
+ /**
+ * @return p.sig_words()
+ */
+ size_t get_p_words() const { return p_words; }
+
+ /**
+ * swaps the states of *this and other, does not throw
+ * @param other curve to swap values with
+ */
+ void swap(CurveGFp& other)
+ {
+ std::swap(p, other.p);
+
+ std::swap(a, other.a);
+ std::swap(b, other.b);
+
+ std::swap(a_r, other.a_r);
+ std::swap(b_r, other.b_r);
+
+ std::swap(p_words, other.p_words);
+
+ std::swap(r2, other.r2);
+ std::swap(p_dash, other.p_dash);
+ }
+
+ /**
+ * Equality operator
+ * @param other curve to compare with
+ * @return true iff this is the same curve as other
+ */
+ bool operator==(const CurveGFp& other) const
+ {
+ /*
+ Relies on choice of R, but that is fixed by constructor based
+ on size of p
+ */
+ return (p == other.p && a_r == other.a_r && b_r == other.b_r);
+ }
+
+ private:
+ // Curve parameters
+ BigInt p, a, b;
+
+ size_t p_words; // cache of p.sig_words()
+
+ // Montgomery parameters
+ BigInt r2, a_r, b_r;
+ word p_dash;
+ };
+
+/**
+* Equality operator
+* @param lhs a curve
+* @param rhs a curve
+* @return true iff lhs is not the same as rhs
+*/
+inline bool operator!=(const CurveGFp& lhs, const CurveGFp& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+}
+
+namespace std {
+
+template<> inline
+void swap<Botan::CurveGFp>(Botan::CurveGFp& curve1,
+ Botan::CurveGFp& curve2)
+ {
+ curve1.swap(curve2);
+ }
+
+} // namespace std
+
+#endif
diff --git a/src/math/ec_gfp/info.txt b/src/math/ec_gfp/info.txt
new file mode 100644
index 000000000..e6ee1d6bf
--- /dev/null
+++ b/src/math/ec_gfp/info.txt
@@ -0,0 +1,16 @@
+define EC_CURVE_GFP
+
+load_on auto
+
+<header:public>
+curve_gfp.h
+point_gfp.h
+</header:public>
+
+<source>
+point_gfp.cpp
+</source>
+
+<requires>
+numbertheory
+</requires>
diff --git a/src/math/ec_gfp/point_gfp.cpp b/src/math/ec_gfp/point_gfp.cpp
new file mode 100644
index 000000000..04805010d
--- /dev/null
+++ b/src/math/ec_gfp/point_gfp.cpp
@@ -0,0 +1,585 @@
+/*
+* Point arithmetic on elliptic curves over GF(p)
+*
+* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke
+* 2008-2011 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/point_gfp.h>
+#include <botan/numthry.h>
+#include <botan/reducer.h>
+#include <botan/internal/mp_core.h>
+
+namespace Botan {
+
+PointGFp::PointGFp(const CurveGFp& curve) :
+ curve(curve), ws(2 * (curve.get_p_words() + 2))
+ {
+ coord_x = 0;
+ coord_y = monty_mult(1, curve.get_r2());
+ coord_z = 0;
+ }
+
+PointGFp::PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y) :
+ curve(curve), ws(2 * (curve.get_p_words() + 2))
+ {
+ coord_x = monty_mult(x, curve.get_r2());
+ coord_y = monty_mult(y, curve.get_r2());
+ coord_z = monty_mult(1, curve.get_r2());
+ }
+
+// Montgomery multiplication
+void PointGFp::monty_mult(BigInt& z, const BigInt& x, const BigInt& y) const
+ {
+ //assert(&z != &x && &z != &y);
+
+ if(x.is_zero() || y.is_zero())
+ {
+ z = 0;
+ return;
+ }
+
+ const BigInt& p = curve.get_p();
+ const size_t p_size = curve.get_p_words();
+ const word p_dash = curve.get_p_dash();
+
+ SecureVector<word>& z_reg = z.get_reg();
+ z_reg.resize(2*p_size+1);
+ zeroise(z_reg);
+
+ bigint_mul(&z_reg[0], z_reg.size(),
+ &ws[0],
+ x.data(), x.size(), x.sig_words(),
+ y.data(), y.size(), y.sig_words());
+
+ bigint_monty_redc(&z[0], z.size(),
+ &ws[0],
+ p.data(), p_size, p_dash);
+ }
+
+// Montgomery squaring
+void PointGFp::monty_sqr(BigInt& z, const BigInt& x) const
+ {
+ //assert(&z != &x);
+
+ if(x.is_zero())
+ {
+ z = 0;
+ return;
+ }
+
+ const BigInt& p = curve.get_p();
+ const size_t p_size = curve.get_p_words();
+ const word p_dash = curve.get_p_dash();
+
+ SecureVector<word>& z_reg = z.get_reg();
+ z_reg.resize(2*p_size+1);
+ zeroise(z_reg);
+
+ bigint_sqr(&z[0], z.size(),
+ &ws[0],
+ x.data(), x.size(), x.sig_words());
+
+ bigint_monty_redc(&z[0], z.size(),
+ &ws[0],
+ p.data(), p_size, p_dash);
+ }
+
+// Point addition
+void PointGFp::add(const PointGFp& rhs, std::vector<BigInt>& ws_bn)
+ {
+ if(is_zero())
+ {
+ coord_x = rhs.coord_x;
+ coord_y = rhs.coord_y;
+ coord_z = rhs.coord_z;
+ return;
+ }
+ else if(rhs.is_zero())
+ return;
+
+ const BigInt& p = curve.get_p();
+
+ BigInt& rhs_z2 = ws_bn[0];
+ BigInt& U1 = ws_bn[1];
+ BigInt& S1 = ws_bn[2];
+
+ BigInt& lhs_z2 = ws_bn[3];
+ BigInt& U2 = ws_bn[4];
+ BigInt& S2 = ws_bn[5];
+
+ BigInt& H = ws_bn[6];
+ BigInt& r = ws_bn[7];
+
+ BigInt& x = ws_bn[8];
+ BigInt& y = ws_bn[9];
+ BigInt& z = ws_bn[10];
+
+ monty_sqr(rhs_z2, rhs.coord_z);
+ monty_mult(U1, coord_x, rhs_z2);
+ monty_mult(S1, coord_y, monty_mult(rhs.coord_z, rhs_z2));
+
+ monty_sqr(lhs_z2, coord_z);
+ monty_mult(U2, rhs.coord_x, lhs_z2);
+ monty_mult(S2, rhs.coord_y, monty_mult(coord_z, lhs_z2));
+
+ H = U2;
+ H -= U1;
+ if(H.is_negative())
+ H += p;
+
+ r = S2;
+ r -= S1;
+ if(r.is_negative())
+ r += p;
+
+ if(H.is_zero())
+ {
+ if(r.is_zero())
+ {
+ mult2(ws_bn);
+ return;
+ }
+
+ *this = PointGFp(curve); // setting myself to zero
+ return;
+ }
+
+ monty_sqr(U2, H);
+
+ monty_mult(S2, U2, H);
+
+ U2 = monty_mult(U1, U2);
+
+ monty_sqr(x, r);
+ x -= S2;
+ x -= (U2 << 1);
+ while(x.is_negative())
+ x += p;
+
+ U2 -= x;
+ if(U2.is_negative())
+ U2 += p;
+
+ monty_mult(y, r, U2);
+ y -= monty_mult(S1, S2);
+ if(y.is_negative())
+ y += p;
+
+ monty_mult(z, monty_mult(coord_z, rhs.coord_z), H);
+
+ coord_x = x;
+ coord_y = y;
+ coord_z = z;
+ }
+
+// *this *= 2
+void PointGFp::mult2(std::vector<BigInt>& ws_bn)
+ {
+ if(is_zero())
+ return;
+ else if(coord_y.is_zero())
+ {
+ *this = PointGFp(curve); // setting myself to zero
+ return;
+ }
+
+ const BigInt& p = curve.get_p();
+
+ BigInt& y_2 = ws_bn[0];
+ BigInt& S = ws_bn[1];
+ BigInt& z4 = ws_bn[2];
+ BigInt& a_z4 = ws_bn[3];
+ BigInt& M = ws_bn[4];
+ BigInt& U = ws_bn[5];
+ BigInt& x = ws_bn[6];
+ BigInt& y = ws_bn[7];
+ BigInt& z = ws_bn[8];
+
+ monty_sqr(y_2, coord_y);
+
+ monty_mult(S, coord_x, y_2);
+ S <<= 2; // * 4
+ while(S >= p)
+ S -= p;
+
+ monty_sqr(z4, monty_sqr(coord_z));
+ monty_mult(a_z4, curve.get_a_r(), z4);
+
+ M = 3 * monty_sqr(coord_x);
+ M += a_z4;
+ while(M >= p)
+ M -= p;
+
+ monty_sqr(x, M);
+ x -= (S << 1);
+ while(x.is_negative())
+ x += p;
+
+ monty_sqr(U, y_2);
+ U <<= 3;
+ while(U >= p)
+ U -= p;
+
+ S -= x;
+ while(S.is_negative())
+ S += p;
+
+ monty_mult(y, M, S);
+ y -= U;
+ if(y.is_negative())
+ y += p;
+
+ monty_mult(z, coord_y, coord_z);
+ z <<= 1;
+ if(z >= p)
+ z -= p;
+
+ coord_x = x;
+ coord_y = y;
+ coord_z = z;
+ }
+
+// arithmetic operators
+PointGFp& PointGFp::operator+=(const PointGFp& rhs)
+ {
+ std::vector<BigInt> ws(11);
+ add(rhs, ws);
+ return *this;
+ }
+
+PointGFp& PointGFp::operator-=(const PointGFp& rhs)
+ {
+ PointGFp minus_rhs = PointGFp(rhs).negate();
+
+ if(is_zero())
+ *this = minus_rhs;
+ else
+ *this += minus_rhs;
+
+ return *this;
+ }
+
+PointGFp& PointGFp::operator*=(const BigInt& scalar)
+ {
+ *this = scalar * *this;
+ return *this;
+ }
+
+PointGFp operator*(const BigInt& scalar, const PointGFp& point)
+ {
+ const CurveGFp& curve = point.get_curve();
+
+ if(scalar.is_zero())
+ return PointGFp(curve); // zero point
+
+ std::vector<BigInt> ws(11);
+
+ if(scalar.abs() <= 2) // special cases for small values
+ {
+ byte value = scalar.abs().byte_at(0);
+
+ PointGFp result = point;
+
+ if(value == 2)
+ result.mult2(ws);
+
+ if(scalar.is_negative())
+ result.negate();
+
+ return result;
+ }
+
+ const size_t scalar_bits = scalar.bits();
+
+#if 0
+
+ PointGFp x1 = PointGFp(curve);
+ PointGFp x2 = point;
+
+ size_t bits_left = scalar_bits;
+
+ // Montgomery Ladder
+ while(bits_left)
+ {
+ const bool bit_set = scalar.get_bit(bits_left - 1);
+
+ if(bit_set)
+ {
+ x1.add(x2, ws);
+ x2.mult2(ws);
+ }
+ else
+ {
+ x2.add(x1, ws);
+ x1.mult2(ws);
+ }
+
+ --bits_left;
+ }
+
+ if(scalar.is_negative())
+ x1.negate();
+
+ return x1;
+
+#else
+ const size_t window_size = 4;
+
+ std::vector<PointGFp> Ps(1 << window_size);
+ Ps[0] = PointGFp(curve);
+ Ps[1] = point;
+
+ for(size_t i = 2; i != Ps.size(); ++i)
+ {
+ Ps[i] = Ps[i-1];
+ Ps[i].add(point, ws);
+ }
+
+ PointGFp H(curve); // create as zero
+ size_t bits_left = scalar_bits;
+
+ while(bits_left >= window_size)
+ {
+ for(size_t i = 0; i != window_size; ++i)
+ H.mult2(ws);
+
+ const u32bit nibble = scalar.get_substring(bits_left - window_size,
+ window_size);
+
+ H.add(Ps[nibble], ws);
+
+ bits_left -= window_size;
+ }
+
+ while(bits_left)
+ {
+ H.mult2(ws);
+ if(scalar.get_bit(bits_left-1))
+ H.add(point, ws);
+
+ --bits_left;
+ }
+
+ if(scalar.is_negative())
+ H.negate();
+
+ return H;
+#endif
+ }
+
+BigInt PointGFp::get_affine_x() const
+ {
+ if(is_zero())
+ throw Illegal_Transformation("Cannot convert zero point to affine");
+
+ const BigInt& r2 = curve.get_r2();
+
+ BigInt z2 = monty_sqr(coord_z);
+ z2 = inverse_mod(z2, curve.get_p());
+
+ z2 = monty_mult(z2, r2);
+ return monty_mult(coord_x, z2);
+ }
+
+BigInt PointGFp::get_affine_y() const
+ {
+ if(is_zero())
+ throw Illegal_Transformation("Cannot convert zero point to affine");
+
+ const BigInt& r2 = curve.get_r2();
+
+ BigInt z3 = monty_mult(coord_z, monty_sqr(coord_z));
+ z3 = inverse_mod(z3, curve.get_p());
+ z3 = monty_mult(z3, r2);
+ return monty_mult(coord_y, z3);
+ }
+
+bool PointGFp::on_the_curve() const
+ {
+ /*
+ Is the point still on the curve?? (If everything is correct, the
+ point is always on its curve; then the function will return true.
+ If somehow the state is corrupted, which suggests a fault attack
+ (or internal computational error), then return false.
+ */
+
+ if(is_zero())
+ return true;
+
+ BigInt y2 = monty_mult(monty_sqr(coord_y), 1);
+ BigInt x3 = monty_mult(coord_x, monty_sqr(coord_x));
+
+ BigInt ax = monty_mult(coord_x, curve.get_a_r());
+
+ const BigInt& b_r = curve.get_b_r();
+
+ BigInt z2 = monty_sqr(coord_z);
+
+ if(coord_z == z2) // Is z equal to 1 (in Montgomery form)?
+ {
+ if(y2 != monty_mult(x3 + ax + b_r, 1))
+ return false;
+ }
+
+ BigInt z3 = monty_mult(coord_z, z2);
+
+ BigInt ax_z4 = monty_mult(ax, monty_sqr(z2));
+
+ BigInt b_z6 = monty_mult(b_r, monty_sqr(z3));
+
+ if(y2 != monty_mult(x3 + ax_z4 + b_z6, 1))
+ return false;
+
+ return true;
+ }
+
+// swaps the states of *this and other, does not throw!
+void PointGFp::swap(PointGFp& other)
+ {
+ curve.swap(other.curve);
+ coord_x.swap(other.coord_x);
+ coord_y.swap(other.coord_y);
+ coord_z.swap(other.coord_z);
+ ws.swap(other.ws);
+ }
+
+bool PointGFp::operator==(const PointGFp& other) const
+ {
+ if(get_curve() != other.get_curve())
+ return false;
+
+ // If this is zero, only equal if other is also zero
+ if(is_zero())
+ return other.is_zero();
+
+ return (get_affine_x() == other.get_affine_x() &&
+ get_affine_y() == other.get_affine_y());
+ }
+
+// encoding and decoding
+SecureVector<byte> EC2OSP(const PointGFp& point, byte format)
+ {
+ if(point.is_zero())
+ return SecureVector<byte>(1); // single 0 byte
+
+ const size_t p_bytes = point.get_curve().get_p().bytes();
+
+ BigInt x = point.get_affine_x();
+ BigInt y = point.get_affine_y();
+
+ SecureVector<byte> bX = BigInt::encode_1363(x, p_bytes);
+ SecureVector<byte> bY = BigInt::encode_1363(y, p_bytes);
+
+ if(format == PointGFp::UNCOMPRESSED)
+ {
+ SecureVector<byte> result;
+ result.push_back(0x04);
+
+ result += bX;
+ result += bY;
+
+ return result;
+ }
+ else if(format == PointGFp::COMPRESSED)
+ {
+ SecureVector<byte> result;
+ result.push_back(0x02 | static_cast<byte>(y.get_bit(0)));
+
+ result += bX;
+
+ return result;
+ }
+ else if(format == PointGFp::HYBRID)
+ {
+ SecureVector<byte> result;
+ result.push_back(0x06 | static_cast<byte>(y.get_bit(0)));
+
+ result += bX;
+ result += bY;
+
+ return result;
+ }
+ else
+ throw Invalid_Argument("illegal point encoding format specification");
+ }
+
+namespace {
+
+BigInt decompress_point(bool yMod2,
+ const BigInt& x,
+ const CurveGFp& curve)
+ {
+ BigInt xpow3 = x * x * x;
+
+ BigInt g = curve.get_a() * x;
+ g += xpow3;
+ g += curve.get_b();
+ g = g % curve.get_p();
+
+ BigInt z = ressol(g, curve.get_p());
+
+ if(z < 0)
+ throw Illegal_Point("error during decompression");
+
+ if(z.get_bit(0) != yMod2)
+ z = curve.get_p() - z;
+
+ return z;
+ }
+
+}
+
+PointGFp OS2ECP(const byte data[], size_t data_len,
+ const CurveGFp& curve)
+ {
+ if(data_len <= 1)
+ return PointGFp(curve); // return zero
+
+ const byte pc = data[0];
+
+ BigInt x, y;
+
+ if(pc == 2 || pc == 3)
+ {
+ //compressed form
+ x = BigInt::decode(&data[1], data_len - 1);
+
+ const bool y_mod_2 = ((pc & 0x01) == 1);
+ y = decompress_point(y_mod_2, x, curve);
+ }
+ else if(pc == 4)
+ {
+ const size_t l = (data_len - 1) / 2;
+
+ // uncompressed form
+ x = BigInt::decode(&data[1], l);
+ y = BigInt::decode(&data[l+1], l);
+ }
+ else if(pc == 6 || pc == 7)
+ {
+ const size_t l = (data_len - 1) / 2;
+
+ // hybrid form
+ x = BigInt::decode(&data[1], l);
+ y = BigInt::decode(&data[l+1], l);
+
+ const bool y_mod_2 = ((pc & 0x01) == 1);
+
+ if(decompress_point(y_mod_2, x, curve) != y)
+ throw Illegal_Point("OS2ECP: Decoding error in hybrid format");
+ }
+ else
+ throw Invalid_Argument("OS2ECP: Unknown format type");
+
+ PointGFp result(curve, x, y);
+
+ if(!result.on_the_curve())
+ throw Illegal_Point("OS2ECP: Decoded point was not on the curve");
+
+ return result;
+ }
+
+}
diff --git a/src/math/ec_gfp/point_gfp.h b/src/math/ec_gfp/point_gfp.h
new file mode 100644
index 000000000..8c279dbd1
--- /dev/null
+++ b/src/math/ec_gfp/point_gfp.h
@@ -0,0 +1,262 @@
+/*
+* Point arithmetic on elliptic curves over GF(p)
+*
+* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke
+* 2008-2011 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_POINT_GFP_H__
+#define BOTAN_POINT_GFP_H__
+
+#include <botan/curve_gfp.h>
+#include <vector>
+
+namespace Botan {
+
+/**
+* Exception thrown if you try to convert a zero point to an affine
+* coordinate
+*/
+struct BOTAN_DLL Illegal_Transformation : public Exception
+ {
+ Illegal_Transformation(const std::string& err =
+ "Requested transformation is not possible") :
+ Exception(err) {}
+ };
+
+/**
+* Exception thrown if some form of illegal point is decoded
+*/
+struct BOTAN_DLL Illegal_Point : public Exception
+ {
+ Illegal_Point(const std::string& err = "Malformed ECP point detected") :
+ Exception(err) {}
+ };
+
+/**
+* This class represents one point on a curve of GF(p)
+*/
+class BOTAN_DLL PointGFp
+ {
+ public:
+ enum Compression_Type {
+ UNCOMPRESSED = 0,
+ COMPRESSED = 1,
+ HYBRID = 2
+ };
+
+ /**
+ * Construct an uninitialized PointGFp
+ */
+ PointGFp() {}
+
+ /**
+ * Construct the zero point
+ * @param curve The base curve
+ */
+ PointGFp(const CurveGFp& curve);
+
+ /**
+ * Construct a point from its affine coordinates
+ * @param curve the base curve
+ * @param x affine x coordinate
+ * @param y affine y coordinate
+ */
+ PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y);
+
+ //PointGFp(const PointGFp& other) = default;
+ //PointGFp& operator=(const PointGFp& other) = default;
+
+ /**
+ * += Operator
+ * @param rhs the PointGFp to add to the local value
+ * @result resulting PointGFp
+ */
+ PointGFp& operator+=(const PointGFp& rhs);
+
+ /**
+ * -= Operator
+ * @param rhs the PointGFp to subtract from the local value
+ * @result resulting PointGFp
+ */
+ PointGFp& operator-=(const PointGFp& rhs);
+
+ /**
+ * *= Operator
+ * @param scalar the PointGFp to multiply with *this
+ * @result resulting PointGFp
+ */
+ PointGFp& operator*=(const BigInt& scalar);
+
+ /**
+ * Multiplication Operator
+ * @param scalar the scalar value
+ * @param point the point value
+ * @return scalar*point on the curve
+ */
+ friend BOTAN_DLL PointGFp operator*(const BigInt& scalar, const PointGFp& point);
+
+ /**
+ * Negate this point
+ * @return *this
+ */
+ PointGFp& negate()
+ {
+ if(!is_zero())
+ coord_y = curve.get_p() - coord_y;
+ return *this;
+ }
+
+ /**
+ * Return base curve of this point
+ * @result the curve over GF(p) of this point
+ */
+ const CurveGFp& get_curve() const { return curve; }
+
+ /**
+ * get affine x coordinate
+ * @result affine x coordinate
+ */
+ BigInt get_affine_x() const;
+
+ /**
+ * get affine y coordinate
+ * @result affine y coordinate
+ */
+ BigInt get_affine_y() const;
+
+ /**
+ * Is this the point at infinity?
+ * @result true, if this point is at infinity, false otherwise.
+ */
+ bool is_zero() const
+ { return (coord_x.is_zero() && coord_z.is_zero()); }
+
+ /**
+ * Checks whether the point is to be found on the underlying
+ * curve; used to prevent fault attacks.
+ * @return if the point is on the curve
+ */
+ bool on_the_curve() const;
+
+ /**
+ * swaps the states of *this and other, does not throw!
+ * @param other the object to swap values with
+ */
+ void swap(PointGFp& other);
+
+ /**
+ * Equality operator
+ */
+ bool operator==(const PointGFp& other) const;
+ private:
+
+ /**
+ * Montgomery multiplication/reduction
+ * @param x first multiplicand
+ * @param y second multiplicand
+ * @param workspace temp space
+ */
+ BigInt monty_mult(const BigInt& x, const BigInt& y) const
+ {
+ BigInt result;
+ monty_mult(result, x, y);
+ return result;
+ }
+
+ /**
+ * Montgomery multiplication/reduction
+ * @warning z cannot alias x or y
+ * @param z output
+ * @param x first multiplicand
+ * @param y second multiplicand
+ */
+ void monty_mult(BigInt& z, const BigInt& x, const BigInt& y) const;
+
+ /**
+ * Montgomery squaring/reduction
+ * @param x multiplicand
+ */
+ BigInt monty_sqr(const BigInt& x) const
+ {
+ BigInt result;
+ monty_sqr(result, x);
+ return result;
+ }
+
+ /**
+ * Montgomery squaring/reduction
+ * @warning z cannot alias x
+ * @param z output
+ * @param x multiplicand
+ */
+ void monty_sqr(BigInt& z, const BigInt& x) const;
+
+ /**
+ * Point addition
+ * @param workspace temp space, at least 11 elements
+ */
+ void add(const PointGFp& other, std::vector<BigInt>& workspace);
+
+ /**
+ * Point doubling
+ * @param workspace temp space, at least 9 elements
+ */
+ void mult2(std::vector<BigInt>& workspace);
+
+ CurveGFp curve;
+ BigInt coord_x, coord_y, coord_z;
+ mutable SecureVector<word> ws; // workspace for Montgomery
+ };
+
+// relational operators
+inline bool operator!=(const PointGFp& lhs, const PointGFp& rhs)
+ {
+ return !(rhs == lhs);
+ }
+
+// arithmetic operators
+inline PointGFp operator-(const PointGFp& lhs)
+ {
+ return PointGFp(lhs).negate();
+ }
+
+inline PointGFp operator+(const PointGFp& lhs, const PointGFp& rhs)
+ {
+ PointGFp tmp(lhs);
+ return tmp += rhs;
+ }
+
+inline PointGFp operator-(const PointGFp& lhs, const PointGFp& rhs)
+ {
+ PointGFp tmp(lhs);
+ return tmp -= rhs;
+ }
+
+inline PointGFp operator*(const PointGFp& point, const BigInt& scalar)
+ {
+ return scalar * point;
+ }
+
+// encoding and decoding
+SecureVector<byte> BOTAN_DLL EC2OSP(const PointGFp& point, byte format);
+
+PointGFp BOTAN_DLL OS2ECP(const byte data[], size_t data_len,
+ const CurveGFp& curve);
+
+inline PointGFp OS2ECP(const MemoryRegion<byte>& data, const CurveGFp& curve)
+ { return OS2ECP(&data[0], data.size(), curve); }
+
+}
+
+namespace std {
+
+template<>
+inline void swap<Botan::PointGFp>(Botan::PointGFp& x, Botan::PointGFp& y)
+ { x.swap(y); }
+
+}
+
+#endif