diff options
Diffstat (limited to 'src/math/ec_gfp')
-rw-r--r-- | src/math/ec_gfp/curve_gfp.h | 162 | ||||
-rw-r--r-- | src/math/ec_gfp/info.txt | 16 | ||||
-rw-r--r-- | src/math/ec_gfp/point_gfp.cpp | 585 | ||||
-rw-r--r-- | src/math/ec_gfp/point_gfp.h | 262 |
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 |