00001
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #ifndef LIBECC_POINT_H
00033 #define LIBECC_POINT_H
00034
00035 #include <gmpxx.h>
00036 #include <libecc/polynomial.h>
00037 #include <libecc/rds.h>
00038
00039 namespacelibecc {
00040
00041 enum order_algorithm {
00042 order_brute_force,
00043 order_default = order_brute_force
00044 };
00045
00056 template<typename Polynomial, Polynomial const& a, Polynomial const& b>
00057 classpoint {
00058 public:
00062 typedef Polynomial polynomial_type;
00063 private:
00064 polynomial_type M_x;
00065 polynomial_type M_y;
00066 bool M_zero;
00067 public:
00071 point(void) : M_zero(true) { }
00077 point(std::string x, std::string y) : M_x(x), M_y(y), M_zero(false) { }
00081 point(polynomial_type const& x, polynomial_type const& y) : M_x(x), M_y(y), M_zero(false) { }
00085 point& operator=(point const& p1);
00089 point& operator+=(point const& p1);
00093 void MULTIPLY_and_assign(point const& pnt, mpz_class const& scalar);
00097 mpz_class order(order_algorithm algorithm = order_default) const;
00103 bool operator==(point const& p1) const;
00109 bool operator!=(point const& p1) const;
00115 bool check(void) const;
00121 polynomial_type const& get_x(void) const{ return M_x; }
00127 polynomial_type const& get_y(void) const{ return M_y; }
00131 bool is_zero(void) const{ return M_zero; }
00135 void print_on(std::ostream& os) const;
00139 void randomize(rds& random_source);
00140 };
00141
00142 template<typename Polynomial, Polynomial const& a, Polynomial const& b>
00143 void
00144 point<Polynomial, a, b>::randomize(rds& random_source)
00145 {
00146 M_zero = false;
00147 for(bool notdone = true; notdone;)
00148 {
00149 random_source.read(M_x.get_bitset());
00150 bitset_digit_t x2buf[polynomial_type::square_digits];
00151 polynomial_type& x2 = M_x.square(x2buf);
00152 polynomial_type r((M_x + a) * x2 + b);
00153 try
00154 {
00155 M_y = polynomial_type(M_x, r);
00156 notdone = false;
00157 }
00158 catch(std::domain_error const&)
00159 {
00160 }
00161 }
00162 bitset_digit_t digit;
00163 random_source.read(&digit, 1);
00164 if ((digit & 1))
00165 {
00166 if (!M_x.get_bitset().any())
00167 M_zero = true;
00168 else
00169 M_y += M_x;
00170 }
00171 }
00172
00173 template<typename Polynomial, Polynomial const& a, Polynomial const& b>
00174 bool
00175 point<Polynomial, a, b>::check(void) const
00176 {
00177 if (M_zero)
00178 return true;
00179 bitset_digit_t x2buf[polynomial_type::square_digits];
00180 polynomial_type& x2 = M_x.square(x2buf);
00181 polynomial_type r((M_x + a) * x2 + b);
00182 bitset_digit_t y2buf[polynomial_type::square_digits];
00183 polynomial_type& y2 = M_y.square(y2buf);
00184 polynomial_type l(y2 + M_x * M_y);
00185 return (r == l);
00186 }
00187
00188 template<typename Polynomial, Polynomial const& a, Polynomial const& b>
00189 inline bool
00190 point<Polynomial, a, b>::operator!=(point const& p1) const
00191 {
00192 return (M_zero != p1.M_zero || (!M_zero && (M_x != p1.M_x || M_y != p1.M_y)));
00193 }
00194
00195 template<typename Polynomial, Polynomial const& a, Polynomial const& b>
00196 inline bool
00197 point<Polynomial, a, b>::operator==(point const& p1) const
00198 {
00199 return !operator!=(p1);
00200 }
00201
00202 template<typename Polynomial, Polynomial const& a, Polynomial const& b>
00203 std::ostream&
00204 operator<<(std::ostream& os, point<Polynomial, a, b> const& p1)
00205 {
00206 if (p1.is_zero())
00207 os << "O";
00208 else
00209 os << '(' << p1.get_x() << ", " << p1.get_y() << ')';
00210 return os;
00211 }
00212
00213 template<typename Polynomial, Polynomial const& a, Polynomial const& b>
00214 void
00215 point<Polynomial, a, b>::print_on(std::ostream& os) const
00216 {
00217 if (M_zero)
00218 os << "O";
00219 else
00220 os << '(' << M_x << ", " << M_y << ')';
00221 }
00222
00223 template<typename Polynomial, Polynomial const& a, Polynomial const& b>
00224 point<Polynomial, a, b>&
00225 point<Polynomial, a, b>::operator=(point<Polynomial, a, b> const& p1)
00226 {
00227 M_zero = p1.M_zero;
00228 if (!M_zero)
00229 {
00230 M_x = p1.M_x;
00231 M_y = p1.M_y;
00232 }
00233 return *this;
00234 }
00235
00236 template<typename Polynomial, Polynomial const& a, Polynomial const& b>
00237 void
00238 point<Polynomial, a, b>::MULTIPLY_and_assign(point<Polynomial, a, b> const& pnt, mpz_class const& scalar)
00239 {
00240 point tmp(pnt);
00241 M_zero = true;
00242 unsigned long int p = 0;
00243 size_t end = mpz_sizeinbase(scalar.get_mpz_t(), 2);
00244 for (unsigned long int bit = mpz_scan1(scalar.get_mpz_t(), 0); bit < end; bit = mpz_scan1(scalar.get_mpz_t(), bit + 1))
00245 {
00246 for (; p < bit; ++p)
00247 tmp += tmp;
00248 *this += tmp;
00249 }
00250 }
00251
00252 template<typename Polynomial, Polynomial const& a, Polynomial const& b>
00253 point<Polynomial, a, b>&
00254 point<Polynomial, a, b>::operator+=(point<Polynomial, a, b> const& p1)
00255 {
00256 if (!p1.M_zero)
00257 {
00258 if (M_zero)
00259 {
00260 M_x = p1.M_x;
00261 M_y = p1.M_y;
00262 M_zero = false;
00263 }
00264 else if (M_x != p1.M_x)
00265 {
00266 polynomial_type s = M_y + p1.M_y;
00267 s /= M_x + p1.M_x;
00268 bitset_digit_t s2buf[polynomial_type::square_digits];
00269 polynomial_type& new_x = s.square(s2buf);
00270 new_x += s + M_x;
00271 new_x += p1.M_x + a;
00272 M_y += s * (M_x + new_x) + new_x;
00273 M_x = new_x;
00274 }
00275 else if (M_y == p1.M_y && M_x.get_bitset().any())
00276 {
00277 polynomial_type s = M_x + M_y / M_x;
00278 bitset_digit_t s2buf[polynomial_type::square_digits];
00279 polynomial_type& new_x = s.square(s2buf);
00280 new_x += s + a;
00281 bitset_digit_t x2buf[polynomial_type::square_digits];
00282 polynomial_type& x2 = M_x.square(x2buf);
00283 M_y = x2 + new_x * (s + polynomial_type::unity());
00284 M_x = new_x;
00285 }
00286 else
00287 M_zero = true;
00288 }
00289 return *this;
00290 }
00291
00292 template<typename Polynomial, Polynomial const& a, Polynomial const& b>
00293 mpz_class
00294 point<Polynomial, a, b>::order(order_algorithm algorithm) const
00295 {
00296 mpz_class n = 1;
00297 switch(algorithm)
00298 {
00299 case order_brute_force:
00300 {
00301 point nP(*this);
00302 while(!nP.M_zero && nP.M_x.get_bitset().any())
00303 {
00304 nP += *this;
00305 ++n;
00306 }
00307 if (!nP.M_zero)
00308 n += n;
00309 break;
00310 }
00311 }
00312 return n;
00313 }
00314
00315 }
00316
00317 #endif // LIBECC_POINT_H