├── .codeclimate.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── auto ├── cpp ├── Makefile ├── README.md ├── bin │ └── .gitkeep ├── includes │ ├── EC.h │ ├── EF.h │ ├── FF.h │ └── ecpy_native.h ├── py │ ├── ecpy │ │ └── native │ │ │ ├── EC.py │ │ │ ├── EF.py │ │ │ ├── FF.py │ │ │ ├── __init__.py │ │ │ ├── library.py │ │ │ └── method.py │ └── setup.py ├── src │ ├── EC_interface.cpp │ ├── EF.cpp │ ├── EF_interface.cpp │ ├── FF.cpp │ ├── FF_interface.cpp │ └── ecpy_native.cpp └── test │ ├── .gitignore │ ├── Makefile │ ├── bin │ └── .gitkeep │ ├── test.cpp │ └── test.py ├── ecpy ├── __init__.py ├── elliptic_curve │ ├── EllipticCurve.py │ ├── EllipticCurveRepository.py │ ├── __init__.py │ ├── pairing.py │ └── sssa_attack.py ├── fields │ ├── ComplexField.py │ ├── ExtendedFiniteField.py │ ├── Field.py │ ├── FiniteField.py │ ├── FractionField.py │ ├── RationalField.py │ ├── RealField.py │ ├── Zmod.py │ └── __init__.py ├── rings │ ├── CommutativeRing.py │ ├── Integer.py │ ├── QuotientRing.py │ ├── Ring.py │ ├── __init__.py │ ├── polynomial_multi.py │ └── polynomial_uni.py └── utils │ ├── __init__.py │ ├── root.py │ └── util.py ├── examples ├── boneh_lynn_shacham_short_signature.py ├── ecdsa.py └── id_based_encryption.py ├── note.md ├── scripts ├── bench_pairing.py ├── graph_test.py ├── schoof.py └── test.py ├── setup.cfg └── setup.py /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | radon: 3 | enabled: true 4 | config: 5 | python_version: 2 6 | threshold: "D" 7 | 8 | ratings: 9 | paths: 10 | - "**.py" 11 | - "**.cpp" 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | *.pyc 31 | *.sage.py 32 | !.gitkeep 33 | .python-version 34 | 35 | **/build/* 36 | **/*.egg-info/** 37 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | language: python 3 | python: 4 | - "2.7" 5 | - "3.7" 6 | before_install: 7 | - "sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test -y" 8 | - "sudo apt-get update -qq" 9 | - "sudo apt-get install build-essential g++-4.8 libboost-dev libgmp-dev libgmpxx* valgrind -y" 10 | install: 11 | - "pip install ." 12 | script: 13 | - "python ./scripts/test.py" 14 | - "cd cpp" 15 | - "make CC=g++-4.8 LD=g++-4.8 OPTFLAGS= test" 16 | - "cd .." 17 | - "python ./scripts/test.py" 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Shiho Midorikawa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ecpy 2 | [![Code Climate](https://codeclimate.com/github/elliptic-shiho/ecpy/badges/gpa.svg)](https://codeclimate.com/github/elliptic-shiho/ecpy) 3 | [![Build Status](http://travis-ci.org/elliptic-shiho/ecpy.svg?branch=master)](https://travis-ci.org/elliptic-shiho/ecpy) 4 | 5 | Elliptic-Curve Cryptography Library (Implemented by Python) 6 | 7 | # Features 8 | * Calculation between elliptic curve points 9 | - Elliptic curve\: `y^2 = x^3 + ax + b` over Field `K` (`char(K) != 2, 3`). 10 | - You can choose K from below: 11 | + Complex Field, Rational Field, FiniteField and Extended Finite Field(Irreducible polynomial: `x^2 + 1` or `x^2 + x + 1`) 12 | * Weil/Tate Pairing 13 | - Distortion Map, symmetric-pairing functions 14 | * SSSA-Attack Implementation 15 | - [Sample](https://gist.github.com/elliptic-shiho/40d42dbab87065e06d6c473ef93e244e) (CTF Challenge Writeup) 16 | * Example Applications 17 | - `example/id_based_encryption.py`: Implementation of Boneh-Franklin's Identity-based Encryption Scheme 18 | - `example/boneh_lynn_shacham_short_signature.py`: Implementation of Boneh-Lynn-Shacham's Short Signature Scheme 19 | - `example/ecdsa.py`: Implementation of ECDSA Signature Scheme 20 | 21 | # Setup 22 | 23 | ``` 24 | > git clone https://github.com/elliptic-shiho/ecpy && cd ecpy 25 | > pip install --upgrade . 26 | ``` 27 | 28 | ## Require modules: 29 | * six 30 | 31 | If installed following modules, `ecpy` uses that. 32 | 33 | * `gmpy2` 34 | * `primefac` or [primefac-fork](https://github.com/elliptic-shiho/primefac-fork/) 35 | 36 | # Setup with Native modules 37 | `ecpy` has a native module. If you want to speed-up ecpy, you can use that. 38 | 39 | ``` 40 | > cd ecpy/cpp 41 | > make 42 | > sudo make install 43 | ``` 44 | 45 | The description is here: [cpp/README.md](cpp/README.md) 46 | 47 | # Speed 48 | See `bench_pairing.py` . 49 | 50 | ``` 51 | Sat Jan 28 03:55:47 JST 2017 ~/prog/lab/mathematics/ecpy 100% 52 | > time python scripts/bench_pairing.py 53 | [+] found gmpy! use gmpy.is_prime 54 | [+] Found native module! 55 | Point (25 : 5635866983L + 11271733966Lw : 1) on Elliptic Curve y^2 = x^3 + 1 over ExtendedFiniteField(13208557577, "x^2+x+1") 56 | [+] Weil Pairing: 57 | weil: 14744.50 usec/pass 58 | weil: 14842.80 usec/pass 59 | weil: 14626.05 usec/pass 60 | weil: 14773.50 usec/pass 61 | weil: 14582.25 usec/pass 62 | weil: 14560.95 usec/pass 63 | weil: 14622.40 usec/pass 64 | weil: 15073.19 usec/pass 65 | weil: 14874.60 usec/pass 66 | weil: 14695.20 usec/pass 67 | [+] Tate Pairing: 68 | tate: 3079.89 usec/pass 69 | tate: 3083.21 usec/pass 70 | tate: 3079.10 usec/pass 71 | tate: 3072.70 usec/pass 72 | tate: 3069.81 usec/pass 73 | tate: 3089.30 usec/pass 74 | tate: 3077.90 usec/pass 75 | tate: 3116.00 usec/pass 76 | tate: 3095.35 usec/pass 77 | tate: 3193.65 usec/pass 78 | ================================================================ 79 | weil: 14739.54 usec/pass 80 | tate: 3095.69 usec/pass 81 | 82 | real 0m4.293s 83 | user 0m4.256s 84 | sys 0m0.012s 85 | ``` 86 | 87 | # Special Thanks 88 | Cybozu Labs Youth (5th, 6th) - http://labs.cybozu.co.jp/youth.html 89 | 90 | # License 91 | This software released under MIT License. Please see /LICENSE. 92 | 93 | -------------------------------------------------------------------------------- /auto: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | pip install --upgrade . 4 | time python scripts/test.py 5 | 6 | time python scripts/bench_pairing.py 7 | -------------------------------------------------------------------------------- /cpp/Makefile: -------------------------------------------------------------------------------- 1 | TARGET := libecpy_native.so 2 | CC := g++ 3 | LD := g++ 4 | LDFLAGS := -lgmp -lgmpxx 5 | CFLAGS := -Iincludes/ 6 | OPTFLAGS := -O2 -Os -mtune=corei7 -mavx -g 7 | GFLAGS := -fPIC -shared -std=c++11 -DPIC -g -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wswitch-default -Wundef -Wno-unused # -stdlib=libc++ <= if use clang++ 8 | OBJS := ecpy_native.o FF.o FF_interface.o EF.o EF_interface.o EC_interface.o 9 | CP := cp 10 | DESTDIR := /usr/local/lib/ 11 | SUDO := sudo 12 | PIP := pip 13 | 14 | 15 | vpath %.cpp src/ 16 | vpath %.h includes/ 17 | vpath %.hpp includes/ 18 | vpath %.o bin/ 19 | export OBJS LDFLAGS 20 | 21 | .PHONY: all 22 | all: bin/$(TARGET) 23 | 24 | bin/$(TARGET): $(OBJS) 25 | $(LD) -o $@ $(addprefix bin/,$(OBJS)) $(LDFLAGS) $(OPTFLAGS) $(GFLAGS) 26 | 27 | %.o: %.cpp includes/* 28 | $(CC) $(CFLAGS) -c -o bin/$@ $< $(OPTFLAGS) $(GFLAGS) 29 | 30 | .PHONY: install 31 | install: bin/$(TARGET) 32 | $(SUDO) $(CP) -rf bin/$(TARGET) $(DESTDIR) 33 | $(PIP) install --upgrade py/ 34 | 35 | .PHONY: test 36 | test: install 37 | $(MAKE) -C test all 38 | -------------------------------------------------------------------------------- /cpp/README.md: -------------------------------------------------------------------------------- 1 | ecpy Native Module 2 | ==================== 3 | 4 | # What 5 | This is Native module of [ecpy](https://github.com/elliptic-shiho/ecpy/). 6 | 7 | # How 8 | 9 | ``` 10 | > make 11 | > sudo make install 12 | > cd py 13 | > pip install --upgrade . 14 | ``` 15 | 16 | # Requirements 17 | * g++ 18 | - require C++11 ~ Support 19 | * GNU MP 20 | -------------------------------------------------------------------------------- /cpp/bin/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elliptic-shiho/ecpy/8813b38f134ee6db388f9504a3e7c2fd7cdc9679/cpp/bin/.gitkeep -------------------------------------------------------------------------------- /cpp/includes/EC.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ecpy_native.h" 3 | 4 | template 5 | struct EC_elem; 6 | 7 | template 8 | struct EC { 9 | const T& base; 10 | mpz_class a, b; 11 | 12 | EC(const T& base, const mpz_class& a, const mpz_class& b) : base(base), a(a), b(b) {} 13 | 14 | EC() = default; 15 | ~EC() = default; 16 | EC(const EC& ec) : base(ec.base), a(ec.a), b(ec.b) {}; 17 | EC(EC&& ec) : base(std::move(ec.base)), a(std::move(ec.a)), b(std::move(ec.b)) {}; 18 | EC& operator=(const EC& ec); 19 | EC& operator=(EC&& ec); 20 | 21 | template 22 | void add(EC_elem& ret, const EC_elem& a, const EC_elem& b) const; 23 | template 24 | void sub(EC_elem& ret, const EC_elem& a, const EC_elem& b) const; 25 | template 26 | void neg(EC_elem& ret, const EC_elem& a) const; 27 | template 28 | void mul(EC_elem& ret, const EC_elem& a, const mpz_class& b) const; 29 | template 30 | bool equ(const EC_elem& a, const EC_elem& b) const; 31 | 32 | // ----------------- UNDEFINED(DELETED) ----------------- 33 | template 34 | void mul(EC_elem& ret, const EC_elem& a, const EC_elem& b) const = delete; 35 | template 36 | void div(EC_elem& ret, const EC_elem& a, const EC_elem& b) const = delete; 37 | template 38 | void pow(EC_elem& ret, const EC_elem& a, const mpz_class& b) const = delete; 39 | // ------------------------------------------------------ 40 | 41 | template 42 | EC_elem to_affine(const EC_elem& elem) const; 43 | template 44 | E line_coeff(const EC_elem& P, const EC_elem& Q) const; 45 | template 46 | bool is_on_curve(const EC_elem& elem) const; 47 | template 48 | bool is_infinity(const EC_elem& P) const; 49 | template 50 | EC_elem random_point() const; 51 | EC* clone() const; 52 | std::string to_string() const; 53 | }; 54 | 55 | template 56 | struct EC_elem { 57 | T x, y, z; 58 | 59 | EC_elem(const mpz_class& x, const mpz_class& y, const mpz_class& z) : x(x), y(y), z(z) {} 60 | EC_elem(const T& x, const T& y, const T& z) : x(x), y(y), z(z) {} 61 | 62 | EC_elem() = default; 63 | ~EC_elem() = default; 64 | EC_elem(const EC_elem& ee) : x(ee.x), y(ee.y), z(ee.z) {}; 65 | EC_elem(EC_elem&& ee) : x(std::move(ee.x)), y(std::move(ee.y)), z(std::move(ee.z)) {}; 66 | EC_elem& operator=(const EC_elem&); 67 | EC_elem& operator=(EC_elem&&); 68 | 69 | EC_elem* clone() const; 70 | std::string to_string() const; 71 | }; 72 | 73 | template 74 | template 75 | void EC::add(EC_elem& ret, const EC_elem& a, const EC_elem& b) const { 76 | const static E zero {0}; 77 | const static E one {1}; 78 | const static E two {2}; 79 | const static E three{3}; 80 | const static E four {4}; 81 | const static E eight{8}; 82 | if (is_infinity(a)) { 83 | ret = b; 84 | } else if (is_infinity(b)) { 85 | ret = a; 86 | } else { 87 | E t; 88 | base.add(t, a.y, b.y); 89 | E c_a {this->a}; 90 | if (base.equ(a.x, b.x) && base.equ(t, zero)) { 91 | ret = EC_elem(zero, one, zero); 92 | } else { 93 | E Rx, Ry, Rz; 94 | if (equ(a, b)) { 95 | E p, q, u, v, yv, yv4, w; 96 | base.mul(p, three, a.x); // 3x 97 | base.mul(p, p, a.x); // 3x^2 98 | base.mul(q, c_a, a.z); // az 99 | base.mul(q, q, a.z); // az^2 100 | base.add(u, p, q); // 3x^2 + az^2 101 | 102 | base.mul(v, a.y, a.z); // yz 103 | 104 | base.mul(yv, a.y, v); // yv 105 | 106 | base.mul(yv4, yv, four); // 4yv 107 | 108 | base.mul(p, u, u); // u^2 109 | base.mul(q, two, a.x); // 2x 110 | base.mul(q, q, yv4); // 2x * yv4 111 | base.sub(w, p, q); // u^2 - 2x * yv4 112 | 113 | base.mul(p, two, v); // 2v 114 | base.mul(Rx, p, w); // 2vw 115 | 116 | base.mul(p, a.x, yv4); // x*yv4 117 | base.sub(p, p, w); // x*yv4 - w 118 | base.mul(p, u, p); // u(x*yv4 - w) 119 | base.mul(q, eight, yv); // 8yv 120 | base.mul(q, q, yv); // 8yv^2 121 | base.sub(Ry, p, q); // u(x*yv4 - w) - 8yv^2 122 | 123 | base.mul(p, eight, v); // 8v 124 | base.mul(q, v, v); // v^2 125 | base.mul(Rz, p, q); // 8v^3 126 | } else { 127 | E p, q, r, u, v, v2, v3, w; 128 | base.mul(p, b.y, a.z); // ByAz 129 | base.mul(q, a.y, b.z); // AyBz 130 | base.sub(u, p, q); // ByAz - AyBz 131 | 132 | base.mul(p, b.x, a.z); // BxAz 133 | base.mul(q, a.x, b.z); // AxBz 134 | base.sub(v, p, q); // BxAz - AxBz 135 | 136 | base.mul(v2, v, v); // v^2 137 | 138 | base.mul(v3, v2, v); // v^3 139 | 140 | base.mul(p, u, u); // u^2 141 | base.mul(q, a.z, b.z); // AzBz 142 | base.mul(p, p, q); // u^2 AzBz 143 | base.sub(p, p, v3); // u^2 AzBz - v3 144 | base.mul(q, two, v2); // 2 v2 145 | base.mul(r, a.x, b.z); // AxBz 146 | base.mul(q, q, r); // 2 Ax Bz v2 147 | base.sub(w, p, q); // u^2 AzBz - v3 - 2 Ax Bz v2 148 | 149 | base.mul(Rx, v, w); // vw 150 | 151 | base.mul(p, v2, a.x); // Ax v2 152 | base.mul(p, p, b.z); // Ax Bz v2 153 | base.sub(p, p, w); // Ax Bz v2 - w 154 | base.mul(p, p, u); // u(Ax Bz v2 - w) 155 | base.mul(q, v3, a.y); // Ay v3 156 | base.mul(q, q, b.z); // Ay Bz v3 157 | base.sub(Ry, p, q); // u(Ax Bz v2 - w) - Ay Bz v3 158 | 159 | base.mul(p, v3, a.z); // Az v3 160 | base.mul(Rz, p, b.z); // Az Bz v3 161 | } 162 | if (!base.equ(Rz, zero)) { 163 | ret.x = Rx; 164 | ret.y = Ry; 165 | ret.z = Rz; 166 | } else { 167 | ret = EC_elem(zero, one, zero); 168 | } 169 | } 170 | } 171 | } 172 | 173 | template 174 | template 175 | void EC::sub(EC_elem& ret, const EC_elem& a, const EC_elem& b) const { 176 | EC_elem b_; 177 | neg(b_, b); 178 | add(ret, a, b_); // a-b 179 | } 180 | 181 | template 182 | template 183 | void EC::neg(EC_elem& ret, const EC_elem& a) const { 184 | const static E zero {0}; 185 | EC_elem a_ { a }; 186 | base.sub(a_.y, zero, a_.y); // -a 187 | ret = a_; 188 | } 189 | 190 | template 191 | template 192 | void EC::mul(EC_elem& ret, const EC_elem& a, const mpz_class& b) const { 193 | const static E zero {0}; 194 | const static E one {1}; 195 | mpz_class m = b; 196 | if (m < 0) { 197 | m = -m; 198 | neg(ret, a); 199 | } else if (m == 0) { 200 | ret = {zero, one, zero}; 201 | } else if (m == 1) { 202 | ret = {a}; 203 | } else if (m == 2) { 204 | add(ret, a, a); 205 | } else { 206 | EC_elem P {a}; 207 | EC_elem Q = {zero, one, zero}; 208 | while (m != 0) { 209 | if ((m&1) == 1) { 210 | add(Q, Q, P); 211 | } 212 | add(P, P, P); 213 | m >>= 1; 214 | } 215 | ret = Q; 216 | } 217 | } 218 | 219 | template 220 | template 221 | bool EC::equ(const EC_elem& a, const EC_elem& b) const { 222 | E p, q; 223 | base.mul(p, a.x, b.y); 224 | base.mul(q, a.y, b.x); 225 | return base.equ(p, q); 226 | } 227 | 228 | template 229 | template 230 | bool EC::is_infinity(const EC_elem& P) const { 231 | static E zero {0}; 232 | static E one {1}; 233 | return base.equ(P.x, zero) && base.equ(P.y, one) && base.equ(P.z, zero); 234 | } 235 | 236 | template 237 | template 238 | bool EC::is_on_curve(const EC_elem& P) const { 239 | E p, q, r, s, t; 240 | base.mul(p, P.y, P.y); // y^2 241 | base.mul(p, p, P.z); // y^2z 242 | 243 | base.mul(q, P.x, P.x); // x^2 244 | base.mul(q, q, P.x); // x^3 245 | base.mul(r, a, P.x); // ax 246 | base.mul(r, r, P.z); // axz 247 | base.mul(r, r, P.z); // axz^2 248 | 249 | base.add(q, q, r); // x^3 + axz^2 250 | 251 | base.mul(r, b, P.z); // bz 252 | base.mul(r, r, P.z); // bz^2 253 | base.mul(r, r, P.z); // bz^3 254 | 255 | base.add(q, q, r); // x^3 + axz^2 + bz^3 256 | return base.equ(p, q); 257 | } 258 | 259 | template 260 | EC_elem& EC_elem::operator=(const EC_elem& other) { 261 | x = other.x; 262 | y = other.y; 263 | z = other.z; 264 | return (*this); 265 | } 266 | 267 | template 268 | EC_elem& EC_elem::operator=(EC_elem&& other) { 269 | x = std::move(other.x); 270 | y = std::move(other.y); 271 | z = std::move(other.z); 272 | return (*this); 273 | } 274 | 275 | template 276 | EC_elem* EC_elem::clone() const { 277 | return new EC_elem(*this); 278 | } 279 | 280 | template 281 | std::string EC_elem::to_string() const { 282 | std::stringstream ss; 283 | ss << "EC_elem(" 284 | << x.to_string() 285 | << ", " 286 | << y.to_string() 287 | << ", " 288 | << z.to_string() 289 | << ")"; 290 | return ss.str(); 291 | } 292 | 293 | template 294 | template 295 | EC_elem EC::to_affine(const EC_elem& elem) const { 296 | EC_elem ret = elem; 297 | base.div(ret.x, ret.x, ret.z); 298 | base.div(ret.y, ret.y, ret.z); 299 | ret.z = 1; 300 | return ret; 301 | } 302 | 303 | template 304 | template 305 | E EC::line_coeff(const EC_elem& P, const EC_elem& Q) const { 306 | const static E two {2}; 307 | const static E three {3}; 308 | E p, q, r; 309 | base.mul(p, P.x, Q.z); 310 | base.mul(q, P.z, Q.x); 311 | if (base.equ(p, q)) { 312 | base.mul(p, P.x, P.x); // x^2 313 | base.mul(p, p, three); // 3x^2 314 | base.mul(q, a, P.z); // az 315 | base.mul(q, q, P.z); // az^2 316 | base.add(p, p, q); // 3x^2+az^2 317 | 318 | base.mul(q, P.y, P.z); // yz 319 | base.mul(q, q, two); // 2yz 320 | 321 | base.div(p, p, q); // (3x^2+az^2) / (2yz) 322 | } else { 323 | base.mul(p, P.z, Q.y); // PzQy 324 | base.mul(q, P.y, Q.z); // PyQz 325 | base.sub(p, p, q); // PzQy - PyQz 326 | 327 | base.mul(q, P.z, Q.x); // PzQx 328 | base.mul(r, P.x, Q.z); // PxQz 329 | base.sub(q, q, r); // PzQx - PxQz 330 | 331 | base.div(p, p, q); // (PzQy - PyQz) / (PzQx - PxQz) 332 | } 333 | return p; 334 | } 335 | 336 | template 337 | EC& EC::operator=(const EC& other) { 338 | base = other.base; 339 | a = other.a; 340 | b = other.b; 341 | return (*this); 342 | } 343 | 344 | template 345 | EC& EC::operator=(EC&& other) { 346 | base = std::move(other.base); 347 | a = std::move(other.a); 348 | b = std::move(other.b); 349 | return (*this); 350 | } 351 | 352 | template 353 | EC* EC::clone() const { 354 | return new EC(*this); 355 | } 356 | 357 | template 358 | std::string EC::to_string() const { 359 | std::stringstream ss; 360 | ss << "Elliptic Curve: y^2 = x^3"; 361 | if (a != 0) { 362 | ss << " + "; 363 | if (a != 1) { 364 | ss << a; 365 | } 366 | ss << "x"; 367 | } 368 | if (b != 0) { 369 | ss << " + " << b; 370 | } 371 | ss << " over " << base.to_string(); 372 | return ss.str(); 373 | } 374 | 375 | extern "C" { 376 | // create EC instance 377 | EC *EC_FF_create(const char *a, const char *b, const FF *base); 378 | // delete EC instance 379 | void EC_FF_delete(const EC* obj); 380 | // ret = a + b 381 | void EC_FF_add(const EC *obj, EC_elem *ret, const EC_elem *a, const EC_elem *b); 382 | // ret = a - b 383 | void EC_FF_sub(const EC *obj, EC_elem *ret, const EC_elem *a, const EC_elem *b); 384 | // ret = a * b 385 | void EC_FF_mul(const EC *obj, EC_elem *ret, const EC_elem *a, const char *b); 386 | // a == b 387 | int EC_FF_equ(const EC *obj, const EC_elem *a, const EC_elem *b); 388 | // to python __str__ function 389 | void EC_FF_to_string(const EC *obj, char *ptr, int len); 390 | }; 391 | 392 | extern "C" { 393 | // create EC instance 394 | EC *EC_EF_create(const char *a, const char *b, const EF *base); 395 | // delete EC instance 396 | void EC_EF_delete(const EC* obj); 397 | // ret = a + b 398 | void EC_EF_add(const EC *obj, EC_elem *ret, const EC_elem *a, const EC_elem *b); 399 | // ret = a - b 400 | void EC_EF_sub(const EC *obj, EC_elem *ret, const EC_elem *a, const EC_elem *b); 401 | // ret = a * b 402 | void EC_EF_mul(const EC *obj, EC_elem *ret, const EC_elem *a, const char *b); 403 | // a == b 404 | int EC_EF_equ(const EC *obj, const EC_elem *a, const EC_elem *b); 405 | // to python __str__ function 406 | void EC_EF_to_string(const EC *obj, char *ptr, int len); 407 | }; 408 | 409 | extern "C" { 410 | // create EC_elem instance 411 | EC_elem *EC_elem_FF_create(const FF_elem *x, const FF_elem *y, const FF_elem *z); 412 | // delete E instance 413 | void EC_elem_FF_delete(const EC_elem* obj); 414 | // to python __str__ function 415 | void EC_elem_FF_to_string(const EC_elem *obj, char *ptr, int len); 416 | }; 417 | 418 | extern "C" { 419 | // create EC_elem instance 420 | EC_elem *EC_elem_EF_create(const EF_elem *x, const EF_elem *y, const EF_elem *z); 421 | // delete E instance 422 | void EC_elem_EF_delete(const EC_elem* obj); 423 | // to python __str__ function 424 | void EC_elem_EF_to_string(const EC_elem *obj, char *ptr, int len); 425 | }; 426 | -------------------------------------------------------------------------------- /cpp/includes/EF.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ecpy_native.h" 3 | 4 | struct EF_elem; 5 | 6 | enum class IrreduciblePolynomialType : int { 7 | X2_1, // x^2+1 8 | X2_X_1, // x^2+x+1 9 | }; 10 | 11 | struct EF { 12 | FF base; 13 | IrreduciblePolynomialType poly; 14 | 15 | EF(const FF& ff, IrreduciblePolynomialType pol) : base(ff), poly(pol) {} 16 | 17 | EF(const mpz_class& p, IrreduciblePolynomialType pol) : base(p), poly(pol) {} 18 | 19 | EF() = default; 20 | ~EF() = default; 21 | EF(const EF& ef) : base(ef.base), poly(ef.poly) {} 22 | EF(EF&& ef) : base(std::move(ef.base)), poly(ef.poly) {} 23 | 24 | EF& operator=(const EF& ef); 25 | EF& operator=(EF&& ef); 26 | 27 | // structure class member functions 28 | void add(EF_elem& ret, const EF_elem& a, const EF_elem& b) const; 29 | void sub(EF_elem& ret, const EF_elem& a, const EF_elem& b) const; 30 | void mul(EF_elem& ret, const EF_elem& a, const EF_elem& b) const; 31 | void div(EF_elem& ret, const EF_elem& a, const EF_elem& b) const; 32 | void pow(EF_elem& ret, const EF_elem& a, const mpz_class& b) const; 33 | bool equ(const EF_elem& a, const EF_elem& b) const; 34 | 35 | // common functions 36 | EF *clone() const; 37 | std::string to_string() const; 38 | }; 39 | 40 | struct EF_elem { 41 | FF_elem u, v; 42 | 43 | EF_elem(const FF_elem& u, const FF_elem& v) : u(u), v(v) {} 44 | 45 | EF_elem(const mpz_class& u, const mpz_class& v) : u(u), v(v) {} 46 | 47 | EF_elem(const FF_elem& u) : u(u), v(0) {} 48 | 49 | EF_elem(const mpz_class& u) : u(u), v(0) {} 50 | 51 | EF_elem() = default; 52 | ~EF_elem() = default; 53 | EF_elem(const EF_elem& ee) : u(ee.u), v(ee.v) {}; 54 | EF_elem(EF_elem&& ee) : u(std::move(ee.u)), v(std::move(ee.v)) {}; 55 | 56 | EF_elem& operator=(const EF_elem& ee); 57 | EF_elem& operator=(EF_elem&& ee); 58 | 59 | // common functions 60 | EF_elem *clone() const; 61 | std::string to_string() const; 62 | }; 63 | 64 | // EF 65 | extern "C" { 66 | // create EF instance 67 | // polynomial is string of irreducible polynomial. 68 | // e.g. x^2+x+1, x^2+1, X^2+1, x^2+ x +1 (ignore spaces and case insensitive) 69 | EF *EF_create(const char *p, const char *polynomial); 70 | // delete EF instance 71 | void EF_delete(const EF *ef); 72 | 73 | // r = a + b 74 | void EF_add(const EF *obj, EF_elem *ret, const EF_elem *a, const EF_elem *b); 75 | // r = a - b 76 | void EF_sub(const EF *obj, EF_elem *ret, const EF_elem *a, const EF_elem *b); 77 | // r = a * b 78 | void EF_mul(const EF *obj, EF_elem *ret, const EF_elem *a, const EF_elem *b); 79 | // r = a / b 80 | void EF_div(const EF *obj, EF_elem *ret, const EF_elem *a, const EF_elem *b); 81 | // r = a ^ b 82 | void EF_pow(const EF *obj, EF_elem *ret, const EF_elem *a, const char *b); 83 | 84 | void EF_to_string(const EF *obj, char *ptr, int len); 85 | }; 86 | 87 | // EF_elem 88 | extern "C" { 89 | EF_elem *EF_elem_create(const char *u, const char *v); 90 | void EF_elem_delete(const EF_elem *obj); 91 | void EF_elem_to_string(const EF_elem *obj, char *ptr, int len); 92 | }; 93 | 94 | -------------------------------------------------------------------------------- /cpp/includes/FF.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ecpy_native.h" 3 | 4 | struct FF_elem; 5 | 6 | struct FF { 7 | mpz_class p; 8 | 9 | FF() = default; 10 | ~FF() = default; 11 | FF(const mpz_class& _p) : p(_p) {} 12 | FF(const FF& t) : p(t.p) {} 13 | FF(FF&& t) : p(std::move(t.p)) {} 14 | 15 | FF& operator=(const FF&); 16 | FF& operator=(FF&&); 17 | 18 | // common functions 19 | FF *clone() const; 20 | std::string to_string() const; 21 | 22 | // structure class member functions 23 | void add(FF_elem&, const FF_elem&, const FF_elem&) const; 24 | void sub(FF_elem&, const FF_elem&, const FF_elem&) const; 25 | void mul(FF_elem&, const FF_elem&, const FF_elem&) const; 26 | void div(FF_elem&, const FF_elem&, const FF_elem&) const; 27 | void pow(FF_elem&, const FF_elem&, const mpz_class&) const; 28 | bool equ(const FF_elem&, const FF_elem&) const; 29 | }; 30 | 31 | struct FF_elem { 32 | mpz_class v; 33 | 34 | FF_elem() = default; 35 | ~FF_elem() = default; 36 | FF_elem(const mpz_class& v) : v(v) {}; 37 | FF_elem(mpz_class&& v) : v(std::move(v)) {}; 38 | FF_elem(const FF_elem& t) : v(t.v) {}; 39 | FF_elem(FF_elem&& t) : v(std::move(t.v)) {}; 40 | 41 | FF_elem& operator=(const FF_elem&); 42 | FF_elem& operator=(FF_elem&&); 43 | 44 | // common functions 45 | FF_elem *clone() const; 46 | std::string to_string() const; 47 | }; 48 | 49 | // FF 50 | extern "C" { 51 | // create FF instance 52 | FF *FF_create(const char *p); 53 | // delete FF instance 54 | void FF_delete(const FF*); 55 | // ret = a + b 56 | void FF_add(const FF *obj, FF_elem *ret, const FF_elem *a, const FF_elem *b); 57 | // ret = a - b 58 | void FF_sub(const FF *obj, FF_elem *ret, const FF_elem *a, const FF_elem *b); 59 | // ret = a * b 60 | void FF_mul(const FF *obj, FF_elem *ret, const FF_elem *a, const FF_elem *b); 61 | // ret = a / b 62 | void FF_div(const FF *obj, FF_elem *ret, const FF_elem *a, const FF_elem *b); 63 | // ret = a ^ b 64 | void FF_pow(const FF *obj, FF_elem *ret, const FF_elem *a, const char *b); 65 | // to python __str__ function 66 | void FF_to_string(const FF *obj, char *ptr, int len); 67 | }; 68 | 69 | // FF_elem 70 | extern "C" { 71 | // create FF_elem instance 72 | FF_elem *FF_elem_create(const char *v); 73 | // delete FF_elem instance 74 | void FF_elem_delete(const FF_elem*); 75 | // to python __str__ function 76 | void FF_elem_to_string(const FF_elem *obj, char *ptr, int len); 77 | }; 78 | -------------------------------------------------------------------------------- /cpp/includes/ecpy_native.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include "FF.h" 16 | 17 | #include "EF.h" 18 | 19 | #include "EC.h" 20 | 21 | template 22 | mpz_class get_modulus(const T& base); 23 | 24 | extern "C" { 25 | void EC_FF_miller(FF_elem *ret, const EC *curve, const EC_elem *P, const EC_elem *Q, const char *m); 26 | void EC_EF_miller(EF_elem *ret, const EC *curve, const EC_elem *P, const EC_elem *Q, const char *m); 27 | void EC_FF_weil_pairing(FF_elem *ret, const EC *curve, const EC_elem *P, const EC_elem *Q, const EC_elem *S, const char *m); 28 | void EC_EF_weil_pairing(EF_elem *ret, const EC *curve, const EC_elem *P, const EC_elem *Q, const EC_elem *S, const char *m); 29 | void EC_FF_tate_pairing(FF_elem *ret, const EC *curve, const EC_elem *P, const EC_elem *Q, const char *m, const int k); 30 | void EC_EF_tate_pairing(EF_elem *ret, const EC *curve, const EC_elem *P, const EC_elem *Q, const char *m, const int k); 31 | }; 32 | 33 | template 34 | void write_to_python_string(const T *x, char *ptr, const int& len) { 35 | std::stringstream ss; 36 | ss << x->to_string(); 37 | std::string r = ss.str(); 38 | if (r.size() < static_cast(len)) { 39 | strcpy(ptr, r.c_str()); 40 | } else { 41 | *ptr = '\0'; 42 | } 43 | } 44 | 45 | template 46 | void h(E& ret, const EC& curve, const EC_elem& P, const EC_elem& Q, const EC_elem& R) { 47 | E u {0}, v {0}; 48 | E p {0}, q {0}; 49 | auto base = curve.base; 50 | base.mul(u, P.x, Q.z); 51 | base.mul(v, P.z, Q.x); 52 | if ((curve.equ(P, Q) && base.equ(P.y, E {0})) || (!curve.equ(P, Q) && base.equ(u, v))) { 53 | base.mul(u, R.x, P.z); 54 | base.mul(v, R.z, P.x); 55 | base.sub(u, u, v); // R.x * P.z - R.z * P.x 56 | base.mul(v, P.z, R.z); 57 | base.div(ret, u, v); // (R.x * P.z - R.z * P.x) / (P.z * R.z) 58 | return; 59 | } 60 | E L = curve.line_coeff(P, Q); 61 | 62 | base.mul(p, R.y, P.z); 63 | base.mul(u, P.y, R.z); 64 | base.sub(p, p, u); // R.y * P.z - P.y * R.z 65 | base.mul(u, R.x, P.z); 66 | base.mul(v, P.x, R.z); 67 | base.sub(u, u, v); // R.x * P.z - P.x * R.z 68 | base.mul(u, u, L); // L * (R.x * P.z - P.x * R.z) 69 | base.sub(p, p, u); // R.y * P.z - P.y * R.z - L * (R.x * P.z - P.x * R.z) 70 | 71 | 72 | base.mul(q, P.x, Q.z); 73 | base.mul(q, q, R.z); 74 | 75 | base.mul(u, Q.x, P.z); 76 | base.mul(u, u, R.z); 77 | base.add(q, q, u); // P.x * Q.z * R.z + P.z * Q.x * R.z 78 | 79 | base.mul(u, P.z, Q.z); 80 | base.mul(u, u, R.x); 81 | base.add(q, q, u); // P.x * Q.z * R.z + P.z * Q.x * R.z + P.z * Q.z * R.x 82 | 83 | base.mul(u, L, L); 84 | base.mul(u, u, P.z); 85 | base.mul(u, u, Q.z); 86 | base.mul(u, u, R.z); 87 | base.sub(q, q, u); // P.x * Q.z * R.z + P.z * Q.x * R.z + P.z * Q.z * R.x - (L^2 * P.z * Q.z * R.z) 88 | 89 | 90 | base.div(ret, p, q); 91 | base.mul(ret, ret, Q.z); 92 | } 93 | 94 | template 95 | void miller(E& ret, const EC& curve, const EC_elem& P, const EC_elem& Q, mpz_class m) { 96 | E t {0}; 97 | 98 | ret = E {1}; 99 | 100 | if (curve.equ(P, Q)) { 101 | return; 102 | } 103 | auto n = mpz_sizeinbase(m.get_mpz_t(), 2); 104 | EC_elem G {P}; 105 | for (mpz_class i = mpz_class(1) << (n - 2); i != 0; i >>= 1) { 106 | curve.base.mul(ret, ret, ret); 107 | h(t, curve, G, G, Q); 108 | curve.base.mul(ret, ret, t); 109 | curve.add(G, G, G); 110 | if ((m & i) != 0) { 111 | h(t, curve, G, P, Q); 112 | curve.base.mul(ret, ret, t); 113 | curve.add(G, G, P); 114 | } 115 | } 116 | } 117 | 118 | template 119 | void weil_pairing(E& ret, const EC& curve, const EC_elem& P, const EC_elem& Q, const EC_elem& S, const mpz_class& m) { 120 | E fpqs {0}, fps {0}, fqps {0}, fqs {0}, u {0}, v {0}; 121 | EC_elem t; 122 | 123 | curve.add(t, Q, S); 124 | miller(fpqs, curve, P, t, m); 125 | 126 | miller(fps, curve, P, S, m); 127 | 128 | curve.sub(t, P, S); 129 | miller(fqps, curve, Q, t, m); 130 | 131 | curve.neg(t, S); 132 | miller(fqs, curve, Q, t, m); 133 | 134 | curve.base.mul(u, fpqs, fqs); 135 | curve.base.mul(v, fps, fqps); 136 | curve.base.div(ret, u, v); 137 | } 138 | template 139 | void tate_pairing(E& ret, const EC& curve, const EC_elem& P, const EC_elem& Q, const mpz_class& m, const int& embedding_degree) { 140 | E f {0}; 141 | miller(f, curve, P, Q, m); 142 | mpz_class p = get_modulus(curve.base); 143 | mpz_class t = 1; 144 | for (int i = 0; i < embedding_degree; i++) { 145 | t *= p; 146 | } 147 | curve.base.pow(ret, f, (t - 1)/m); 148 | } 149 | -------------------------------------------------------------------------------- /cpp/py/ecpy/native/EC.py: -------------------------------------------------------------------------------- 1 | from .library import lib, NativeProxy, to_char_ptr 2 | from ctypes import c_void_p 3 | from .FF import FF, FF_elem 4 | from .EF import EF, EF_elem 5 | import ast 6 | 7 | 8 | class EC(NativeProxy): 9 | _EC_FF_create = lib.EC_FF_create 10 | _EC_FF_create.restype = c_void_p 11 | 12 | _EC_EF_create = lib.EC_EF_create 13 | _EC_EF_create.restype = c_void_p 14 | 15 | def __init__(s, base, a, b): 16 | s.base = base 17 | s.a = a 18 | s.b = b 19 | 20 | if isinstance(base, FF): 21 | ptr = EC._EC_FF_create(to_char_ptr(str(a)), to_char_ptr(str(b)), base.ptr) 22 | tostring_func = lib.EC_FF_to_string 23 | del_func = lib.EC_FF_delete 24 | s.add_func = lib.EC_FF_add 25 | s.sub_func = lib.EC_FF_sub 26 | s.mul_func = lib.EC_FF_mul 27 | s.type = 1 28 | elif isinstance(base, EF): 29 | ptr = EC._EC_EF_create( 30 | to_char_ptr(str(a)), 31 | to_char_ptr(str(b)), 32 | base.ptr, 33 | to_char_ptr(base.poly), 34 | ) 35 | tostring_func = lib.EC_EF_to_string 36 | del_func = lib.EC_EF_delete 37 | s.add_func = lib.EC_EF_add 38 | s.sub_func = lib.EC_EF_sub 39 | s.mul_func = lib.EC_EF_mul 40 | s.type = 2 41 | NativeProxy.__init__(s, ptr, tostring_func, del_func) 42 | 43 | def add(s, ret, a, b): 44 | assert isinstance(ret, EC_elem) 45 | assert isinstance(a, EC_elem) 46 | assert isinstance(b, EC_elem) 47 | s.add_func(s.ptr, ret.ptr, a.ptr, b.ptr) 48 | 49 | def sub(s, ret, a, b): 50 | assert isinstance(ret, EC_elem) 51 | assert isinstance(a, EC_elem) 52 | assert isinstance(b, EC_elem) 53 | s.sub_func(s.ptr, ret.ptr, a.ptr, b.ptr) 54 | 55 | def mul(s, ret, a, b): 56 | assert isinstance(ret, EC_elem) and isinstance(a, EC_elem) 57 | s.mul_func(s.ptr, ret.ptr, a.ptr, to_char_ptr(str(b))) 58 | 59 | def div(s, ret, a, b): 60 | raise NotImplementedError() 61 | 62 | def pow(s, ret, a, b): 63 | raise NotImplementedError() 64 | 65 | 66 | class EC_elem(NativeProxy): 67 | _EC_elem_FF_create = lib.EC_elem_FF_create 68 | _EC_elem_FF_create.restype = c_void_p 69 | 70 | _EC_elem_EF_create = lib.EC_elem_EF_create 71 | _EC_elem_EF_create.restype = c_void_p 72 | 73 | def __init__(s, curve, x, y, z=1): 74 | from six import integer_types 75 | 76 | def conv(x): 77 | if s.curve.type == 1: 78 | if isinstance(x, tuple): 79 | return FF_elem(x[0]) 80 | else: 81 | return FF_elem(x) 82 | elif s.curve.type == 2: 83 | if isinstance(x, tuple): 84 | return EF_elem(x[0], x[1]) 85 | else: 86 | return EF_elem(x, 0) 87 | 88 | assert isinstance(curve, EC) 89 | s.x = x 90 | s.y = y 91 | s.z = z 92 | s.curve = curve 93 | s.base = curve.base 94 | if isinstance(x, integer_types + (tuple,)): 95 | x = conv(x) 96 | if isinstance(y, integer_types + (tuple,)): 97 | y = conv(y) 98 | if isinstance(z, integer_types + (tuple,)): 99 | z = conv(z) 100 | 101 | if s.curve.type == 1: 102 | ptr = EC_elem._EC_elem_FF_create(x.ptr, y.ptr, z.ptr) 103 | tostring_func = lib.EC_elem_FF_to_string 104 | del_func = lib.EC_elem_FF_delete 105 | elif s.curve.type == 2: 106 | ptr = EC_elem._EC_elem_EF_create(x.ptr, y.ptr, z.ptr) 107 | tostring_func = lib.EC_elem_EF_to_string 108 | del_func = lib.EC_elem_EF_delete 109 | 110 | NativeProxy.__init__(s, ptr, tostring_func, del_func) 111 | 112 | def to_python(s): 113 | r = str(s).lstrip("EC_elem").replace("EF_elem", "").replace("FF_elem", "") 114 | return tuple(ast.literal_eval(r)) 115 | -------------------------------------------------------------------------------- /cpp/py/ecpy/native/EF.py: -------------------------------------------------------------------------------- 1 | from .library import lib, NativeProxy, to_char_ptr 2 | from ctypes import c_void_p 3 | import ast 4 | 5 | 6 | class EF(NativeProxy): 7 | _EF_create = lib.EF_create 8 | _EF_create.restype = c_void_p 9 | 10 | def __init__(s, p, poly): 11 | s.p = p 12 | s.poly = poly 13 | NativeProxy.__init__( 14 | s, 15 | EF._EF_create(to_char_ptr(str(p)), to_char_ptr(poly)), 16 | lib.EF_to_string, 17 | lib.EF_delete, 18 | ) 19 | 20 | def add(s, ret, a, b): 21 | assert isinstance(ret, EF_elem) 22 | assert isinstance(a, EF_elem) 23 | assert isinstance(b, EF_elem) 24 | lib.EF_add(s.ptr, ret.ptr, a.ptr, b.ptr) 25 | 26 | def sub(s, ret, a, b): 27 | assert isinstance(ret, EF_elem) 28 | assert isinstance(a, EF_elem) 29 | assert isinstance(b, EF_elem) 30 | lib.EF_sub(s.ptr, ret.ptr, a.ptr, b.ptr) 31 | 32 | def mul(s, ret, a, b): 33 | assert isinstance(ret, EF_elem) 34 | assert isinstance(a, EF_elem) 35 | assert isinstance(b, EF_elem) 36 | lib.EF_mul(s.ptr, ret.ptr, a.ptr, b.ptr) 37 | 38 | def div(s, ret, a, b): 39 | assert isinstance(ret, EF_elem) 40 | assert isinstance(a, EF_elem) 41 | assert isinstance(b, EF_elem) 42 | lib.EF_div(s.ptr, ret.ptr, a.ptr, b.ptr) 43 | 44 | def pow(s, ret, a, b): 45 | assert isinstance(ret, EF_elem) 46 | assert isinstance(a, EF_elem) 47 | lib.EF_pow(s.ptr, ret.ptr, a.ptr, to_char_ptr(str(b))) 48 | 49 | 50 | class EF_elem(NativeProxy): 51 | _EF_elem_create = lib.EF_elem_create 52 | _EF_elem_create.restype = c_void_p 53 | 54 | def __init__(s, u, v): 55 | NativeProxy.__init__( 56 | s, 57 | EF_elem._EF_elem_create(to_char_ptr(str(u)), to_char_ptr(str(v))), 58 | lib.EF_elem_to_string, 59 | lib.EF_elem_delete, 60 | ) 61 | 62 | def to_python(s): 63 | r = str(s).lstrip("EF_elem") 64 | return tuple(ast.literal_eval(r)) 65 | -------------------------------------------------------------------------------- /cpp/py/ecpy/native/FF.py: -------------------------------------------------------------------------------- 1 | from .library import lib, NativeProxy, c_char_p 2 | from ctypes import c_void_p 3 | 4 | 5 | class FF(NativeProxy): 6 | _FF_create = lib.FF_create 7 | _FF_create.restype = c_void_p 8 | 9 | def __init__(s, p): 10 | s.p = p 11 | NativeProxy.__init__( 12 | s, 13 | FF._FF_create(c_char_p(str(p).encode("us-ascii"))), 14 | lib.FF_to_string, 15 | lib.FF_delete, 16 | ) 17 | 18 | def add(s, ret, a, b): 19 | assert isinstance(ret, FF_elem) 20 | assert isinstance(a, FF_elem) 21 | assert isinstance(b, FF_elem) 22 | lib.FF_add(s.ptr, ret.ptr, a.ptr, b.ptr) 23 | 24 | def sub(s, ret, a, b): 25 | assert isinstance(ret, FF_elem) 26 | assert isinstance(a, FF_elem) 27 | assert isinstance(b, FF_elem) 28 | lib.FF_sub(s.ptr, ret.ptr, a.ptr, b.ptr) 29 | 30 | def mul(s, ret, a, b): 31 | assert isinstance(ret, FF_elem) 32 | assert isinstance(a, FF_elem) 33 | assert isinstance(b, FF_elem) 34 | lib.FF_mul(s.ptr, ret.ptr, a.ptr, b.ptr) 35 | 36 | def div(s, ret, a, b): 37 | assert isinstance(ret, FF_elem) 38 | assert isinstance(a, FF_elem) 39 | assert isinstance(b, FF_elem) 40 | lib.FF_div(s.ptr, ret.ptr, a.ptr, b.ptr) 41 | 42 | def pow(s, ret, a, b): 43 | assert isinstance(ret, FF_elem) and isinstance(a, FF_elem) 44 | lib.FF_pow(s.ptr, ret.ptr, a.ptr, c_char_p(str(b).encode("us-ascii"))) 45 | 46 | 47 | class FF_elem(NativeProxy): 48 | _FF_elem_create = lib.FF_elem_create 49 | _FF_elem_create.restype = c_void_p 50 | 51 | def __init__(s, v): 52 | s.v = v 53 | NativeProxy.__init__( 54 | s, 55 | FF_elem._FF_elem_create(c_char_p(str(v).encode("us-ascii"))), 56 | lib.FF_elem_to_string, 57 | lib.FF_elem_delete, 58 | ) 59 | 60 | def to_python(s): 61 | return int(str(s)) 62 | -------------------------------------------------------------------------------- /cpp/py/ecpy/native/__init__.py: -------------------------------------------------------------------------------- 1 | from .FF import FF, FF_elem 2 | from .EF import EF, EF_elem 3 | from .EC import EC, EC_elem 4 | from .method import miller, weil_pairing, tate_pairing 5 | -------------------------------------------------------------------------------- /cpp/py/ecpy/native/library.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | 3 | lib = cdll.LoadLibrary("libecpy_native.so") 4 | 5 | 6 | def to_char_ptr(string): 7 | return c_char_p(string.encode("us-ascii")) 8 | 9 | 10 | class NativeProxy(object): 11 | def __init__(s, object_ptr, tostring_func, del_func): 12 | s.ptr = c_void_p(object_ptr) 13 | s.tostring_func = tostring_func 14 | s.del_func = del_func 15 | 16 | def __to_string(s, bufsize): 17 | b = create_string_buffer(bufsize) 18 | s.tostring_func(s.ptr, b, bufsize) 19 | b = b.value 20 | if len(b) == 0: # not enough buffer size 21 | return s.__to_string(2 * bufsize) 22 | return b 23 | 24 | def __str__(s): 25 | return str(s.__to_string(1024).decode("us-ascii")) 26 | 27 | def __del__(s): 28 | s.del_func(s.ptr) 29 | -------------------------------------------------------------------------------- /cpp/py/ecpy/native/method.py: -------------------------------------------------------------------------------- 1 | from .library import * 2 | 3 | 4 | def miller(ret, E, P, Q, m): 5 | cond = {1: lib.EC_FF_miller, 2: lib.EC_EF_miller} 6 | cond[E.type](ret.ptr, E.ptr, P.ptr, Q.ptr, to_char_ptr(str(m))) 7 | 8 | 9 | def weil_pairing(ret, E, P, Q, S, m): 10 | cond = {1: lib.EC_FF_weil_pairing, 2: lib.EC_EF_weil_pairing} 11 | cond[E.type](ret.ptr, E.ptr, P.ptr, Q.ptr, S.ptr, to_char_ptr(str(m))) 12 | 13 | 14 | def tate_pairing(ret, E, P, Q, m, k): 15 | cond = {1: lib.EC_FF_tate_pairing, 2: lib.EC_EF_tate_pairing} 16 | cond[E.type](ret.ptr, E.ptr, P.ptr, Q.ptr, to_char_ptr(str(m)), int(k)) 17 | -------------------------------------------------------------------------------- /cpp/py/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup( 4 | name="ecpy_native", 5 | version="1.0.0", 6 | description="A Native Module of ecpy", 7 | author="@elliptic_shiho", 8 | author_email="shiho.elliptic@gmaill.com", 9 | url="https://github.com/elliptic-shiho/ecpy/", 10 | packages=["ecpy.native"], 11 | ) 12 | -------------------------------------------------------------------------------- /cpp/src/EC_interface.cpp: -------------------------------------------------------------------------------- 1 | #include "ecpy_native.h" 2 | 3 | using namespace std; 4 | 5 | extern "C" EC *EC_FF_create(const char *a, const char *b, const FF *base) { 6 | EC *ec = new EC(*base, mpz_class(a), mpz_class(b)); 7 | return ec; 8 | } 9 | 10 | extern "C" void EC_FF_delete(const EC *obj) { 11 | delete obj; 12 | } 13 | 14 | extern "C" void EC_FF_add(const EC *obj, EC_elem *ret, const EC_elem *a, const EC_elem *b) { 15 | obj->add(*ret, *a, *b); 16 | } 17 | 18 | extern "C" void EC_FF_sub(const EC *obj, EC_elem *ret, const EC_elem *a, const EC_elem *b) { 19 | obj->sub(*ret, *a, *b); 20 | } 21 | 22 | extern "C" void EC_FF_mul(const EC *obj, EC_elem *ret, const EC_elem *a, const char *_b) { 23 | mpz_class b(_b); 24 | obj->mul(*ret, *a, b); 25 | } 26 | 27 | extern "C" int EC_FF_equ(const EC *obj, const EC_elem *a, const EC_elem *b) { 28 | return obj->equ(*a, *b) ? 1 : 0; 29 | } 30 | 31 | extern "C" void EC_FF_to_string(const EC *obj, char *ptr, int len) { 32 | write_to_python_string(obj, ptr, len); 33 | } 34 | 35 | extern "C" EC *EC_EF_create(const char *a, const char *b, const EF *base) { 36 | EC *ec = new EC(*base, mpz_class(a), mpz_class(b)); 37 | return ec; 38 | } 39 | 40 | extern "C" void EC_EF_delete(const EC *obj) { 41 | delete obj; 42 | } 43 | 44 | extern "C" void EC_EF_add(const EC *obj, EC_elem *ret, const EC_elem *a, const EC_elem *b) { 45 | obj->add(*ret, *a, *b); 46 | } 47 | 48 | extern "C" void EC_EF_sub(const EC *obj, EC_elem *ret, const EC_elem *a, const EC_elem *b) { 49 | obj->sub(*ret, *a, *b); 50 | } 51 | 52 | extern "C" void EC_EF_mul(const EC *obj, EC_elem *ret, const EC_elem *a, const char *_b) { 53 | mpz_class b(_b); 54 | obj->mul(*ret, *a, b); 55 | } 56 | 57 | extern "C" int EC_EF_equ(const EC *obj, const EC_elem *a, const EC_elem *b) { 58 | return obj->equ(*a, *b) ? 1 : 0; 59 | } 60 | 61 | extern "C" void EC_EF_to_string(const EC *obj, char *ptr, int len) { 62 | write_to_python_string(obj, ptr, len); 63 | } 64 | 65 | extern "C" EC_elem *EC_elem_FF_create(const FF_elem *x, const FF_elem *y, const FF_elem *z) { 66 | EC_elem *P = new EC_elem(*x, *y, *z); 67 | return P; 68 | } 69 | 70 | extern "C" void EC_elem_FF_delete(const EC_elem *obj) { 71 | delete obj; 72 | } 73 | 74 | extern "C" void EC_elem_FF_to_string(const EC_elem *obj, char *ptr, int len) { 75 | write_to_python_string(obj, ptr, len); 76 | } 77 | 78 | extern "C" EC_elem *EC_elem_EF_create(const EF_elem *x, const EF_elem *y, const EF_elem *z) { 79 | EC_elem *P = new EC_elem(*x, *y, *z); 80 | return P; 81 | } 82 | 83 | extern "C" void EC_elem_EF_delete(const EC_elem *obj) { 84 | delete obj; 85 | } 86 | 87 | extern "C" void EC_elem_EF_to_string(const EC_elem *obj, char *ptr, int len) { 88 | write_to_python_string(obj, ptr, len); 89 | } 90 | -------------------------------------------------------------------------------- /cpp/src/EF.cpp: -------------------------------------------------------------------------------- 1 | #include "ecpy_native.h" 2 | 3 | EF& EF::operator=(const EF& ef) { 4 | base = ef.base; 5 | poly = ef.poly; 6 | return (*this); 7 | } 8 | 9 | EF& EF::operator=(EF&& ef) { 10 | base = std::move(ef.base); 11 | poly = std::move(ef.poly); 12 | return (*this); 13 | } 14 | 15 | void EF::add(EF_elem& ret, const EF_elem& a, const EF_elem& b) const { 16 | base.add(ret.u, a.u, b.u); 17 | base.add(ret.v, a.v, b.v); 18 | } 19 | 20 | void EF::sub(EF_elem& ret, const EF_elem& a, const EF_elem& b) const { 21 | base.sub(ret.u, a.u, b.u); 22 | base.sub(ret.v, a.v, b.v); 23 | } 24 | 25 | void EF::mul(EF_elem& ret, const EF_elem& a, const EF_elem& b) const { 26 | FF_elem p, q, r, s; 27 | FF_elem u, v; 28 | switch (poly) { 29 | case IrreduciblePolynomialType::X2_1: 30 | base.mul(p, a.u, b.u); // ac 31 | base.mul(q, a.v, b.v); // bd 32 | base.sub(u, p, q); // ac-bd 33 | 34 | base.mul(p, a.u, b.v); // ad 35 | base.mul(q, a.v, b.u); // bc 36 | base.add(v, p, q); // ad+bc 37 | break; 38 | case IrreduciblePolynomialType::X2_X_1: 39 | base.mul(p, a.u, b.u); // ac 40 | base.mul(q, a.v, b.v); // bd 41 | base.sub(u, p, q); // ac-bd 42 | 43 | base.mul(r, a.u, b.v); // ad 44 | base.mul(s, a.v, b.u); // bc 45 | base.add(r, r, s); // ad+bc 46 | base.sub(v, r, q); // ad+bc-bd 47 | break; 48 | default: 49 | // do not reach here 50 | ; 51 | } 52 | ret.u = u; 53 | ret.v = v; 54 | } 55 | 56 | void EF::div(EF_elem& ret, const EF_elem& a, const EF_elem& b) const { 57 | FF_elem p, q, r, s, t; 58 | FF_elem u, v; 59 | static const FF_elem ZERO(0); 60 | switch (poly) { 61 | case IrreduciblePolynomialType::X2_1: 62 | // t = c^2+d^2 63 | base.mul(p, b.u, b.u); 64 | base.mul(q, b.v, b.v); 65 | base.add(t, p, q); 66 | 67 | // Real: (ac+bd)/t 68 | base.mul(p, a.u, b.u); 69 | base.mul(q, a.v, b.v); 70 | base.add(p, p, q); 71 | base.div(u, p, t); 72 | 73 | // Image: -(ad-bc)/t = (bc-ad)/t 74 | base.mul(p, a.v, b.u); 75 | base.mul(q, a.u, b.v); 76 | base.sub(p, p, q); 77 | base.div(v, p, t); 78 | break; 79 | case IrreduciblePolynomialType::X2_X_1: 80 | // t = c^2+d^2-cd 81 | base.mul(p, b.u, b.u); 82 | base.mul(q, b.v, b.v); 83 | base.mul(r, b.u, b.v); 84 | base.add(p, p, q); 85 | base.sub(t, p, r); 86 | 87 | // Real: (ac+bd-ad)/t 88 | base.mul(p, a.u, b.u); 89 | base.mul(q, a.v, b.v); 90 | base.mul(r, a.u, b.v); 91 | base.add(p, p, q); 92 | base.sub(p, p, r); 93 | base.div(u, p, t); 94 | 95 | // Image: -(ad-bc)/t = (bc-ad)/t 96 | base.mul(p, a.v, b.u); 97 | base.mul(q, a.u, b.v); 98 | base.sub(p, p, q); 99 | base.div(v, p, t); 100 | break; 101 | default: 102 | // do not reach here 103 | ; 104 | } 105 | ret.u = u; 106 | ret.v = v; 107 | } 108 | 109 | void EF::pow(EF_elem& ret, const EF_elem& a, const mpz_class& b) const { 110 | auto P = a; 111 | auto m = b; 112 | FF_elem u, v; 113 | if (m == 0) { 114 | ret.u = FF_elem(1); 115 | ret.v = FF_elem(0); 116 | } else if (m == 1) { 117 | ret.u = a.u; 118 | ret.v = a.v; 119 | } else { 120 | EF_elem t(1, 0), x(a); 121 | while (m != 0) { 122 | if ((m & 1) == 1) { 123 | mul(t, t, x); 124 | } 125 | mul(x, x, x); 126 | m >>= 1; 127 | } 128 | ret.u = t.u; 129 | ret.v = t.v; 130 | } 131 | } 132 | 133 | bool EF::equ(const EF_elem& a, const EF_elem& b) const { 134 | return base.equ(a.u, b.u) && base.equ(a.v, b.v); 135 | } 136 | 137 | EF *EF::clone() const { 138 | return new EF(*this); 139 | } 140 | 141 | std::string EF::to_string() const { 142 | std::stringstream ss; 143 | ss << "Extended Field " << base.to_string() << "/"; 144 | switch (poly) { 145 | case IrreduciblePolynomialType::X2_1: 146 | ss << "(x^2+1)"; 147 | break; 148 | case IrreduciblePolynomialType::X2_X_1: 149 | ss << "(x^2+x+1)"; 150 | break; 151 | default: 152 | // do not reach here 153 | ; 154 | } 155 | return ss.str(); 156 | } 157 | 158 | EF_elem& EF_elem::operator=(const EF_elem& ee) { 159 | u = ee.u; 160 | v = ee.v; 161 | return (*this); 162 | } 163 | 164 | EF_elem& EF_elem::operator=(EF_elem&& ee) { 165 | u = std::move(ee.u); 166 | v = std::move(ee.v); 167 | return (*this); 168 | } 169 | 170 | 171 | EF_elem *EF_elem::clone() const { 172 | return new EF_elem(*this); 173 | } 174 | 175 | std::string EF_elem::to_string() const { 176 | std::stringstream ss; 177 | ss << "EF_elem(" 178 | << u.to_string() 179 | << ", " 180 | << v.to_string() 181 | << ")"; 182 | return ss.str(); 183 | } 184 | -------------------------------------------------------------------------------- /cpp/src/EF_interface.cpp: -------------------------------------------------------------------------------- 1 | #include "ecpy_native.h" 2 | 3 | // EF 4 | // create EF instance 5 | // polynomial is string of irreducible polynomial. 6 | // e.g. x^2+x+1, x^2+1, X^2+1, x^2+ x +1 (ignore spaces and case insensitive) 7 | extern "C" EF *EF_create(const char *p, const char *polynomial) { 8 | // string to polynomial 9 | auto poly_ = std::string(polynomial); 10 | IrreduciblePolynomialType ret; 11 | // lower case 12 | std::transform(poly_.begin(), poly_.end(), poly_.begin(), ::tolower); 13 | // remove spaces 14 | auto poly = std::accumulate(poly_.begin(), poly_.end(), std::string(), [](std::string a, char b) { 15 | if (b != ' ') { 16 | a += b; 17 | } 18 | return a; 19 | }); 20 | if (poly == "x^2+1") { 21 | ret = IrreduciblePolynomialType::X2_1; 22 | } else if (poly == "x^2+x+1") { 23 | ret = IrreduciblePolynomialType::X2_X_1; 24 | } else { 25 | throw std::runtime_error("Invalid Irreducible Polynomial"); 26 | } 27 | return new EF(mpz_class(p), ret); 28 | } 29 | // delete EF instance 30 | extern "C" void EF_delete(const EF *ef) { 31 | delete ef; 32 | } 33 | 34 | // r = a + b 35 | extern "C" void EF_add(const EF *obj, EF_elem *ret, const EF_elem *a, const EF_elem *b) { 36 | obj->add(*ret, *a, *b); 37 | } 38 | 39 | // r = a - b 40 | extern "C" void EF_sub(const EF *obj, EF_elem *ret, const EF_elem *a, const EF_elem *b) { 41 | obj->sub(*ret, *a, *b); 42 | } 43 | 44 | // r = a * b 45 | extern "C" void EF_mul(const EF *obj, EF_elem *ret, const EF_elem *a, const EF_elem *b) { 46 | obj->mul(*ret, *a, *b); 47 | } 48 | // r = a / b 49 | extern "C" void EF_div(const EF *obj, EF_elem *ret, const EF_elem *a, const EF_elem *b) { 50 | obj->div(*ret, *a, *b); 51 | } 52 | // r = a ^ b 53 | extern "C" void EF_pow(const EF *obj, EF_elem *ret, const EF_elem *a, const char *b) { 54 | obj->pow(*ret, *a, mpz_class(b)); 55 | } 56 | 57 | extern "C" void EF_to_string(const EF *obj, char *ptr, int len) { 58 | write_to_python_string(obj, ptr, len); 59 | } 60 | 61 | // EF_elem 62 | extern "C" EF_elem *EF_elem_create(const char *u, const char *v) { 63 | return new EF_elem(mpz_class(u), mpz_class(v)); 64 | } 65 | 66 | extern "C" void EF_elem_delete(const EF_elem *obj) { 67 | delete obj; 68 | } 69 | 70 | extern "C" void EF_elem_to_string(const EF_elem *obj, char *ptr, int len) { 71 | write_to_python_string(obj, ptr, len); 72 | } 73 | 74 | -------------------------------------------------------------------------------- /cpp/src/FF.cpp: -------------------------------------------------------------------------------- 1 | #include "ecpy_native.h" 2 | 3 | using namespace std; 4 | 5 | FF& FF::operator=(const FF& f) { 6 | p = f.p; 7 | return (*this); 8 | } 9 | 10 | FF& FF::operator=(FF&& f) { 11 | p = std::move(f.p); 12 | return (*this); 13 | } 14 | 15 | std::string FF::to_string() const { 16 | std::stringstream ss; 17 | ss << "F_" 18 | << p.get_str(10); 19 | return ss.str(); 20 | } 21 | 22 | template 23 | inline mpz_class modulo(T a, const mpz_class& modulo) { 24 | mpz_class t = a % modulo; 25 | if (t < 0) { 26 | t += modulo; 27 | } 28 | return t; 29 | } 30 | 31 | void FF::add(FF_elem& ret, const FF_elem& a, const FF_elem& b) const { 32 | ret.v = modulo(a.v + b.v, p); 33 | } 34 | 35 | void FF::sub(FF_elem& ret, const FF_elem& a, const FF_elem& b) const { 36 | ret.v = modulo(a.v - b.v, p); 37 | } 38 | 39 | void FF::mul(FF_elem& ret, const FF_elem& a, const FF_elem& b) const { 40 | ret.v = modulo(a.v * b.v, p); 41 | } 42 | 43 | void FF::div(FF_elem& ret, const FF_elem& a, const FF_elem& b) const { 44 | mpz_class t; 45 | mpz_invert(t.get_mpz_t(), b.v.get_mpz_t(), p.get_mpz_t()); 46 | ret.v = modulo(a.v * t, p); 47 | } 48 | 49 | void FF::pow(FF_elem& ret, const FF_elem& a, const mpz_class& b) const { 50 | mpz_class t; 51 | mpz_powm(t.get_mpz_t(), a.v.get_mpz_t(), b.get_mpz_t(), p.get_mpz_t()); 52 | ret.v = modulo(t, p); 53 | } 54 | 55 | bool FF::equ(const FF_elem& a, const FF_elem& b) const { 56 | return modulo(a.v - b.v, p) == 0; 57 | } 58 | 59 | FF_elem& FF_elem::operator=(const FF_elem& f) { 60 | v = f.v; 61 | return (*this); 62 | } 63 | 64 | FF_elem& FF_elem::operator=(FF_elem&& f) { 65 | v = std::move(f.v); 66 | return (*this); 67 | } 68 | 69 | FF_elem *FF_elem::clone() const { 70 | return new FF_elem((*this)); 71 | } 72 | 73 | std::string FF_elem::to_string() const { 74 | return v.get_str(10); 75 | } 76 | -------------------------------------------------------------------------------- /cpp/src/FF_interface.cpp: -------------------------------------------------------------------------------- 1 | #include "ecpy_native.h" 2 | 3 | /* FF_elem interface functions */ 4 | 5 | // create E instance 6 | extern "C" FF_elem *FF_elem_create(const char* v) { 7 | auto ret = new FF_elem(mpz_class(v)); 8 | return ret; 9 | } 10 | 11 | // delete E instance 12 | extern "C" void FF_elem_delete(const FF_elem* obj) { 13 | delete obj; 14 | } 15 | 16 | // to python __str__ function 17 | extern "C" void FF_elem_to_string(const FF_elem *obj, char *ptr, int len) { 18 | write_to_python_string(obj, ptr, len); 19 | } 20 | 21 | /* FF interface functions */ 22 | 23 | // create FF instance 24 | extern "C" FF *FF_create(const char *p) { 25 | return new FF(mpz_class(p)); 26 | } 27 | 28 | // delete FF instance 29 | extern "C" void FF_delete(const FF* obj) { 30 | delete obj; 31 | } 32 | 33 | // ret = a + b 34 | extern "C" void FF_add(const FF *obj, FF_elem *ret, const FF_elem *a, const FF_elem *b) { 35 | obj->add(*ret, *a, *b); 36 | } 37 | 38 | // ret = a - b 39 | extern "C" void FF_sub(const FF *obj, FF_elem *ret, const FF_elem *a, const FF_elem *b) { 40 | obj->sub(*ret, *a, *b); 41 | } 42 | 43 | // ret = a * b 44 | extern "C" void FF_mul(const FF *obj, FF_elem *ret, const FF_elem *a, const FF_elem *b) { 45 | obj->mul(*ret, *a, *b); 46 | } 47 | 48 | // ret = a / b 49 | extern "C" void FF_div(const FF *obj, FF_elem *ret, const FF_elem *a, const FF_elem *b) { 50 | obj->div(*ret, *a, *b); 51 | } 52 | 53 | // ret = a ^ b 54 | extern "C" void FF_pow(const FF *obj, FF_elem *ret, const FF_elem *a, const char *b) { 55 | obj->pow(*ret, *a, mpz_class(b)); 56 | } 57 | 58 | // to python __str__ function 59 | extern "C" void FF_to_string(const FF *obj, char *ptr, int len) { 60 | write_to_python_string(obj, ptr, len); 61 | } 62 | -------------------------------------------------------------------------------- /cpp/src/ecpy_native.cpp: -------------------------------------------------------------------------------- 1 | #include "ecpy_native.h" 2 | 3 | using namespace std; 4 | 5 | template<> 6 | mpz_class get_modulus(const FF& base) { 7 | return base.p; 8 | } 9 | 10 | template<> 11 | mpz_class get_modulus(const EF& base) { 12 | return base.base.p * base.base.p; 13 | } 14 | 15 | extern "C" void EC_FF_miller(FF_elem *ret, const EC *curve, const EC_elem *P, const EC_elem *Q, const char *m) { 16 | miller(*ret, *curve, *P, *Q, mpz_class(m)); 17 | } 18 | extern "C" void EC_EF_miller(EF_elem *ret, const EC *curve, const EC_elem *P, const EC_elem *Q, const char *m) { 19 | miller(*ret, *curve, *P, *Q, mpz_class(m)); 20 | } 21 | extern "C" void EC_FF_weil_pairing(FF_elem *ret, const EC *curve, const EC_elem *P, const EC_elem *Q, const EC_elem *S, const char *m) { 22 | weil_pairing(*ret, *curve, *P, *Q, *S, mpz_class(m)); 23 | } 24 | 25 | extern "C" void EC_EF_weil_pairing(EF_elem *ret, const EC *curve, const EC_elem *P, const EC_elem *Q, const EC_elem *S, const char *m) { 26 | weil_pairing(*ret, *curve, *P, *Q, *S, mpz_class(m)); 27 | } 28 | 29 | extern "C" void EC_FF_tate_pairing(FF_elem *ret, const EC *curve, const EC_elem *P, const EC_elem *Q, const char *m, const int k) { 30 | tate_pairing(*ret, *curve, *P, *Q, mpz_class(m), k); 31 | } 32 | 33 | extern "C" void EC_EF_tate_pairing(EF_elem *ret, const EC *curve, const EC_elem *P, const EC_elem *Q, const char *m, const int k) { 34 | tate_pairing(*ret, *curve, *P, *Q, mpz_class(m), k); 35 | } 36 | -------------------------------------------------------------------------------- /cpp/test/.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | !bin/.gitkeep 3 | -------------------------------------------------------------------------------- /cpp/test/Makefile: -------------------------------------------------------------------------------- 1 | CC := g++ 2 | LD := g++ 3 | CFLAGS := -I../includes/ 4 | OPTFLAGS := -O2 -Os -mtune=corei7 -mavx 5 | GFLAGS := -g -std=c++11 # -stdlib=libc++ <= if use clang++ 6 | PYTHON := python 7 | 8 | 9 | vpath %.o ../bin/ 10 | 11 | .PHONY: all 12 | all: bin/test 13 | valgrind --leak-check=full -v ./bin/test 14 | sudo ldconfig 15 | $(PYTHON) test.py 16 | 17 | bin/test: bin/test.o $(OBJS) 18 | $(LD) -o bin/test $(GFLAGS) $(OPTFLAGS) $^ $(LDFLAGS) 19 | 20 | bin/%.o: %.cpp ../bin/* 21 | $(CC) -o $@ -c $< $(OPTFLAGS) $(CFLAGS) $(GFLAGS) 22 | -------------------------------------------------------------------------------- /cpp/test/bin/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elliptic-shiho/ecpy/8813b38f134ee6db388f9504a3e7c2fd7cdc9679/cpp/test/bin/.gitkeep -------------------------------------------------------------------------------- /cpp/test/test.cpp: -------------------------------------------------------------------------------- 1 | #include "ecpy_native.h" 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | static int ac_count = 0; 7 | static int wa_count = 0; 8 | 9 | #define ES_ASSERT_EQ_FM(x,y,m) ES_ASSERTION(x == y, m) 10 | #define ES_ASSERT_NEQ_FM(x,y,m) ES_ASSERTION(x != y, m) 11 | #define ES_ASSERT_EQ_M(x,y,m) ES_ASSERT_EQ_FM(x, y, m " == " #y) 12 | #define ES_ASSERT_NEQ_M(x,y,m) ES_ASSERT_NEQ_FM(x, y, m " != " #y) 13 | #define ES_ASSERT_EQ(x,y) ES_ASSERT_EQ_M(x, y, #x) 14 | #define ES_ASSERT_NEQ(x,y) ES_ASSERT_NEQ_M(x, y, #x) 15 | 16 | #define ES_ASSERTION(cond, msg) do {\ 17 | cout << boost::format("[+] %-16s...%-8s") % msg % "";\ 18 | try { \ 19 | if(!(cond)) { \ 20 | cout << "\033[31m[ FAILED ]\033[0m" << endl; \ 21 | wa_count++; \ 22 | } else { \ 23 | cout << "\033[33m[ OK ]\033[0m" << endl; \ 24 | ac_count++;\ 25 | }\ 26 | } catch (const runtime_error& e) { \ 27 | cout << "\033[31mFAILED(EXCEPTION)\033[0m" << endl; \ 28 | cerr << "[-] \033[31mAssertion Failed: <" \ 29 | << __FILE__ << "> " << __FUNCTION__ << ":" << __LINE__ \ 30 | << "(Exception occurerd!) -> !(" << #cond << ")\033[0m" \ 31 | << "\n\t-> \033[01;04;31m" << e.what() << "\033[0m" << endl;\ 32 | wa_count++; \ 33 | } \ 34 | } while(0) 35 | 36 | #define TEST(name) void _ ## name ## _test(); void name ## _test() { \ 37 | clock_t start, end; \ 38 | double time;\ 39 | cout << boost::format("Start Test: %s\n") % #name; \ 40 | start = clock();\ 41 | _ ## name ## _test(); \ 42 | end = clock();\ 43 | time = ((double)(end - start) / CLOCKS_PER_SEC); \ 44 | cout << boost::format("Test Finished. Time: %s sec (%s usec)\n") % time % (time * 1e+6); \ 45 | } \ 46 | void _ ## name ## _test() 47 | 48 | TEST(ec_ff) { 49 | auto F = FF(7); 50 | auto E = EC(F, 0, 1); 51 | auto P = EC_elem(0, 1, 1); 52 | auto Q = EC_elem(3, 0, 1); 53 | EC_elem T, U, Z; 54 | 55 | ES_ASSERT_NEQ_FM(E.equ(P, Q), true, "P != Q"); 56 | ES_ASSERT_EQ_FM(E.equ(P, P), true, "P == P"); 57 | ES_ASSERT_EQ_FM(E.equ(Q, Q), true, "Q == Q"); 58 | 59 | E.add(T, P, Q); 60 | E.add(U, Q, P); 61 | 62 | ES_ASSERT_EQ_FM(E.equ(T, U), true, "P+Q == Q+P"); 63 | 64 | Z = {6, 3, 6}; 65 | ES_ASSERT_EQ_FM(E.equ(T, Z), true, "P+Q=(6:3:6)"); 66 | 67 | E.add(T, P, P); 68 | Z = {0, 6, 1}; 69 | ES_ASSERT_EQ_FM(E.equ(T, Z), true, "P+P=(0:6:1)"); 70 | 71 | E.sub(T, P, P); 72 | Z = {0, 1, 0}; 73 | ES_ASSERT_EQ_FM(E.equ(T, Z), true, "P-P=(0:1:0)"); 74 | 75 | E.mul(T, P, 3); 76 | Z = {0, 1, 0}; 77 | ES_ASSERT_EQ_FM(E.equ(T, Z), true, "3P=(0:1:0)"); 78 | 79 | ES_ASSERT_EQ(E.is_on_curve(P), true); 80 | ES_ASSERT_EQ(E.is_on_curve(Q), true); 81 | ES_ASSERT_EQ(E.is_on_curve(T), true); 82 | 83 | auto r = E.line_coeff(P, Q); 84 | ES_ASSERT_EQ_FM(F.equ(r, FF_elem(2)), true, "line_coeff(P, Q)"); 85 | } 86 | 87 | TEST(ec_miller) { 88 | auto F = FF(631); 89 | auto E = EC(F, 30, 34); 90 | auto m = 5; 91 | 92 | auto P = EC_elem{36, 60, 1}; 93 | auto Q = EC_elem{121, 387, 1}; 94 | auto S = EC_elem{0, 36, 1}; 95 | FF_elem t {0}, z {0}; 96 | EC_elem Z; 97 | 98 | E.add(Z, Q, S); 99 | miller(t, E, P, Z, m); 100 | z = {103}; 101 | ES_ASSERT_EQ_FM(F.equ(t, z), true, "miller(P, Q+S) == 103"); 102 | 103 | miller(t, E, P, S, m); 104 | z = {219}; 105 | ES_ASSERT_EQ_FM(F.equ(t, z), true, "miller(P, S) == 219"); 106 | 107 | E.sub(Z, P, S); 108 | miller(t, E, Q, Z, m); 109 | z = {284}; 110 | ES_ASSERT_EQ_FM(F.equ(t, z), true, "miller(Q, P-S) == 284"); 111 | 112 | E.sub(Z, EC_elem{0, 1, 0}, S); 113 | miller(t, E, Q, Z, m); 114 | z = {204}; 115 | ES_ASSERT_EQ_FM(F.equ(t, z), true, "miller(Q, -S) == 204"); 116 | 117 | weil_pairing(t, E, P, Q, S, m); 118 | z = {242}; 119 | ES_ASSERT_EQ_FM(F.equ(t, z), true, "weil_pairing(P, Q) == 242"); 120 | 121 | tate_pairing(t, E, P, Q, m, 1); 122 | z = {279}; 123 | ES_ASSERT_EQ_FM(F.equ(t, z), true, "tate_pairing(P, Q) == 279"); 124 | } 125 | 126 | TEST(ec_ef_1) { 127 | auto F = EF(7, IrreduciblePolynomialType::X2_1); 128 | auto E = EC(F, 0, 1); 129 | auto P = EC_elem(EF_elem(4, 2), EF_elem(2, 1), EF_elem(1, 0)); 130 | auto Q = EC_elem(EF_elem(0, 3), EF_elem(3, 6), EF_elem(1, 0)); 131 | EC_elem T, U, Z; 132 | 133 | ES_ASSERT_NEQ_FM(E.equ(P, Q), true, "P != Q"); 134 | ES_ASSERT_EQ_FM(E.equ(P, P), true, "P == P"); 135 | ES_ASSERT_EQ_FM(E.equ(Q, Q), true, "Q == Q"); 136 | 137 | E.add(T, P, Q); 138 | E.add(U, Q, P); 139 | ES_ASSERT_EQ_FM(E.equ(T, U), true, "P+Q == Q+P"); 140 | 141 | Z = {EF_elem(0, 2), EF_elem(4, 6), EF_elem(1)}; 142 | ES_ASSERT_EQ_FM(E.equ(T, Z), true, "P+Q=(2i:4+6i:1)"); 143 | 144 | E.add(T, P, P); 145 | Z = {EF_elem(4, 1), EF_elem(6, 5), EF_elem(2, 4)}; 146 | ES_ASSERT_EQ_FM(E.equ(T, Z), true, "P+P=(4+i:6+5i:2+4i)"); 147 | 148 | E.sub(T, P, P); 149 | Z = {0, 1, 0}; 150 | ES_ASSERT_EQ_FM(E.equ(T, Z), true, "P-P=(0:1:0)"); 151 | 152 | E.mul(T, P, 9); 153 | Z = {EF_elem(1, 1), EF_elem(0, 1), EF_elem(5, 3)}; 154 | ES_ASSERT_EQ_FM(E.equ(T, Z), true, "9P=(1+i:i:5+3i)"); 155 | 156 | auto r = E.line_coeff(P, Q); 157 | ES_ASSERT_EQ_FM(F.equ(r, EF_elem(5)), true, "line_coeff(P, Q)"); 158 | 159 | ES_ASSERT_EQ(E.is_on_curve(P), true); 160 | ES_ASSERT_EQ(E.is_on_curve(Q), true); 161 | ES_ASSERT_EQ(E.is_on_curve(T), true); 162 | } 163 | 164 | TEST(ec_ef_2) { 165 | auto F = EF(41, IrreduciblePolynomialType::X2_X_1); 166 | auto E = EC(F, 0, 1); 167 | auto P = EC_elem(EF_elem(39, 39), EF_elem(3, 0), EF_elem(1, 0)); 168 | auto Q = EC_elem(EF_elem(5, 5), EF_elem(9, 0), EF_elem(1, 0)); 169 | EC_elem T, U, Z; 170 | 171 | ES_ASSERT_NEQ_FM(E.equ(P, Q), true, "P != Q"); 172 | ES_ASSERT_EQ_FM(E.equ(P, P), true, "P == P"); 173 | ES_ASSERT_EQ_FM(E.equ(Q, Q), true, "Q == Q"); 174 | 175 | E.add(T, P, Q); 176 | E.add(U, Q, P); 177 | ES_ASSERT_EQ_FM(E.equ(T, U), true, "P+Q == Q+P"); 178 | 179 | Z = {EF_elem(10, 10), EF_elem(27), EF_elem(26)}; 180 | ES_ASSERT_EQ_FM(E.equ(T, Z), true, "P+Q=(10+10w:27:26)"); 181 | 182 | E.add(T, P, P); 183 | Z = {EF_elem(0), EF_elem(11), EF_elem(11)}; 184 | ES_ASSERT_EQ_FM(E.equ(T, Z), true, "P+P=(0:11:11)"); 185 | 186 | E.sub(T, P, P); 187 | Z = {0, 1, 0}; 188 | ES_ASSERT_EQ_FM(E.equ(T, Z), true, "P-P=(0:1:0)"); 189 | 190 | E.add(T, P, Q); 191 | E.mul(T, T, 27); 192 | Z = {EF_elem(24, 24), EF_elem(29, 0), EF_elem(2, 0)}; 193 | ES_ASSERT_EQ_FM(E.equ(T, Z), true, "27(P+Q)=(24+24w:29:2)"); 194 | 195 | auto r = E.line_coeff(P, Q); 196 | ES_ASSERT_EQ_FM(F.equ(r, EF_elem(0, 5)), true, "line_coeff(P, Q)"); 197 | 198 | ES_ASSERT_EQ(E.is_on_curve(P), true); 199 | ES_ASSERT_EQ(E.is_on_curve(Q), true); 200 | ES_ASSERT_EQ(E.is_on_curve(T), true); 201 | } 202 | 203 | TEST(ef_1) { 204 | auto F = EF(7, IrreduciblePolynomialType::X2_1); 205 | auto x = EF_elem(3, 0); 206 | auto y = EF_elem(0, 5); 207 | EF_elem t; 208 | 209 | F.add(t, x, y); 210 | ES_ASSERT_EQ_FM((t.u.v == 3 && t.v.v == 5), true, "x+y=3+5i"); 211 | F.sub(t, x, y); 212 | ES_ASSERT_EQ_FM((t.u.v == 3 && t.v.v == 2), true, "x-y=3+2i"); 213 | F.mul(t, x, y); 214 | ES_ASSERT_EQ_FM((t.u.v == 0 && t.v.v == 1), true, "x*y=i"); 215 | F.div(t, x, y); 216 | ES_ASSERT_EQ_FM((t.u.v == 0 && t.v.v == 5), true, "x/y=5i"); 217 | F.pow(t, y, 31); 218 | ES_ASSERT_EQ_FM((t.u.v == 0 && t.v.v == 2), true, "y^31=2i"); 219 | } 220 | 221 | TEST(ef_2) { 222 | auto F = EF(41, IrreduciblePolynomialType::X2_X_1); 223 | auto x = EF_elem(15, 25); 224 | auto y = EF_elem(39, 10); 225 | EF_elem t; 226 | 227 | F.add(t, x, y); 228 | ES_ASSERT_EQ_FM((t.u.v == 13 && t.v.v == 35), true, "x+y=13+35w"); 229 | F.sub(t, x, y); 230 | ES_ASSERT_EQ_FM((t.u.v == 17 && t.v.v == 15), true, "x-y=17+15w"); 231 | F.mul(t, x, y); 232 | ES_ASSERT_EQ_FM((t.u.v == 7 && t.v.v == 14), true, "x*y=7+14w"); 233 | F.div(t, x, y); 234 | ES_ASSERT_EQ_FM((t.u.v == 29 && t.v.v == 5), true, "x/y=29+5w"); 235 | F.pow(t, x, 40); 236 | ES_ASSERT_EQ_FM((t.u.v == 14 && t.v.v == 17), true, "x^40=14+17w"); 237 | } 238 | 239 | TEST(ff) { 240 | auto ff = FF(7); 241 | FF_elem x(3), y(6); 242 | FF_elem t; 243 | ES_ASSERT_EQ(x.v, 3); 244 | ES_ASSERT_EQ(y.v, 6); 245 | 246 | ff.add(t, x, y); 247 | ES_ASSERT_EQ_FM(t.v, 2, "x+y"); 248 | 249 | ff.sub(t, x, y); 250 | ES_ASSERT_EQ_FM(t.v, 4, "x-y"); 251 | 252 | ff.mul(t, x, y); 253 | ES_ASSERT_EQ_FM(t.v, 4, "x*y"); 254 | 255 | ff.div(t, x, y); 256 | ES_ASSERT_EQ_FM(t.v, 4, "x/y"); 257 | 258 | ff.pow(t, x, 30); 259 | ES_ASSERT_EQ_FM(t.v, 1, "x^30"); 260 | } 261 | 262 | void exec_test() { 263 | ff_test(); 264 | ef_1_test(); 265 | ef_2_test(); 266 | ec_ff_test(); 267 | ec_ef_1_test(); 268 | ec_ef_2_test(); 269 | ec_miller_test(); 270 | cout << boost::format("[+] %d Test(s) finished. %d Test(s) success, %d Test(s) fail.") 271 | % (ac_count + wa_count) 272 | % ac_count 273 | % wa_count 274 | << endl; 275 | } 276 | 277 | int main(int ac, char **av) { 278 | exec_test(); 279 | return wa_count; 280 | } 281 | -------------------------------------------------------------------------------- /cpp/test/test.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from ecpy.native import * 3 | import time 4 | import sys 5 | 6 | ac_count = 0 7 | wa_count = 0 8 | 9 | 10 | def _assert(a, b, msg, cond): 11 | global ac_count, wa_count 12 | msg = msg.ljust(16) 13 | print(("[+] %s..." % (msg)).ljust(30), end=" ") 14 | var = {"a": a, "b": b} 15 | if eval("a %s b" % cond, var): 16 | r = repr(b)[:64] 17 | if repr(b) != r: 18 | r += "..." 19 | print("\x1b[33m[ OK ]\x1b[0m %s" % (r,)) 20 | ac_count += 1 21 | else: 22 | print("\x1b[31m[ Fail ]\x1b[0m Expected: %r, Result: %r" % (b, a)) 23 | wa_count += 1 24 | 25 | 26 | def assert_neq(a, b, m): 27 | _assert(a, b, m, "!=") 28 | 29 | 30 | def assert_eq(a, b, m): 31 | _assert(a, b, m, "==") 32 | 33 | 34 | def main(): 35 | F = FF(31) 36 | x = FF_elem(25) 37 | y = FF_elem(10) 38 | t = FF_elem(0) 39 | F.add(t, x, y) 40 | assert_eq(t.to_python(), 4, "x+y") 41 | F.sub(t, x, y) 42 | assert_eq(t.to_python(), 15, "x+y") 43 | F.mul(t, x, y) 44 | assert_eq(t.to_python(), 2, "x*y") 45 | F.div(t, x, y) 46 | assert_eq(t.to_python(), 18, "x/y") 47 | F.pow(t, x, y) 48 | assert_eq(t.to_python(), 25, "x^y") 49 | 50 | F = EF(41, "x^2+x+1") 51 | x = EF_elem(15, 25) 52 | y = EF_elem(39, 10) 53 | t = EF_elem(0, 0) 54 | 55 | F.add(t, x, y) 56 | assert_eq(t.to_python(), (13, 35), "x+y=13+35w") 57 | F.sub(t, x, y) 58 | assert_eq(t.to_python(), (17, 15), "x-y=17+15w") 59 | F.mul(t, x, y) 60 | assert_eq(t.to_python(), (7, 14), "x+y=7+14w") 61 | F.div(t, x, y) 62 | assert_eq(t.to_python(), (29, 5), "x+y=29+5w") 63 | print( 64 | "[+] %d Test(s) finished. %d Test(s) success, %d Test(s) fail." 65 | % (ac_count + wa_count, ac_count, wa_count) 66 | ) 67 | 68 | p = 17 69 | F = FF(p) 70 | E = EC(F, 0, 1) 71 | P = EC_elem(E, 1, 6) 72 | Q = EC_elem(E, 14, 5) 73 | t = EC_elem(E, 0, 0) 74 | 75 | E.add(t, P, Q) 76 | assert_eq(t.to_python(), (4, 10, 4), "P+Q") 77 | E.add(t, P, P) 78 | assert_eq(t.to_python(), (1, 13, 11), "P+P") 79 | E.mul(t, P, 2) 80 | assert_eq(t.to_python(), (1, 13, 11), "2*P") 81 | E.mul(t, P, 4) 82 | assert_eq(t.to_python(), (15, 3, 7), "4*P") 83 | E.mul(t, P, 9) 84 | assert_eq(t.to_python(), (0, 1, 0), "#P = 9") 85 | 86 | p = 631 87 | m = 5 88 | F = FF(p) 89 | E = EC(F, 30, 34) 90 | P = EC_elem(E, 36, 60) 91 | Q = EC_elem(E, 121, 387) 92 | S = EC_elem(E, 0, 36) 93 | t = FF_elem(0) 94 | weil_pairing(t, E, P, Q, S, m) 95 | assert_eq(t.to_python(), 242, "weil_pairing") 96 | tate_pairing(t, E, P, Q, m, 1) 97 | assert_eq(t.to_python(), 279, "tate_pairing") 98 | 99 | sys.exit(wa_count) 100 | 101 | 102 | if __name__ == "__main__": 103 | main() 104 | -------------------------------------------------------------------------------- /ecpy/__init__.py: -------------------------------------------------------------------------------- 1 | from ecpy.fields import * 2 | from ecpy.elliptic_curve import * 3 | from ecpy.utils import * 4 | from ecpy.rings import * 5 | -------------------------------------------------------------------------------- /ecpy/elliptic_curve/EllipticCurve.py: -------------------------------------------------------------------------------- 1 | from ecpy.fields import FiniteField, ExtendedFiniteField 2 | from ecpy.utils.util import is_enable_native, _native 3 | from ecpy.utils import modular_square_root 4 | from random import randint 5 | 6 | 7 | def EllipticCurve(field, *args, **kwargs): 8 | """ 9 | Return Elliptic Curve Instance. 10 | """ 11 | if isinstance(field, FiniteField): 12 | return FiniteFieldEllipticCurve(field, *args, **kwargs) 13 | else: 14 | return GenericEllipticCurve(field, *args, **kwargs) 15 | 16 | 17 | def EC_from_j_invariant(field, j0): 18 | """ 19 | Return Elliptic Curve Instance which has j-invariant is `j0`. 20 | """ 21 | assert isinstance(field, FiniteField) 22 | R = randint(1, field.n) 23 | if j0 == 0: 24 | return FiniteFieldEllipticCurve(field, 0, R) 25 | if j0 == 1728: 26 | return FiniteFieldEllipticCurve(field, R, 0) 27 | ADR = 3 * j0 * R**2 28 | BDR = 2 * j0 * R**3 29 | u = 1728 - j0 30 | uinv = 1 / field(u) 31 | return FiniteFieldEllipticCurve(field, ADR * uinv, BDR * uinv) 32 | 33 | 34 | class GenericEllipticCurve(object): 35 | """ 36 | Elliptic Curve on General Field 37 | """ 38 | 39 | def __init__(s, field, a, b): 40 | """ 41 | Constructor of Elliptic Curve. 42 | y^2 = x^3 + `a`x+ `b` on `field` 43 | """ 44 | s.element_class = GenericEllipticCurvePoint 45 | s.field = field 46 | s.a = a 47 | s.b = b 48 | s.O = s.element_class(s, 0, 1, 0) 49 | 50 | def is_on_curve(s, point): 51 | """ 52 | Is on curve `point`? 53 | """ 54 | return s._is_on_curve(point.x, point.y, point.z) 55 | 56 | def _is_on_curve(s, x, y, z=1): 57 | """ 58 | Is on curve (`x`, `y`, `z`)? 59 | """ 60 | x = s.field(x) 61 | y = s.field(y) 62 | z = s.field(z) 63 | return y * y * z == x * x * x + s.a * x * z * z + s.b * z * z * z 64 | 65 | def determinant(s): 66 | """ 67 | Calculate Determinant of Curve. 68 | """ 69 | return -16 * (4 * s.a**3 + 27 * s.b**2) 70 | 71 | def j_invariant(s): 72 | """ 73 | Calculate j-Invariant of Curve. 74 | """ 75 | return -1728 * ((4 * s.a**3) / s.determinant()) 76 | 77 | def __repr__(s): 78 | return "EllipticCurve(%r, %r, %r)" % (s.field, s.a, s.b) 79 | 80 | def __call__(s, *x): 81 | return s.element_class(s, *x) 82 | 83 | def __str__(s): 84 | res = "Elliptic Curve y^2 = x^3" 85 | if s.a != 0: 86 | if s.a == 1: 87 | res += " + x" 88 | else: 89 | res += " + %rx" % s.a 90 | if s.b != 0: 91 | res += " + %r" % s.b 92 | res += " over %r" % s.field 93 | return res 94 | 95 | def _add(s, P, Q): 96 | from six import integer_types 97 | 98 | """ 99 | Add Operation on Perspective Coordinate 100 | P : tuple (x, y, z) 101 | Q : tuple (u, v, w) 102 | return: R = P + Q 103 | """ 104 | Px, Py, Pz = P 105 | Qx, Qy, Qz = Q 106 | Rx, Ry, Rz = s.O 107 | if s._equ(P, Q): 108 | X, Y, Z = Px, Py, Pz 109 | u = 3 * X * X + s.a * Z * Z 110 | v = Y * Z 111 | a = Y * v 112 | w = u * u - 8 * X * a 113 | Rx = 2 * v * w 114 | Ry = u * (4 * X * a - w) - 8 * a * a 115 | Rz = 8 * v * v * v 116 | else: 117 | u = Qy * Pz - Py * Qz 118 | v = Qx * Pz - Px * Qz 119 | v2 = v * v 120 | v3 = v2 * v 121 | w = u * u * Pz * Qz - v3 - 2 * v2 * Px * Qz 122 | Rx = v * w 123 | Ry = u * (v2 * Px * Qz - w) - v3 * Py * Qz 124 | Rz = v3 * Pz * Qz 125 | if isinstance(Rz, integer_types): 126 | z = 1 // s.field(Rz) 127 | else: 128 | z = 1 // Rz 129 | if z == 0: 130 | return s.O 131 | return s.element_class(s, Rx * z, Ry * z, 1) 132 | 133 | def _equ(s, P, Q): 134 | """ 135 | Is P equals to Q? 136 | """ 137 | return P[0] * Q[1] == P[1] * Q[0] 138 | 139 | def _neg(s, P): 140 | """ 141 | return -P 142 | """ 143 | if P == (0, 1, 0): 144 | return s.O 145 | return s.element_class(s, P[0], -P[1]) 146 | 147 | 148 | class GenericEllipticCurvePoint(object): 149 | """ 150 | Elliptic Curve Point on General Field 151 | """ 152 | 153 | def __init__(s, group, x, y, z=1): 154 | def F(x): 155 | if isinstance(x, tuple): 156 | return group.field(*x) 157 | return group.field(x) 158 | 159 | s.group = group 160 | s.x = F(x) 161 | s.y = F(y) 162 | s.z = F(z) 163 | s.inf = s.x == 0 and s.y == 1 and s.z == 0 164 | if not (s.inf or s.group.is_on_curve(s)): 165 | raise ArithmeticError("Invalid Point: (%s, %s, %s)" % (s.x, s.y, s.z)) 166 | 167 | def is_infinity(s): 168 | """ 169 | Returns: 170 | Is self equals to O? 171 | """ 172 | return s.inf 173 | 174 | def change_group(s, _group): 175 | return s.__class__(_group, *tuple(s)) 176 | 177 | def line_coeff(s, Q): 178 | from six.moves import map 179 | 180 | """ 181 | Calculate Line Coefficient of Line self to Q 182 | """ 183 | P = s 184 | x1, y1, z1 = map(s.group.field, P) 185 | x2, y2, z2 = map(s.group.field, Q) 186 | assert z1 == z2 == 1 # is normalized? 187 | if x1 == x2: 188 | l = (3 * x1 * x1 + s.group.a) // (2 * y1) 189 | else: 190 | l = (y2 - y1) // (x2 - x1) 191 | return l 192 | 193 | def __add__(s, rhs): 194 | if isinstance(rhs, GenericEllipticCurvePoint) and rhs.is_infinity(): 195 | return s 196 | d = s._to_tuple(rhs) 197 | if s.is_infinity(): 198 | return s.__class__(s.group, d[0], d[1]) 199 | else: 200 | return s.group._add(tuple(s), d) 201 | 202 | def __sub__(s, rhs): 203 | return s + (-rhs) 204 | 205 | def __mul__(s, rhs): 206 | """ 207 | Multiplication Operation 208 | """ 209 | from six.moves import map 210 | 211 | d = rhs 212 | if d < 0: 213 | b = -1 214 | d = -d 215 | else: 216 | b = 1 217 | if d == 0: 218 | return s.group.O 219 | bits = list(map(int, bin(d)[2:]))[::-1] 220 | x = s 221 | if bits[0]: 222 | res = x 223 | else: 224 | res = s.group.O 225 | for cur in bits[1:]: 226 | x += x 227 | if cur: 228 | res += x 229 | if b == -1: 230 | res = -res 231 | return res 232 | 233 | def __neg__(s): 234 | """ 235 | Negate Operation Wrapper 236 | """ 237 | return s.group._neg(tuple(s)) 238 | 239 | def __rmul__(s, lhs): 240 | return s * lhs 241 | 242 | def __eq__(s, rhs): 243 | """ 244 | Is self equals to rhs? 245 | """ 246 | if rhs == None: 247 | return False 248 | return s.group._equ(tuple(s), s._to_tuple(rhs)) 249 | 250 | def _to_tuple(s, d): 251 | if isinstance(d, GenericEllipticCurvePoint): 252 | return tuple(d) 253 | elif isinstance(d, tuple): 254 | return d 255 | else: 256 | raise ArithmeticError("Invalid Parameter: %r" % d) 257 | 258 | def __iter__(s): 259 | return (s.x, s.y, s.z).__iter__() 260 | 261 | def __repr__(s): 262 | if s.is_infinity(): 263 | return "%r.O" % s.group 264 | return "%r(%r, %r, %r)" % (s.group, s.x, s.y, s.z) 265 | 266 | def __str__(s): 267 | if s.is_infinity(): 268 | return "Infinity Point (0 : 1 : 0) on %s" % s.group 269 | return "Point (%s : %s : %s) on %s" % (s.x, s.y, s.z, s.group) 270 | 271 | 272 | class FiniteFieldEllipticCurve(GenericEllipticCurve): 273 | """ 274 | Elliptic Curve on Finite Field or Extended Finite Field 275 | """ 276 | 277 | def __init__(s, field, a, b): 278 | s.field = field 279 | s.a = a 280 | s.b = b 281 | s.element_class = FiniteFieldEllipticCurvePoint 282 | s.O = s.element_class(s, 0, 1, 0) 283 | if is_enable_native: 284 | if isinstance(field, ExtendedFiniteField): 285 | cond = {1: "x^2+1", 2: "x^2+x+1"} 286 | poly = cond[field.t] 287 | s.base = _native.EF(field.p, poly) 288 | elif isinstance(field, FiniteField): 289 | s.base = _native.FF(field.p) 290 | s.ec = _native.EC(s.base, a, b) 291 | s._add = s.__add_native 292 | else: 293 | s.add_func = s.__add 294 | 295 | def get_corresponding_y(s, x): 296 | """ 297 | Calculate `y` coordinate corresponding to given x. 298 | """ 299 | x = s.field(x) 300 | y_square = x * x * x + s.a * x + s.b 301 | for y in modular_square_root(y_square, s.field.p ** s.field.degree()): 302 | if pow(y, 2, s.field.p ** s.field.degree()) == y_square: 303 | return y 304 | return None 305 | 306 | def embedding_degree(s, m): 307 | """ 308 | Calculate Embedding Degree. 309 | <=> minimum `k` satisfy m | p^k - 1 310 | """ 311 | k = 1 312 | while True: 313 | if (s.field.p ** (k * s.field.degree()) - 1) % m == 0: 314 | return k 315 | k += 1 316 | 317 | def random_point(s): 318 | """ 319 | return random point on this curve. 320 | """ 321 | rnd = [randint(0, s.field.order())] * s.field.degree() 322 | x = s.field(*rnd) 323 | while True: 324 | y = s.get_corresponding_y(x) 325 | if y != None: 326 | if s._is_on_curve(x, y): 327 | return s.element_class(s, x, y) 328 | x += 1 329 | 330 | def __add(s, P, Q): 331 | return super(FiniteFieldEllipticCurve, s)._add(P, Q) 332 | 333 | def __add_native(s, P, Q): 334 | R = _native.EC_elem(s.ec, 0, 0) 335 | P = _native.EC_elem(s.ec, tuple(P[0]), tuple(P[1]), tuple(P[2])) 336 | Q = _native.EC_elem(s.ec, tuple(Q[0]), tuple(Q[1]), tuple(Q[2])) 337 | s.ec.add(R, P, Q) 338 | R = FiniteFieldEllipticCurvePoint(s, *R.to_python(), normalize=True) 339 | return R 340 | 341 | 342 | class FiniteFieldEllipticCurvePoint(GenericEllipticCurvePoint): 343 | def __init__(s, group, x, y, z=1, normalize=False): 344 | def F(x): 345 | if type(x) == tuple: 346 | return group.field(*x) 347 | return group.field(x) 348 | 349 | s.group = group 350 | s.x = F(x) 351 | s.y = F(y) 352 | s.z = F(z) 353 | if normalize and s.z != 0: 354 | s.x = s.x / s.z 355 | s.y = s.y / s.z 356 | s.z = s.z / s.z 357 | s.inf = s.x == 0 and s.y == 1 and s.z == 0 358 | if not (s.inf or s.group.is_on_curve(s)): 359 | raise ArithmeticError("Invalid Point: (%s, %s, %s)" % (s.x, s.y, s.z)) 360 | if is_enable_native: 361 | s.__mul_method__ = s._mul_native 362 | else: 363 | s.__mul_method__ = super(FiniteFieldEllipticCurvePoint, s).__mul__ 364 | 365 | def _mul_native(s, rhs): 366 | P = tuple(s) 367 | R = _native.EC_elem(s.group.ec, 0, 1, 0) 368 | P = _native.EC_elem(s.group.ec, tuple(P[0]), tuple(P[1]), tuple(P[2])) 369 | m = rhs 370 | s.group.ec.mul(R, P, m) 371 | R = FiniteFieldEllipticCurvePoint(s.group, *R.to_python(), normalize=True) 372 | return R 373 | 374 | def __mul__(s, rhs): 375 | return s.__mul_method__(rhs) 376 | 377 | def distortion_map(s): 378 | """ 379 | IMPORTANT: If you want to use this function, 380 | definition field should be Extended Finite Field. 381 | return \phi(self), \phi is Distortion map 382 | Polynomial: x^2+1 or x^2+x+1 383 | """ 384 | 385 | def to_tuple(x): 386 | from six import integer_types 387 | 388 | if type(x) in integer_types: 389 | return (x, 0) 390 | return tuple(x) 391 | 392 | x = to_tuple(s.x) 393 | y = to_tuple(s.y) 394 | if s.group.field.t == 1: 395 | x = (-x[0], -x[1]) 396 | y = (y[1], y[0]) 397 | elif s.group.field.t == 2: 398 | x = (x[1], x[0]) 399 | y = (y[0], y[1]) 400 | return s.__class__(s.group, x, y) 401 | 402 | def order(s): 403 | """ 404 | return order of self 405 | """ 406 | r = s.change_group(s.group) 407 | i = 2 408 | while True: 409 | if r.is_infinity(): 410 | return i 411 | r += s 412 | i += 1 413 | -------------------------------------------------------------------------------- /ecpy/elliptic_curve/EllipticCurveRepository.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple as _namedtuple 2 | 3 | _ECData = _namedtuple("ECData", ["p", "a", "b", "n", "Gx", "Gy"]) 4 | _repo = { 5 | "secp192k1": _ECData( 6 | p=2**192 - 2**32 - 2**12 - 2**8 - 2**7 - 2**6 - 2**3 - 1, 7 | a=0, 8 | b=3, 9 | Gx=0xDB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D, 10 | Gy=0x9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D, 11 | n=0xFFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D, 12 | ), 13 | "secp192r1": _ECData( 14 | p=2**192 - 2**64 - 1, 15 | a=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC, 16 | b=0x64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1, 17 | Gx=0x188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012, 18 | Gy=0x07192B95FFC8DA78631011ED6B24CDD573F977A11E794811, 19 | n=0xFFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831, 20 | ), 21 | "secp224k1": _ECData( 22 | p=2**224 - 2**32 - 2**12 - 2**11 - 2**9 - 2**7 - 2**4 - 2 - 1, 23 | a=0, 24 | b=5, 25 | Gx=0xA1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C, 26 | Gy=0x7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5, 27 | n=0x010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7, 28 | ), 29 | "secp224r1": _ECData( 30 | p=2**224 - 2**96 + 1, 31 | a=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE, 32 | b=0xB4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4, 33 | Gx=0xB70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21, 34 | Gy=0xBD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34, 35 | n=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D, 36 | ), 37 | "secp256k1": _ECData( 38 | p=2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 - 1, 39 | a=0, 40 | b=7, 41 | Gx=0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 42 | Gy=0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8, 43 | n=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141, 44 | ), 45 | "secp256r1": _ECData( 46 | p=2**224 * (2**32 - 1) + 2**192 + 2**96 - 1, 47 | a=0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC, 48 | b=0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B, 49 | Gx=0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296, 50 | Gy=0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5, 51 | n=0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551, 52 | ), 53 | "secp384r1": _ECData( 54 | p=2**384 - 2**128 - 2**96 + 2**32 - 1, 55 | a=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC, 56 | b=0xB3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF, 57 | Gx=0xAA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7, 58 | Gy=0x3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F, 59 | n=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973, 60 | ), 61 | "secp521r1": _ECData( 62 | p=2**521 - 1, 63 | a=0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC, 64 | b=0x0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00, 65 | Gx=0x00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66, 66 | Gy=0x011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650, 67 | n=0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409, 68 | ), 69 | } 70 | 71 | 72 | def EllipticCurveRepository(name): 73 | """ 74 | Elliptic Curve Repository - standard curves repository function 75 | Args: 76 | name: name of the curve (e.g. 'secp256k1') case insensitive 77 | Return: Tuple (F, E, G, n) 78 | F: Base field object of E 79 | E: Elliptic curve corresponding to `name` 80 | G: Base point given by `name` 81 | n: Order of `G` 82 | """ 83 | from ecpy.fields import FiniteField 84 | from .EllipticCurve import EllipticCurve 85 | 86 | name = name.lower() 87 | if name in _repo.keys(): 88 | data = _repo[name] 89 | F = FiniteField(data.p) 90 | E = EllipticCurve(F, data.a, data.b) 91 | G = E(data.Gx, data.Gy) 92 | n = data.n 93 | return (F, E, G, n) 94 | else: 95 | raise ValueError("Invalid Elliptic Curve Name: %r" % name) 96 | -------------------------------------------------------------------------------- /ecpy/elliptic_curve/__init__.py: -------------------------------------------------------------------------------- 1 | from .EllipticCurve import EllipticCurve 2 | from .EllipticCurveRepository import EllipticCurveRepository 3 | from .sssa_attack import SSSA_Attack 4 | from .pairing import weil_pairing, tate_pairing, find_point_by_order 5 | from .pairing import gen_supersingular_ec, MapToPoint, miller 6 | from .pairing import symmetric_tate_pairing, symmetric_weil_pairing 7 | -------------------------------------------------------------------------------- /ecpy/elliptic_curve/pairing.py: -------------------------------------------------------------------------------- 1 | def miller(E, P, Q, m): 2 | from six.moves import map 3 | 4 | """ 5 | Calculate Divisor by Miller's Algorithm 6 | Args: 7 | E: The Elliptic Curve 8 | P: A point over E which has order m 9 | Q: A point over E which has order m to apply function f_P 10 | m: The order of P, Q on E 11 | Returns: 12 | f_P(Q) 13 | """ 14 | 15 | def h(P, Q, R): 16 | # if \lambda is infinity 17 | if (P == Q and P.y == 0) or (P != Q and P.x == Q.x): 18 | return R.x - P.x 19 | L = P.line_coeff(Q) 20 | p = R.y - P.y - L * (R.x - P.x) 21 | q = R.x + P.x + Q.x - L * L 22 | return p / q 23 | 24 | if P == Q: 25 | return 1 26 | b = map(int, bin(m)[2:]) 27 | next(b) 28 | f = 1 29 | T = P 30 | for i in b: 31 | f = f * f * h(T, T, Q) 32 | T = T + T 33 | if i: 34 | f = f * h(T, P, Q) 35 | T = T + P 36 | return f 37 | 38 | 39 | def weil_pairing(E, P, Q, m, S=None): 40 | """ 41 | Calculate Weil Pairing 42 | Args: 43 | E: The Elliptic Curve 44 | P: A point over E which has order m 45 | Q: A point over E which has order m 46 | m: The order of P, Q on E 47 | S: [Optional] A random point on E 48 | Returns: 49 | e_m(P, Q) 50 | """ 51 | if S is None: 52 | S = E.random_point() 53 | from ecpy.utils.util import is_enable_native, _native 54 | from ecpy.fields.ExtendedFiniteField import ExtendedFiniteFieldElement 55 | 56 | if is_enable_native: 57 | P = _native.EC_elem(E.ec, tuple(P.x), tuple(P.y), tuple(P.z)) 58 | Q = _native.EC_elem(E.ec, tuple(Q.x), tuple(Q.y), tuple(Q.z)) 59 | S = _native.EC_elem(E.ec, tuple(S.x), tuple(S.y), tuple(S.z)) 60 | if E.ec.type == 1: 61 | t = _native.FF_elem(0) 62 | elif E.ec.type == 2: 63 | t = _native.EF_elem(0, 0) 64 | _native.weil_pairing(t, E.ec, P, Q, S, m) 65 | if E.ec.type == 1: 66 | return t.to_python() 67 | elif E.ec.type == 2: 68 | t = t.to_python() 69 | return ExtendedFiniteFieldElement(E.field, t[0], t[1]) 70 | else: 71 | fpqs = miller(E, P, Q + S, m) 72 | fps = miller(E, P, S, m) 73 | fqps = miller(E, Q, P - S, m) 74 | fqs = miller(E, Q, -S, m) 75 | return E.field._inv(fps * fqps) * fpqs * fqs 76 | 77 | 78 | def tate_pairing(E, P, Q, m, k=2): 79 | """ 80 | Calculate Tate Pairing 81 | Args: 82 | E: The Elliptic Curve 83 | P: A point over E which has order m 84 | Q: A point over E which has order m 85 | m: The order of P, Q on E 86 | k: [Optional] The Embedding Degree of m on E 87 | """ 88 | from ecpy.utils.util import is_enable_native, _native 89 | 90 | if is_enable_native: 91 | P = _native.EC_elem(E.ec, tuple(P.x), tuple(P.y), tuple(P.z)) 92 | Q = _native.EC_elem(E.ec, tuple(Q.x), tuple(Q.y), tuple(Q.z)) 93 | if E.ec.type == 1: 94 | t = _native.FF_elem(0) 95 | elif E.ec.type == 2: 96 | t = _native.EF_elem(0, 0) 97 | _native.tate_pairing(t, E.ec, P, Q, m, k) 98 | if E.ec.type == 1: 99 | from ecpy.fields.Zmod import ZmodElement 100 | 101 | return ZmodElement(E.field, t.to_python()) 102 | elif E.ec.type == 2: 103 | from ecpy.fields.ExtendedFiniteField import ExtendedFiniteFieldElement 104 | 105 | t = t.to_python() 106 | return ExtendedFiniteFieldElement(E.field, t[0], t[1]) 107 | else: 108 | f = miller(E, P, Q, m) 109 | return f ** (((E.field.p**k) - 1) // m) 110 | 111 | 112 | def MapToPoint(E, y): 113 | """ 114 | MapToPoint Function: Given by Boneh-Durfee's ID-based Encryption Paper. 115 | Args: 116 | E: The Elliptic Curve 117 | y: Any Value (should be E.field element) 118 | 119 | Returns: 120 | Correspond point of y on E 121 | """ 122 | from ecpy.utils import cubic_root 123 | 124 | x = cubic_root(y**2 - 1) 125 | Q = E(x, y) 126 | return 6 * Q 127 | 128 | 129 | def gen_supersingular_ec(bits=70): 130 | """ 131 | Generate Super-Singluar Elliptic Curve 132 | Args: 133 | bits: The Security Parameter: log_2 p = bits 134 | 135 | Returns: 136 | A (Super Singular) Elliptic Curve, Extended Finite Field, l 137 | l is need to calculate Pairing 138 | """ 139 | from ecpy.fields import ExtendedFiniteField 140 | from .EllipticCurve import EllipticCurve 141 | 142 | def _next_prime(n): 143 | from ecpy import is_prime 144 | 145 | """ 146 | return next prime of n 147 | """ 148 | while not is_prime(n): 149 | n += 1 150 | return n 151 | 152 | """ 153 | If you have gmpy, use gmpy.next_prime 154 | in other hand, use slow function 155 | """ 156 | try: 157 | from gmpy import next_prime 158 | except: 159 | next_prime = _next_prime 160 | 161 | def gen_prime(): 162 | from ecpy import is_prime 163 | from random import randint 164 | 165 | while True: 166 | p = int(next_prime(randint(2 ** (bits - 1), 2**bits))) 167 | if is_prime(p * 6 - 1): 168 | break 169 | return p * 6 - 1, p 170 | 171 | p, l = gen_prime() 172 | F = ExtendedFiniteField(p, "x^2+x+1") 173 | return EllipticCurve(F, 0, 1), F, l 174 | 175 | 176 | def find_point_by_order(E, l): 177 | """ 178 | Find a Elliptic Curve Point P which has order l. 179 | Args: 180 | E: The Elliptic Curve 181 | l: Order of Point on E 182 | 183 | Returns: 184 | Point on E which has order l. 185 | """ 186 | i = 3 187 | while True: 188 | r = E.get_corresponding_y(i) 189 | if r != None: 190 | P = E(i, r) 191 | if (P * l).is_infinity(): 192 | return P 193 | i += 1 194 | 195 | 196 | def symmetric_weil_pairing(E, P, Q, m): 197 | """ 198 | Symmetric Weil Pairing 199 | \hat{e}(P, Q) = e(P, \phi(Q)) (\phi is Distortion Map) 200 | Args: 201 | E: The Elliptic Curve 202 | P: A point on E which has order m 203 | Q: A point on E which has order m 204 | m: The order of P, Q 205 | """ 206 | return weil_pairing(E, P, Q.distortion_map(), m) 207 | 208 | 209 | def symmetric_tate_pairing(E, P, Q, m, k=2): 210 | """ 211 | Symmetric Tate Pairing 212 | \hat{e}(P, Q) = e(P, \phi(Q)) (\phi is Distortion Map) 213 | Args: 214 | E: The Elliptic Curve 215 | P: A point on E which has order m 216 | Q: A point on E which has order m 217 | m: The order of P, Q 218 | k: [Optional] The Embedding Degree of m on E 219 | """ 220 | return tate_pairing(E, P, Q.distortion_map(), m) 221 | -------------------------------------------------------------------------------- /ecpy/elliptic_curve/sssa_attack.py: -------------------------------------------------------------------------------- 1 | def hensel_lift(curve, P): 2 | from six.moves import map 3 | 4 | """ 5 | Calculate Lifted Point using Hensel's Lemma 6 | Args: 7 | curve: The Elliptic Curve 8 | P: A point on curve 9 | Returns: 10 | The "lifted" Point 11 | """ 12 | from six.moves import map 13 | from ecpy.utils import modinv 14 | 15 | x, y, _ = map(int, tuple(P)) 16 | p = curve.field.p 17 | t = (((x * x * x + curve.a * x + curve.b) - y * y) // p) % p 18 | t = (t * modinv(2 * y, p)) % p 19 | return list(map(int, (x, y + (curve.field.p * t)))) 20 | 21 | 22 | def SSSA_Attack(F, E, P, Q): 23 | """ 24 | Solve ECDLP using SSSA(Semaev-Smart-Satoh-Araki) Attack. 25 | Args: 26 | F: The Base Field 27 | E: The Elliptic Curve 28 | P: A point on E 29 | Q: A point on E 30 | Returns: 31 | Return x where satisfies Q = xP. 32 | """ 33 | from .EllipticCurve import EllipticCurve 34 | from ecpy.fields import QQ, Zmod 35 | from ecpy.utils.util import modinv, is_enable_native, _native 36 | 37 | A = E.a 38 | # lP, lQ, ... is "lifted" P, Q, ... 39 | x1, y1 = hensel_lift(E, P) 40 | x2, y2 = hensel_lift(E, Q) 41 | lF = Zmod(F.p**2) 42 | lA = y2 * y2 - y1 * y1 - (x2 * x2 * x2 - x1 * x1 * x1) 43 | lA = (lA * modinv(x2 - x1, lF.n)) % lF.n 44 | lB = (y1 * y1 - x1 * x1 * x1 - A * x1) % lF.n 45 | if not is_enable_native: 46 | modulo = F.p**2 47 | lE = EllipticCurve(lF, lA, lB) 48 | lP = lE(x1, y1) 49 | lQ = lE(x2, y2) 50 | lU = (F.p - 1) * lP 51 | lV = (F.p - 1) * lQ 52 | dx1 = ((int(lU.x) - x1) // F.p) % modulo 53 | dx2 = int(lU.y) - y1 54 | dy1 = ((int(lV.x) - x2) // F.p) % modulo 55 | dy2 = int(lV.y) - y2 56 | m = (dy1 * dx2 * modinv(dx1 * dy2, modulo)) % modulo 57 | return m % F.p 58 | else: 59 | modulo = F.p**2 60 | base = _native.FF(modulo) 61 | lE = _native.EC(base, lA, lB) 62 | lP = _native.EC_elem(lE, x1, y1) 63 | lQ = _native.EC_elem(lE, x2, y2) 64 | lU = _native.EC_elem(lE, 0, 1, 0) 65 | lV = _native.EC_elem(lE, 0, 1, 0) 66 | lE.mul(lU, lP, F.p - 1) 67 | lE.mul(lV, lQ, F.p - 1) 68 | lUx, lUy, lUz = lU.to_python() 69 | lVx, lVy, lVz = lV.to_python() 70 | lUx = (lUx * modinv(lUz, modulo)) % modulo 71 | lUy = (lUy * modinv(lUz, modulo)) % modulo 72 | lVx = (lVx * modinv(lVz, modulo)) % modulo 73 | lVy = (lVy * modinv(lVz, modulo)) % modulo 74 | dx1 = ((lUx - x1) // F.p) % modulo 75 | dx2 = lUy - y1 76 | dy1 = ((lVx - x2) // F.p) % modulo 77 | dy2 = lVy - y2 78 | m = (dy1 * dx2 * modinv(dx1 * dy2, modulo)) % modulo 79 | return m % F.p 80 | -------------------------------------------------------------------------------- /ecpy/fields/ComplexField.py: -------------------------------------------------------------------------------- 1 | from .Field import Field, FieldElement 2 | 3 | 4 | class ComplexField(Field): 5 | def __init__(s): 6 | super(ComplexField, s).__init__(ComplexFieldElement) 7 | 8 | def _add(s, a, b): 9 | return s.element_class(s, a[0] + b[0], a[1] + b[1]) 10 | 11 | def _neg(s, a): 12 | return s.element_class(s, -a[0], -a[1]) 13 | 14 | def _mul(s, a, b): 15 | return s.element_class(s, a[0] * b[0] - a[1] * b[1], a[0] * b[1] + a[1] * b[0]) 16 | 17 | def _equ(s, a, b): 18 | return a[0] == b[0] and a[1] == b[1] 19 | 20 | def _inv(s, a): 21 | a = s.element_class(s, a[0], a[1]) 22 | x = a.absolute_value() 23 | abar = a.conjugate() 24 | return s.element_class(s, abar.x / x, abar.y / x) 25 | 26 | def _div(s, z, w): 27 | a, b, c, d = z[0], z[1], w[0], w[1] 28 | u = 1.0 / (c**2 + d**2) 29 | return s.element_class(s, (a * c + b * d) * u, (b * c - a * d) * u) 30 | 31 | 32 | class ComplexFieldElement(FieldElement): 33 | def __init__(s, field, x, y=0): 34 | super(ComplexFieldElement, s).__init__(field, x) 35 | s.y = y 36 | 37 | def norm(s): 38 | """ 39 | Calculate Norm 40 | Returns: 41 | ||self|| 42 | """ 43 | return s.x**2 - s.y**2 44 | 45 | def absolute_value(s): 46 | """ 47 | Calculate Absolute Value 48 | Returns: 49 | |self| 50 | """ 51 | import math 52 | 53 | return math.sqrt(s.x**2 + s.y**2) 54 | 55 | def conjugate(s): 56 | """ 57 | Calculate conjugate complex 58 | Returns: 59 | \overline{self} 60 | """ 61 | return s.__class__(s.field, s.x, -s.y) 62 | 63 | def __repr__(s): 64 | return "%r(%r, %r)" % (s.field, s.x, s.y) 65 | 66 | def __str__(s): 67 | return "%r + %ri" % (s.x, s.y) 68 | 69 | def __iter__(s): 70 | return (s.x, s.y).__iter__() 71 | 72 | def _to_tuple(s, d): 73 | if isinstance(d, s.__class__): 74 | return tuple(d) 75 | elif isinstance(d, tuple): 76 | return d 77 | else: 78 | return (d, 0) 79 | 80 | 81 | CC = ComplexField() 82 | -------------------------------------------------------------------------------- /ecpy/fields/ExtendedFiniteField.py: -------------------------------------------------------------------------------- 1 | from ecpy.utils import is_prime, modinv 2 | from .FiniteField import FiniteField 3 | from .Field import Field, FieldElement 4 | from .Zmod import Zmod, ZmodElement 5 | 6 | 7 | class ExtendedFiniteField(FiniteField): 8 | def __init__(s, p, poly="x^2+1"): 9 | Field.__init__(s, ExtendedFiniteFieldElement) 10 | s.p = s.n = p 11 | if poly == "x^2+1": 12 | assert p % 4 == 3 13 | s.t = 1 14 | elif poly == "x^2+x+1": 15 | assert p % 3 == 2 # and (p + 1) % 6 == 0 and is_prime((p + 1) / 6) 16 | s.t = 2 17 | else: 18 | raise ValueError("Invalid Polynomial: %s" % poly) 19 | 20 | def __str__(s): 21 | res = Zmod.__str__(s, "p^%d" % s.degree()) + " : Polynomial is :" 22 | if s.t == 1: 23 | res += "i^2+1 = 0" 24 | elif s.t == 2: 25 | res += "w^2+w+1 = 0" 26 | return res 27 | 28 | def __repr__(s): 29 | res = "%s(%s, " % (s.__class__.__name__, s.n) 30 | if s.t == 1: 31 | res += '"x^2+1"' 32 | elif s.t == 2: 33 | res += '"x^2+x+1"' 34 | res += ")" 35 | return res 36 | 37 | def _add(s, a, b): 38 | if s.t == 1 or s.t == 2: 39 | return s.element_class(s, a[0] + b[0], a[1] + b[1]) 40 | 41 | def _neg(s, a): 42 | if s.t == 1 or s.t == 2: 43 | return s.element_class(s, s.p - a[0], s.p - a[1]) 44 | 45 | def _mul(s, a, b): 46 | if s.t == 1: 47 | return s.element_class( 48 | s, a[0] * b[0] - a[1] * b[1], a[0] * b[1] + a[1] * b[0] 49 | ) 50 | elif s.t == 2: 51 | a, _b = a 52 | c, d = b 53 | b = _b 54 | return s.element_class(s, a * c - b * d, a * d + b * c - b * d) 55 | 56 | def _equ(s, a, b): 57 | if s.degree() == 2: 58 | if len(b) == 1: 59 | return a[0] == b[0] and a[1] == 0 60 | return a[0] == b[0] and a[1] == b[1] 61 | 62 | def _div(s, z, w): 63 | r = s._inv(w) * z 64 | return r 65 | 66 | def _inv(s, a): 67 | if len(a) == 1: 68 | return Zmod._inv(s, a) 69 | a, b = map(int, a) 70 | if s.t == 1: 71 | u = a * a + b * b 72 | u = modinv(u, s.n) 73 | return s.element_class(s, a * u, -b * u) 74 | elif s.t == 2: 75 | u = a * a - a * b + b * b 76 | u = modinv(u, s.n) 77 | return s.element_class(s, (a - b) * u, (-b) * u) 78 | 79 | def degree(s): 80 | return 2 81 | 82 | 83 | class ExtendedFiniteFieldElement(ZmodElement): 84 | def __init__(s, field, x, y=0): 85 | FieldElement.__init__(s, field, x) 86 | if isinstance(x, s.__class__): 87 | x, y = x.x, x.y 88 | s.x = x % s.field.p 89 | s.y = y % s.field.p 90 | 91 | def __repr__(s): 92 | if s.field.t == 1 or s.field.t == 2: 93 | return "%r(%r, %r)" % (s.field, s.x, s.y) 94 | 95 | def __str__(s): 96 | res = None 97 | if s == 0: 98 | return "0" 99 | res = "" 100 | if s.x != 0: 101 | res += "%r" % s.x 102 | if s.y != 0: 103 | if s.x != 0: 104 | res += " + " 105 | if s.y != 1: 106 | res += "%r" % s.y 107 | res += " iw"[s.field.t] 108 | return res 109 | 110 | def __iter__(s): 111 | if s.field.t == 1 or s.field.t == 2: 112 | return (s.x, s.y).__iter__() 113 | 114 | def _to_tuple(s, d): 115 | if isinstance(d, s.__class__): 116 | return d 117 | elif isinstance(d, tuple): 118 | return d 119 | else: 120 | if s.field.t == 1 or s.field.t == 2: 121 | return (d, 0) 122 | 123 | def __hash__(s): 124 | return s.x * s.y * s.field.p 125 | 126 | def __getitem__(s, idx): 127 | return [s.x, s.y][idx] 128 | 129 | def __len__(s): 130 | return 2 131 | -------------------------------------------------------------------------------- /ecpy/fields/Field.py: -------------------------------------------------------------------------------- 1 | from ..rings.CommutativeRing import CommutativeRing, CommutativeRingElement 2 | 3 | 4 | class Field(CommutativeRing): 5 | def __init__(s, element_class): 6 | CommutativeRing.__init__(s, element_class) 7 | 8 | def _inv(s, a): 9 | raise NotImplementedError() 10 | 11 | def _mod(s, a, b): 12 | raise NotImplementedError() 13 | 14 | def _div(s, a, b): 15 | return s._mul(a, (s._inv(b))) 16 | 17 | 18 | class FieldElement(CommutativeRingElement): 19 | def __init__(s, field, x): 20 | CommutativeRingElement.__init__(s, field, x) 21 | s.field = field 22 | if isinstance(x, FieldElement): 23 | x = x.x 24 | s.x = x 25 | 26 | def change_field(s, _field): 27 | return s.__class__(_field, *tuple(s)) 28 | 29 | def __mul__(s, rhs): 30 | return s.field._mul(tuple(s), s._to_tuple(rhs)) 31 | 32 | def __div__(s, rhs): 33 | return s.field._div(tuple(s), s._to_tuple(rhs)) 34 | 35 | def __rdiv__(s, lhs): 36 | return s.field._div(s._to_tuple(lhs), tuple(s)) 37 | 38 | def __truediv__(s, rhs): 39 | return s.field._div(tuple(s), s._to_tuple(rhs)) 40 | 41 | def __rtruediv__(s, lhs): 42 | return s.field._div(s._to_tuple(lhs), tuple(s)) 43 | 44 | def __floordiv__(s, rhs): 45 | if hasattr(s.field, "_fdiv"): 46 | return s.field._fdiv(tuple(s), s._to_tuple(rhs)) 47 | else: 48 | return s.field._div(tuple(s), s._to_tuple(rhs)) 49 | 50 | def __rfloordiv__(s, lhs): 51 | if hasattr(s.field, "_fdiv"): 52 | return s.field._fdiv(s._to_tuple(lhs), tuple(s)) 53 | else: 54 | return s.field._div(s._to_tuple(lhs), tuple(s)) 55 | 56 | def __pow__(s, rhs, mod=None): 57 | from six.moves import map 58 | 59 | if rhs == 0: 60 | return s.__class__(s.field, 1) 61 | d = int(rhs) 62 | if d < 0: 63 | x = 1 / s 64 | d = -d 65 | else: 66 | x = s 67 | bits = list(map(int, bin(d)[2:]))[::-1] 68 | if bits[0]: 69 | res = x 70 | else: 71 | res = s.field(1) 72 | for cur in bits[1:]: 73 | x *= x 74 | if cur: 75 | res *= x 76 | return res 77 | 78 | def __mod__(s, rhs): 79 | return s.field._mod(tuple(s), s._to_tuple(rhs)) 80 | 81 | def __rmod__(s, lhs): 82 | return s.field._mod(s._to_tuple(lhs), tuple(s)) 83 | 84 | def __rmul__(s, lhs): 85 | return s * lhs 86 | 87 | def int(s): 88 | return int(s.x) 89 | 90 | def __ne__(s, rhs): 91 | return not (s == rhs) 92 | 93 | def __eq__(s, rhs): 94 | return s.field._equ(tuple(s), s._to_tuple(rhs)) 95 | 96 | def __iter__(s): 97 | return (s.x,).__iter__() 98 | 99 | def __int__(s): 100 | return s.int() 101 | 102 | def __hash__(s): 103 | return s.x 104 | -------------------------------------------------------------------------------- /ecpy/fields/FiniteField.py: -------------------------------------------------------------------------------- 1 | from .Zmod import Zmod, ZmodElement 2 | 3 | 4 | class FiniteField(Zmod): 5 | """ 6 | Finite Field Class 7 | """ 8 | 9 | def __init__(s, p): 10 | """ 11 | Constructor of FiniteField 12 | p should be prime 13 | """ 14 | s.n = s.p = p 15 | s.element_class = ZmodElement 16 | 17 | def __str__(s): 18 | return Zmod.__str__(s, "p") 19 | -------------------------------------------------------------------------------- /ecpy/fields/FractionField.py: -------------------------------------------------------------------------------- 1 | from ecpy.utils import gcd, lcm 2 | from .Field import Field, FieldElement 3 | 4 | 5 | class FractionField(Field): 6 | def __init__(s, ring): 7 | from ecpy.rings.Ring import Ring 8 | 9 | assert issubclass(ring.__class__, Ring) 10 | super(FractionField, s).__init__(FractionFieldElement) 11 | s.ring = ring 12 | 13 | def _add(s, a, b): 14 | if a[1] == b[1]: 15 | return s.element_class(s, a[0] + b[0], a[1]) 16 | else: 17 | l = a[1] * b[1] 18 | p1 = a[0] * l / a[1] 19 | p2 = b[0] * l / b[1] 20 | return s.element_class(s, p1 + p2, l) 21 | 22 | def _mul(s, a, b): 23 | return s.element_class(s, a[0] * b[0], a[1] * b[1]) 24 | 25 | def _neg(s, a): 26 | return s.element_class(s, -a[0], a[1]) 27 | 28 | def _inv(s, a): 29 | return s.element_class(s, a[1], a[0]) 30 | 31 | def _equ(s, a, b): 32 | return a[0] == b[0] and a[1] == b[1] 33 | 34 | def _mod(s, a, b): 35 | return s.element_class(s, a[0] % b[0], a[1]) 36 | 37 | def __str__(s): 38 | return "Fraction Field of %s" % s.ring 39 | 40 | def __repr__(s): 41 | return "%s(%r)" % (s.__class__.__name__, s.ring) 42 | 43 | 44 | class FractionFieldElement(FieldElement): 45 | def __init__(s, *args): 46 | p, q = None, 1 47 | if len(args) >= 1: 48 | if isinstance(args[0], s.__class__): 49 | v = args[0] 50 | p = v.p 51 | q = v.q 52 | field = v.field 53 | elif len(args) >= 2: 54 | field = args[0] 55 | p = args[1] 56 | q = 1 57 | if len(args) == 3: 58 | q = args[2] 59 | if p == None or q == None: 60 | raise TypeError("Invalid Argument: '%s'" % (tuple(map(str, args)),)) 61 | super(FractionFieldElement, s).__init__(field, p) 62 | s.y = q 63 | if hasattr(s.ring.ring, "_div"): 64 | s.p = p / gcd(p, q) 65 | s.q = q / gcd(p, q) 66 | else: 67 | s.p = p 68 | s.q = q 69 | 70 | def __repr__(s): 71 | return "%r(%r, %r)" % (s.field, s.p, s.q) 72 | 73 | def __str__(s): 74 | if s.q == 1: 75 | return "%s" % s.p 76 | return "%s/%s" % (s.p, s.q) 77 | 78 | def __iter__(s): 79 | return (s.p, s.q).__iter__() 80 | 81 | def _to_tuple(s, d): 82 | if isinstance(d, s.__class__): 83 | return tuple(d) 84 | elif isinstance(d, tuple): 85 | return d 86 | else: 87 | return (d, 1) 88 | -------------------------------------------------------------------------------- /ecpy/fields/RationalField.py: -------------------------------------------------------------------------------- 1 | from ecpy.fields.FractionField import FractionField, FractionFieldElement 2 | from ecpy.rings.Integer import ZZ 3 | from ecpy.utils import gcd 4 | 5 | 6 | class RationalField(FractionField): 7 | def __init__(s): 8 | FractionField.__init__(s, ZZ) 9 | s.element_class = RationalFieldElement 10 | 11 | 12 | class RationalFieldElement(FractionFieldElement): 13 | def __init__(s, *args): 14 | FractionFieldElement.__init__(s, *args) 15 | p, q = s.x, s.y 16 | s.p = int(p // gcd(p, q)) 17 | s.q = int(q // gcd(p, q)) 18 | 19 | def __int__(s): 20 | if s.p % s.q != 0: 21 | raise ValueError("Can't divide a value: %s" % s) 22 | return s.p // s.q 23 | 24 | 25 | QQ = RationalField() 26 | -------------------------------------------------------------------------------- /ecpy/fields/RealField.py: -------------------------------------------------------------------------------- 1 | from .Field import Field, FieldElement 2 | 3 | 4 | class RealField(Field): 5 | def __init__(s): 6 | Field.__init__(s, RealFieldElement) 7 | 8 | def __repr__(s): 9 | return "RealField()" 10 | 11 | def __str__(s): 12 | return "RealField()" 13 | 14 | def _add(s, a, b): 15 | return s.element_class(s, a[0] + b[0]) 16 | 17 | def _mul(s, a, b): 18 | return s.element_class(s, a[0] * b[0]) 19 | 20 | def _neg(s, a): 21 | return s.element_class(s, -a[0]) 22 | 23 | def _inv(s, a): 24 | return s.element_class(s, 1.0 / a[0]) 25 | 26 | def _equ(s, a, b): 27 | d = a[0] - b[0] 28 | if isinstance(d, RealFieldElement): 29 | d = d.x 30 | return abs(d) < 0.00001 31 | 32 | 33 | class RealFieldElement(FieldElement): 34 | pass 35 | 36 | 37 | RR = RealField() 38 | -------------------------------------------------------------------------------- /ecpy/fields/Zmod.py: -------------------------------------------------------------------------------- 1 | from ecpy.utils import modinv, euler_phi 2 | from .Field import Field, FieldElement 3 | 4 | 5 | class Zmod(Field): 6 | def __init__(s, n): 7 | Field.__init__(s, ZmodElement) 8 | s.n = n 9 | 10 | def __repr__(s): 11 | return "%s(%s)" % (s.__class__.__name__, s.n) 12 | 13 | def __str__(s, var="n"): 14 | return "%s : %s = %d" % (s.__class__.__name__, var, s.n) 15 | 16 | def order(s): 17 | return euler_phi(s.n) 18 | 19 | def _ord(s, a): 20 | a = a[0] 21 | i = 1 22 | while i <= s.order(): 23 | if s.element_class(s, a) ** i == 1: 24 | return i 25 | i += 1 26 | return 0 27 | 28 | def _add(s, a, b): 29 | return s.element_class(s, a[0] + b[0]) 30 | 31 | def _mul(s, a, b): 32 | return s.element_class(s, a[0] * b[0]) 33 | 34 | def _inv(s, a): 35 | return s.element_class(s, modinv(a[0], s.n)) 36 | 37 | def _neg(s, a): 38 | return s.element_class(s, s.n - a[0]) 39 | 40 | def _equ(s, a, b): 41 | return a[0] == b[0] 42 | 43 | def _mod(s, a, b): 44 | return s.element_class(s, a[0] % b[0]) 45 | 46 | 47 | class ZmodElement(FieldElement): 48 | def __init__(s, field, x): 49 | FieldElement.__init__(s, field, x) 50 | if isinstance(x, s.__class__): 51 | x = x.x % (field.n) 52 | else: 53 | x = x % (field.n) 54 | s.x = x 55 | 56 | def __repr__(s): 57 | return "%r(%s)" % (s.field, s.x) 58 | 59 | def __str__(s): 60 | return "%s" % s.x 61 | -------------------------------------------------------------------------------- /ecpy/fields/__init__.py: -------------------------------------------------------------------------------- 1 | from .ComplexField import CC 2 | from .ExtendedFiniteField import ExtendedFiniteField 3 | from .FractionField import FractionField 4 | from .FiniteField import FiniteField 5 | from .RationalField import QQ 6 | from .RealField import RR 7 | from .Zmod import Zmod 8 | -------------------------------------------------------------------------------- /ecpy/rings/CommutativeRing.py: -------------------------------------------------------------------------------- 1 | from .Ring import Ring, RingElement 2 | 3 | 4 | class CommutativeRing(Ring): 5 | def __init__(s, element_class): 6 | Ring.__init__(s, element_class) 7 | 8 | 9 | class CommutativeRingElement(RingElement): 10 | def __init__(s, ring, x): 11 | RingElement.__init__(s, ring, x) 12 | 13 | def __radd__(s, lhs): 14 | return s + lhs 15 | 16 | def __rsub__(s, lhs): 17 | return -s + lhs 18 | 19 | def __rmul__(s, lhs): 20 | return s * lhs 21 | -------------------------------------------------------------------------------- /ecpy/rings/Integer.py: -------------------------------------------------------------------------------- 1 | from .CommutativeRing import CommutativeRing, CommutativeRingElement 2 | 3 | 4 | class Integer(CommutativeRing): 5 | def __init__(s): 6 | CommutativeRing.__init__(s, IntegerElement) 7 | 8 | def _add(s, a, b): 9 | return a[0] + b[0] 10 | 11 | def _neg(s, a): 12 | return -a[0] 13 | 14 | def _equ(s, a, b): 15 | return len(a) == len(b) == 1 and a[0] == b[0] 16 | 17 | 18 | class IntegerElement(CommutativeRingElement): 19 | def __init__(s, ring, x): 20 | CommutativeRingElement.__init__(s, ring, x) 21 | 22 | def __mul__(s, rhs, mod=None): 23 | import six 24 | 25 | if isinstance(rhs, IntegerElement): 26 | return s.__class__(s.ring, s.x * rhs.x) 27 | elif isinstance(rhs, six.integer_types): 28 | return s.__class__(s.ring, s.x * rhs) 29 | else: 30 | raise ValueError("Invalid Value: %r" % rhs) 31 | 32 | def __floordiv__(s, rhs): 33 | return s.__div__(rhs) 34 | 35 | def __truediv__(s, rhs): 36 | return s.__div__(rhs) 37 | 38 | def __rfloordiv__(s, lhs): 39 | return s.__rdiv__(lhs) 40 | 41 | def __rtruediv__(s, lhs): 42 | return s.__rdiv__(lhs) 43 | 44 | def __div__(s, rhs): 45 | import six 46 | 47 | if rhs == 0: 48 | raise ZeroDivisionError() 49 | if isinstance(rhs, IntegerElement): 50 | return s.__class__(s.ring, s.x // rhs.x) 51 | elif isinstance(rhs, six.integer_types): 52 | return s.__class__(s.ring, s.x // rhs) 53 | elif hasattr(rhs, "__rfloordiv__"): 54 | return rhs.__rfloordiv__(s.x) 55 | else: 56 | raise ValueError("Invalid Value: %r" % rhs) 57 | 58 | def __rdiv__(s, lhs): 59 | import six 60 | 61 | if lhs == 0: 62 | raise ZeroDivisionError() 63 | if isinstance(lhs, IntegerElement): 64 | return s.__class__(s.ring, lhs.x // s.x) 65 | elif isinstance(lhs, six.integer_types): 66 | return s.__class__(s.ring, lhs // s.x) 67 | elif hasattr(lhs, "__floordiv__"): 68 | return lhs.__floordiv__(s.x) 69 | else: 70 | raise ValueError("Invalid Value: %r" % rhs) 71 | 72 | 73 | ZZ = Integer() 74 | -------------------------------------------------------------------------------- /ecpy/rings/QuotientRing.py: -------------------------------------------------------------------------------- 1 | from .Ring import Ring, RingElement 2 | 3 | 4 | class QuotientRing(Ring): 5 | def __init__(s, base_ring, modulo): 6 | assert isinstance(base_ring, Ring) 7 | Ring.__init__(s, QuotientRingElement) 8 | s.base_ring = base_ring 9 | s.modulo = modulo 10 | 11 | def __str__(s): 12 | return "Quotient ring of %s modulo %s" % (s.base_ring, s.modulo) 13 | 14 | def __repr__(s): 15 | return "%s(%r, %r)" % (s.__class__.__name__, s.base_ring, s.modulo) 16 | 17 | 18 | class QuotientRingElement(RingElement): 19 | def __init__(s, ring, x): 20 | RingElement.__init__(s, ring, x) 21 | s.x = s.x % ring.modulo 22 | 23 | def lift(s): 24 | return s._lift(s) 25 | 26 | def _lift(s, t): 27 | if isinstance(t, QuotientRingElement): 28 | assert t.ring == s.ring 29 | x = t.x 30 | else: 31 | x = t 32 | return x 33 | 34 | def __add__(s, rhs): 35 | x = s.x 36 | y = s._lift(rhs) 37 | return s.__class__(s.ring, x + y) 38 | 39 | def __sub__(s, rhs): 40 | x = s.x 41 | y = s._lift(rhs) 42 | return s.__class__(s.ring, x - y) 43 | 44 | def __mul__(s, rhs): 45 | x = s.x 46 | y = s._lift(rhs) 47 | return s.__class__(s.ring, x * y) 48 | 49 | def __rmul__(s, lhs): 50 | x = s._lift(lhs) 51 | y = s.x 52 | return s.__class__(s.ring, x * y) 53 | 54 | def __rtruediv__(s, lhs): 55 | return s.__rdiv__(lhs) 56 | 57 | def __rfloordiv__(s, lhs): 58 | return s.__rdiv__(lhs) 59 | 60 | def __truediv__(s, rhs): 61 | return s.__div__(rhs) 62 | 63 | def __floordiv__(s, rhs): 64 | return s.__div__(rhs) 65 | 66 | def __div__(s, rhs): 67 | from ecpy.utils import egcd 68 | 69 | x = s.x 70 | y = s._lift(rhs) 71 | return s.__class__(s.ring, x * egcd(y, s.ring.modulo)[1]) 72 | 73 | def __rdiv__(s, lhs): 74 | from ecpy.utils import egcd 75 | 76 | x = s._lift(lhs) 77 | y = s.x 78 | return s.__class__(s.ring, x * egcd(y, s.ring.modulo)[1]) 79 | 80 | def __neg__(s): 81 | return s.__class__(s.ring, s.x) 82 | 83 | def __eq__(s, rhs): 84 | x = s.x 85 | y = s._lift(rhs) 86 | return x == y 87 | 88 | def __str__(s): 89 | return str(s.x) 90 | 91 | def __iter__(s): 92 | if hasattr(s.x, "__iter__"): 93 | return iter(s.x) 94 | return RingElement.__iter__(s) 95 | -------------------------------------------------------------------------------- /ecpy/rings/Ring.py: -------------------------------------------------------------------------------- 1 | class Ring(object): 2 | def __init__(s, element_class): 3 | s.element_class = element_class 4 | 5 | def __repr__(s): 6 | return "%s()" % s.__class__.__name__ 7 | 8 | def __str__(s): 9 | return s.__class__.__name__ 10 | 11 | def __call__(s, *x): 12 | return s.element_class(s, *x) 13 | 14 | def _add(s, a, b): 15 | raise NotImplementedError() 16 | 17 | def _mul(s, a, b): 18 | raise NotImplementedError() 19 | 20 | def _neg(s, a, b): 21 | raise NotImplementedError() 22 | 23 | def _equ(s, a, b): 24 | raise NotImplementedError() 25 | 26 | def order(s): 27 | return 0 28 | 29 | def _ord(s, a): 30 | return 0 31 | 32 | def degree(s): 33 | return 1 34 | 35 | 36 | class RingElement(object): 37 | def __init__(s, ring, x): 38 | s.ring = ring 39 | s.x = x 40 | 41 | def change_ring(s, _ring): 42 | return s.__class__(_ring, *tuple(s)) 43 | 44 | def __mul__(s, rhs, mod=None): 45 | return s.ring._mul(tuple(s), s._to_tuple(rhs)) 46 | 47 | def __rmul__(s, lhs): 48 | return s.ring._mul(s._to_tuple(lhs), tuple(s)) 49 | 50 | def __getitem__(s, idx): 51 | return s._to_tuple(s)[idx] 52 | 53 | def __len__(s): 54 | return 1 55 | 56 | def order(s): 57 | return s.ring._ord(tuple(s)) 58 | 59 | def int(s): 60 | return int(s.x) 61 | 62 | def __add__(s, rhs): 63 | return s.ring._add(tuple(s), s._to_tuple(rhs)) 64 | 65 | def __sub__(s, rhs): 66 | return s.ring._add(tuple(s), s._to_tuple(-rhs)) 67 | 68 | def __neg__(s): 69 | return s.ring._neg(tuple(s)) 70 | 71 | def __radd__(s, lhs): 72 | return s.ring._add(s._to_tuple(lhs), tuple(s)) 73 | 74 | def __rsub__(s, lhs): 75 | return s.ring._add(s._to_tuple(-lhs), tuple(s)) 76 | 77 | def __ne__(s, rhs): 78 | return not (s == rhs) 79 | 80 | def __eq__(s, rhs): 81 | return s.ring._equ(tuple(s), s._to_tuple(rhs)) 82 | 83 | def __repr__(s): 84 | return "%r(%s)" % (s.ring, s.x) 85 | 86 | def __str__(s): 87 | return "%s" % s.x 88 | 89 | def _to_tuple(s, d): 90 | if isinstance(d, s.__class__): 91 | return tuple(d) 92 | elif isinstance(d, tuple): 93 | return d 94 | else: 95 | return (d,) 96 | 97 | def __iter__(s): 98 | return (s.x,).__iter__() 99 | 100 | def __int__(s): 101 | return s.int() 102 | 103 | def __hash__(s): 104 | return hash(str(s.x) + str(s.ring)) 105 | -------------------------------------------------------------------------------- /ecpy/rings/__init__.py: -------------------------------------------------------------------------------- 1 | from .Integer import ZZ 2 | from .QuotientRing import QuotientRing 3 | from .polynomial_uni import UnivariatePolynomialRing 4 | from .polynomial_multi import BivariatePolynomialRing 5 | -------------------------------------------------------------------------------- /ecpy/rings/polynomial_multi.py: -------------------------------------------------------------------------------- 1 | from .polynomial_uni import UnivariatePolynomialElement 2 | from .polynomial_uni import UnivariatePolynomialRing 3 | from .Ring import Ring, RingElement 4 | from six.moves import map, xrange, zip_longest 5 | from ecpy.utils import memoize 6 | from copy import deepcopy 7 | import itertools 8 | 9 | 10 | class BivariatePolynomialRing(Ring): 11 | """ 12 | Bivariate Polynomial Ring 13 | """ 14 | 15 | def __init__(s, field, gens): 16 | """ 17 | Args: 18 | field : A base field class 19 | gens : generator names 20 | 21 | Example: 22 | PR = BivariatePolynomialRing(RR, ['x', 'y']) 23 | """ 24 | Ring.__init__(s, BivariatePolynomialElement) 25 | assert len(gens) == 2 26 | s.field = field 27 | s.gen_names = gens 28 | 29 | def gens(s): 30 | ret = [] 31 | ret += [s.element_class(s, [[0, 1]])] 32 | ret += [s.element_class(s, [[0], [1]])] 33 | return ret 34 | 35 | def _add(s, A, B): 36 | # A + B 37 | if len(A) == 1 and len(A[0]) == 1: 38 | A = A[0][0] 39 | return s.element_class(s, [[A + B[0][0]] + list(B[0][1:])] + list(B[1:])) 40 | elif len(B) == 1 and len(B[0]) == 1: 41 | B = B[0][0] 42 | return s.element_class(s, [[A[0][0] + B] + list(A[0][1:])] + list(A[1:])) 43 | ret = [] 44 | for x, y in zip_longest(A, B, fillvalue=[0]): 45 | t = [] 46 | for xs, ys in zip_longest(x, y, fillvalue=0): 47 | t += [xs + ys] 48 | ret += [t] 49 | return s.element_class(s, ret) 50 | 51 | def _mul(s, A, B): 52 | if len(A) == 1 and len(A[0]) == 1: 53 | A = A[0][0] 54 | return s.element_class(s, map(lambda y: map(lambda x: A * x, y), B)) 55 | elif len(B) == 1 and len(B[0]) == 1: 56 | B = B[0][0] 57 | return s.element_class(s, map(lambda y: map(lambda x: x * B, y), A)) 58 | deg_total_1 = max([len(X) + len(Y) - 1 for X, Y in itertools.product(A, B)]) 59 | deg_total_2 = len(list(itertools.product(A, B))) 60 | ret = [[0] * deg_total_1 for _ in xrange(deg_total_2)] 61 | deg1 = 0 62 | for X in A: 63 | deg2 = 0 64 | for Y in B: 65 | for x, y in enumerate(X): 66 | for u, v in enumerate(Y): 67 | ret[deg1 + deg2][x + u] += y * v 68 | deg2 += 1 69 | deg1 += 1 70 | return s.element_class(s, ret) 71 | 72 | def _neg(s, A): 73 | return s.element_class(s, map(lambda y: map(lambda x: -x, y), A)) 74 | 75 | def _equ(s, A, B): 76 | if len(A) == 1 and len(A[0]) == 1 and len(B) == 1 and len(B[0]) == 1: 77 | return A[0][0] == B[0][0] 78 | return all( 79 | [ 80 | all([s == t for s, t in zip_longest(x, y, fillvalue=0)]) 81 | for x, y in zip(A, B) 82 | ] 83 | ) 84 | 85 | def __repr__(s): 86 | return "%s(%r, %r)" % (s.__class__.__name__, s.field, s.gen_names) 87 | 88 | def __str__(s): 89 | return "Bivariate Polynomial Ring over %s" % s.field 90 | 91 | 92 | class BivariatePolynomialElement(RingElement): 93 | def __init__(s, poly_ring, args): 94 | RingElement.__init__(s, poly_ring, args) 95 | if isinstance(args, BivariatePolynomialElement): 96 | s.coeffs = args.coeffs 97 | elif hasattr(args, "__iter__"): 98 | s.coeffs = list(args) 99 | else: 100 | s.coeffs = [[args]] 101 | s.trim() 102 | s.coeffs = list(map(lambda y: list(map(s.ring.field, y)), s.coeffs)) 103 | 104 | def __getitem__(s, idx): 105 | return s.coeffs[idx] 106 | 107 | def __iter__(s): 108 | return iter(s.coeffs) 109 | 110 | def __len__(s): 111 | return len(s.coeffs) 112 | 113 | def __pow__(s, rhs, mod=0): 114 | if rhs == 0: 115 | return s.__class__(s.ring, [[1]]) 116 | d = rhs 117 | if d < 0: 118 | x = 1 / s 119 | d = -d 120 | else: 121 | x = s 122 | bits = list(map(int, bin(d)[2:]))[::-1] 123 | if bits[0]: 124 | res = x 125 | else: 126 | res = s.__class__(s.ring, [[1]]) 127 | b = 0 128 | for cur in bits[1:]: 129 | b += 1 130 | x *= x 131 | if mod > 0: 132 | x %= mod 133 | x.trim() 134 | if cur: 135 | res *= x 136 | if mod > 0: 137 | res %= mod 138 | res.trim() 139 | return res 140 | 141 | def __str__(s): 142 | if len(s.coeffs) == 0: 143 | return "0" 144 | res = [] 145 | deg1 = 0 146 | for y in s.coeffs: 147 | deg2 = 0 148 | res2 = [] 149 | for x in y: 150 | r = "" 151 | if x != 0: 152 | if (x != -1 and x != 1) or deg2 == 0: 153 | r += str(x) 154 | elif x == -1: 155 | r += "-" 156 | if deg2 > 0: 157 | r += s.ring.gen_names[0] 158 | if deg2 > 1: 159 | r += "^%d" % deg2 160 | if r != "": 161 | res2 += [r] 162 | deg2 += 1 163 | r = "+".join(res2[::-1]).replace("+-", "-") 164 | if len(r) != 0: 165 | if deg1 > 0: 166 | if deg2 > 2: 167 | r = "(" + r + ")" 168 | if deg1 == 1: 169 | r += s.ring.gen_names[1] 170 | else: 171 | r += "%s^%d" % (s.ring.gen_names[1], deg1) 172 | if r[:2] == "1y": 173 | r = r.lstrip("1") 174 | if r != "": 175 | res += [r] 176 | deg1 += 1 177 | if len(res) == 0: 178 | return "0" 179 | return "+".join(res).replace("+-", "-") 180 | 181 | @memoize 182 | def apply(s, x0, y0): 183 | """ 184 | Using Horner's method 185 | """ 186 | ret = 0 187 | for y in s.coeffs[::-1]: 188 | t = 0 189 | for x in y[::-1]: 190 | t = t * x0 + x 191 | ret = ret * y0 + t 192 | return ret 193 | 194 | def degree(s): 195 | return max([len(x) + i - 1 for i, x in enumerate(s.coeffs)]) 196 | 197 | def monic(s): 198 | return s / s[-1] 199 | 200 | def trim(s): 201 | res = [] 202 | for y in s.coeffs: 203 | i = 0 204 | r = list(y) 205 | for x in r[::-1]: 206 | if x != 0: 207 | break 208 | i += 1 209 | if 0 < i < len(r): 210 | r = r[:-i] 211 | elif i == len(r): 212 | r = [0] 213 | res += [r] 214 | i = 0 215 | for r in res[::-1]: 216 | if not (len(r) == 1 and r[0] == 0): 217 | break 218 | i += 1 219 | if i < len(res): 220 | if 0 < i: 221 | s.coeffs = res[:-i] 222 | else: 223 | s.coeffs = res 224 | elif i == len(res): 225 | s.coeffs = [[0]] 226 | 227 | def __hash__(s): 228 | return hash("".join(map(str, s.coeffs)) + str(s.ring)) 229 | 230 | def _to_tuple(s, d): 231 | if isinstance(d, s.__class__): 232 | return tuple(d) 233 | elif isinstance(d, tuple): 234 | return d 235 | else: 236 | return ((d,),) 237 | -------------------------------------------------------------------------------- /ecpy/rings/polynomial_uni.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy 2 | from ecpy.utils import memoize 3 | from .Ring import Ring, RingElement 4 | from six.moves import map, xrange, zip_longest 5 | 6 | 7 | class UnivariatePolynomialRing(Ring): 8 | """ 9 | Univariate Polynomial Ring 10 | """ 11 | 12 | def __init__(s, field, gen="x"): 13 | """ 14 | Args: 15 | field : A base field class 16 | """ 17 | Ring.__init__(s, UnivariatePolynomialElement) 18 | s.field = field 19 | s.gen_name = gen 20 | 21 | def gen(s): 22 | return s.element_class(s, 0, 1) # x 23 | 24 | def __str__(s): 25 | return "Univariate Polynomial Ring over %s" % s.field 26 | 27 | def _add(s, A, B): 28 | if len(A) == 1: 29 | return s.element_class(s, [A[0] + B[0]] + list(B[1:])) 30 | elif len(B) == 1: 31 | return s.element_class(s, [A[0] + B[0]] + list(A[1:])) 32 | ret = [] 33 | for x, y in zip_longest(A, B, fillvalue=0): 34 | ret += [(x + y)] 35 | return s.element_class(s, ret) 36 | 37 | def _mul(s, A, B): 38 | if len(A) == 1: 39 | return s.element_class(s, map(lambda x: A[0] * x, B)) 40 | elif len(B) == 1: 41 | return s.element_class(s, map(lambda x: x * B[0], A)) 42 | ret = [0] * (len(A) + len(B) - 1) 43 | for x, y in enumerate(A): 44 | for u, v in enumerate(B): 45 | ret[x + u] += y * v 46 | return s.element_class(s, ret) 47 | 48 | def _neg(s, A): 49 | return s.element_class(s, map(lambda x: -x, A)) 50 | 51 | def _equ(s, A, B): 52 | from six.moves import zip_longest 53 | 54 | if len(A) == 1 and len(B) == 1: 55 | return A[0] == B[0] 56 | return all([x == y for x, y in zip_longest(A, B, fillvalue=0)]) 57 | 58 | 59 | class UnivariatePolynomialElement(RingElement): 60 | def __init__(s, poly_ring, *args): 61 | """ 62 | coeffs = [x^0, x^1, x^2, ... degree's coefficient] 63 | """ 64 | RingElement.__init__(s, poly_ring, args) 65 | if len(args) == 1: 66 | v = args[0] 67 | if isinstance(v, UnivariatePolynomialElement): 68 | s.coeffs = v.coeffs 69 | elif hasattr(v, "__iter__"): 70 | s.coeffs = list(v) 71 | else: 72 | s.coeffs = [v] 73 | else: 74 | s.coeffs = args 75 | s.trim() 76 | s.coeffs = list(map(s.ring.field, s.coeffs)) 77 | 78 | def __rdivmod__(s, lhs): 79 | if not isinstance(lhs, UnivariatePolynomialElement): 80 | lhs = s.__class__(s.ring, lhs) 81 | return divmod(lhs, s) 82 | 83 | def __divmod__(s, rhs): 84 | assert rhs != 0 85 | if isinstance(rhs, UnivariatePolynomialElement): 86 | if len(rhs) == 1: 87 | q = UnivariatePolynomialElement( 88 | s.ring, map(lambda x: x / rhs[0], s.coeffs) 89 | ) 90 | r = UnivariatePolynomialElement( 91 | s.ring, map(lambda x: x % rhs[0], s.coeffs) 92 | ) 93 | return q, r 94 | q = UnivariatePolynomialElement(s.ring, 0) 95 | r = s 96 | d = rhs.degree() 97 | c = rhs[-1] 98 | while r.degree() >= d: 99 | t = UnivariatePolynomialElement(s.ring, [r[-1] / c]).shift( 100 | r.degree() - d 101 | ) 102 | q = q + t 103 | r = r - t * rhs 104 | return q, r 105 | else: 106 | q = UnivariatePolynomialElement(s.ring, map(lambda x: x / rhs, s.coeffs)) 107 | r = UnivariatePolynomialElement(s.ring, map(lambda x: x % rhs, s.coeffs)) 108 | return q, r 109 | 110 | def __div__(s, rhs): 111 | return divmod(s, rhs)[0] 112 | 113 | def __truediv__(s, rhs): 114 | return s.__div__(rhs) 115 | 116 | def __floordiv__(s, rhs): 117 | return s.__div__(rhs) 118 | 119 | def __getitem__(s, idx): 120 | return s.coeffs[idx] 121 | 122 | def __iter__(s): 123 | return iter(s.coeffs) 124 | 125 | def __len__(s): 126 | return len(s.coeffs) 127 | 128 | def __mod__(s, rhs): 129 | return divmod(s, rhs)[1] 130 | 131 | def __rmod__(s, lhs): 132 | return divmod(lhs, s)[1] 133 | 134 | def __pow__(s, rhs, mod=0): 135 | if rhs == 0: 136 | return UnivariatePolynomialElement(s.ring, 1) 137 | d = int(rhs) 138 | if d < 0: 139 | x = 1 / s 140 | d = -d 141 | else: 142 | x = s 143 | bits = list(map(int, bin(d)[2:]))[::-1] 144 | if bits[0]: 145 | res = x 146 | else: 147 | res = UnivariatePolynomialElement(s.ring, 1) 148 | b = 0 149 | for cur in bits[1:]: 150 | b += 1 151 | x *= x 152 | if mod > 0: 153 | x %= mod 154 | x.trim() 155 | if cur: 156 | res *= x 157 | if mod > 0: 158 | res %= mod 159 | res.trim() 160 | return res 161 | 162 | def __str__(s): 163 | if len(s.coeffs) == 0: 164 | return "0" 165 | res = [] 166 | deg = 0 167 | for x in s: 168 | r = "" 169 | if x != 0: 170 | if (x != -1 and x != 1) or deg == 0: 171 | r += str(x) 172 | elif x == -1: 173 | r += "-" 174 | if deg > 0: 175 | r += s.ring.gen_name 176 | if deg > 1: 177 | r += "^%d" % deg 178 | if r != "": 179 | res += [r] 180 | deg += 1 181 | if len(res) == 0: 182 | return "0" 183 | return "+".join(res[::-1]).replace("+-", "-") 184 | 185 | @memoize 186 | def apply(s, x0): 187 | """ 188 | Using Horner's method 189 | """ 190 | ret = 0 191 | for x in s.coeffs[::-1]: 192 | ret = ret * x0 + x 193 | return ret 194 | 195 | def degree(s): 196 | return len(s.coeffs) - 1 197 | 198 | def monic(s): 199 | return s / s[-1] 200 | 201 | def shift(s, i): 202 | if i > 0: 203 | return UnivariatePolynomialElement(s.ring, [0] * abs(i) + s.coeffs) 204 | else: 205 | return UnivariatePolynomialElement(s.ring, s.coeffs[abs(i) :]) 206 | 207 | def trim(s): 208 | i = 0 209 | for x in s.coeffs[::-1]: 210 | if x != 0: 211 | break 212 | i += 1 213 | if 0 < i < len(s.coeffs): 214 | s.coeffs = s.coeffs[:-i] 215 | elif i == len(s.coeffs): 216 | s.coeffs = [0] 217 | 218 | def __hash__(s): 219 | return hash("".join(map(str, s.coeffs)) + str(s.ring)) 220 | -------------------------------------------------------------------------------- /ecpy/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .root import modular_square_root, modular_square_root_extended 2 | from .root import extended_legendre_symbol, cubic_root 3 | from .util import crt, gcd, gcd_multiple, egcd, is_enable_native 4 | from .util import euler_phi, is_prime, jacobi_symbol, legendre_symbol 5 | from .util import lcm, modinv, memoize, miller_rabin 6 | -------------------------------------------------------------------------------- /ecpy/utils/root.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import random 3 | 4 | 5 | def _find_power_divisor(base, x, modulo=None): 6 | k = 0 7 | m = base 8 | while x % m == 0: 9 | k += 1 10 | m = pow(m * base, 1, modulo) 11 | return k 12 | 13 | 14 | def _find_power(power_base, x, crib, modulo=None): 15 | k = 1 16 | r = power_base 17 | while pow(x, r, modulo) != crib: 18 | k += 1 19 | r *= power_base 20 | return k 21 | 22 | 23 | def modular_square_root(a, m, force=False): 24 | """ 25 | Calculate Quadratic Residue 26 | Args: 27 | a: The Target 28 | m: Modulus 29 | Returns: 30 | A Quadratic Residue of a modulo m 31 | """ 32 | from ecpy.fields.ExtendedFiniteField import ExtendedFiniteFieldElement 33 | 34 | if isinstance(a, ExtendedFiniteFieldElement) and not force: 35 | return modular_square_root_extended(a) 36 | else: 37 | return __modular_square_root(int(a), m) 38 | 39 | 40 | def __modular_square_root(a, m): 41 | from ecpy.utils import is_prime, legendre_symbol, modinv 42 | 43 | if is_prime(m): 44 | if legendre_symbol(a, m) == -1: 45 | return [] 46 | # Tonelli-Shanks Algorithm 47 | if m % 4 == 3: 48 | r = pow(a, (m + 1) // 4, m) 49 | return [r, m - r] 50 | s = _find_power_divisor(2, m - 1) 51 | q = (m - 1) // 2**s 52 | z = 0 53 | while legendre_symbol(z, m) != -1: 54 | z = random.randint(1, m) 55 | c = pow(z, q, m) 56 | r = pow(a, (q + 1) // 2, m) 57 | t = pow(a, q, m) 58 | l = s 59 | while True: 60 | if t % m == 1: 61 | assert (r**2) % m == a 62 | return [r, m - r] 63 | i = _find_power(2, t, 1, m) 64 | power = l - i - 1 65 | if power < 0: 66 | power = modinv(2**-power, m) 67 | else: 68 | power = 2**power 69 | b = pow(c, power, m) 70 | r = (r * b) % m 71 | t = (t * (b**2)) % m 72 | c = pow(b, 2, m) 73 | l = i 74 | if m == 2: 75 | return a 76 | if m % 4 == 3: 77 | r = pow(a, (m + 1) // 4, m) 78 | return [r, m - r] 79 | if m % 8 == 5: 80 | v = pow(2 * a, (m - 5) // 8, m) 81 | i = pow(2 * a * v, 2, m) 82 | r = a * v * (i - 1) % m 83 | return [r, m - r] 84 | if m % 8 == 1: 85 | e = _find_power_divisor(2, m - 1) 86 | q = (m - 1) // 2**e 87 | z = 1 88 | while pow(z, 2 ** (e - 1), m) == 1: 89 | x = random.randint(1, m) 90 | z = pow(x, q, m) 91 | y = z 92 | r = e 93 | x = pow(a, (q - 1) // 2, m) 94 | v = a * x % m 95 | w = v * x % m 96 | while True: 97 | if w == 1: 98 | return [v, m - v] 99 | k = _find_power(2, w, 1, m) 100 | d = pow(y, 2 ** (r - k - 1), m) 101 | y = pow(d, 2, m) 102 | r = k 103 | v = d * v % m 104 | w = w * y % m 105 | 106 | 107 | def extended_legendre_symbol(a): 108 | """ 109 | Legendre Symbol on the Extended Field 110 | Args: 111 | a: The Target 112 | Returns: 113 | Legendre Symbol of a 114 | """ 115 | from six.moves import xrange 116 | from ecpy.utils import legendre_symbol 117 | 118 | m = a.field.degree() 119 | p = a.field.p 120 | b = pow(a, sum([p**i for i in xrange(0, m)]), p) 121 | return legendre_symbol(b, p) 122 | 123 | 124 | def modular_square_root_extended(x): 125 | """ 126 | Calculate Quadratic Residue on Extended Field 127 | Args: 128 | x: The Target 129 | Returns: 130 | A square root of x 131 | """ 132 | if extended_legendre_symbol(x) != 1: 133 | return [] 134 | a = x 135 | 136 | m = a.field.degree() 137 | p = a.field.p 138 | q = p ** (m // 2) 139 | if m % 2 == 0: 140 | if pow(q, m // 2, 4) == 1: 141 | c0 = 1 142 | while c0 == 1: 143 | c = x.field(random.randint(0, q**2), random.randint(0, q**2)) 144 | c0 = extended_legendre_symbol(c) 145 | d = pow(c, (q - 1) // 2) 146 | e = 1 // (c * d) 147 | f = (c * d) ** 2 148 | b = pow(a, (q - 1) // 4) 149 | b2 = b**2 150 | a0 = (b2) ** q * b2 151 | if a0 == -1: 152 | return [] 153 | R = b2 * a 154 | S = b**q 155 | if b ** (q + 1) != 1: 156 | S *= e 157 | R *= f 158 | x0 = modular_square_root(R, q, force=True)[0] 159 | return [x0 * S] 160 | elif pow(q, m // 2, 4) == 3: 161 | pass 162 | else: 163 | pass 164 | else: 165 | raise NotImplementedError( 166 | "If you want to use function, please implement " 167 | "Shanks, Atkin, Kong et al, Mueller, Tonelli-" 168 | "Shanks, ... algorithm." 169 | ) 170 | 171 | 172 | def cubic_root(x): 173 | """ 174 | Calculate Cubic Residue 175 | Args: 176 | x: The Target 177 | Returns: 178 | A Cubic Residue of x 179 | """ 180 | F = x.field 181 | p = F.p 182 | m = F.degree() 183 | rho = 1 184 | pm = p**m 185 | r = (pm - 1) // 3 186 | rho = 1 187 | while rho**r == 1: 188 | rho = F(random.randint(1, p - 1), random.randint(1, p - 1)) 189 | t = 1 190 | while True: 191 | r = 3**t 192 | if (pm - 1) % r == 0: 193 | t += 1 194 | else: 195 | t -= 1 196 | s = (pm - 1) // 3**t 197 | if (s + 1) % 3 == 0: 198 | l = (s + 1) // 3 199 | break 200 | elif (s - 1) % 3 == 0: 201 | l = (s - 1) // 3 202 | break 203 | a = rho**s 204 | a_ = rho ** (3 ** (t - 1) * s) 205 | b = x**s 206 | h = 1 207 | i = 1 208 | while i < t: 209 | d = b ** (3 ** (t - 1 - i)) 210 | if d == 1: 211 | k = 0 212 | elif d == a_: 213 | k = 2 214 | else: 215 | k = 1 216 | b = b * (a * a * a) ** k 217 | h = h * a**k 218 | a = a * a * a 219 | i += 1 220 | r = x**l * h 221 | if s == 3 * l + 1: 222 | r = 1 // r 223 | return r 224 | -------------------------------------------------------------------------------- /ecpy/utils/util.py: -------------------------------------------------------------------------------- 1 | import operator as op 2 | import random 3 | import sys 4 | 5 | 6 | def memoize(f): 7 | cache = {} 8 | 9 | def helper(*args): 10 | if args not in cache: 11 | cache[args] = f(*args) 12 | return cache[args] 13 | 14 | return helper 15 | 16 | 17 | def gcd(x, y): 18 | """ 19 | Calculate greatest common divisor 20 | """ 21 | while y != 0: 22 | t = x % y 23 | x, y = y, t 24 | return x 25 | 26 | 27 | def gcd_multiple(*a): 28 | from six.moves import reduce 29 | 30 | """ 31 | Apply gcd to some variables. 32 | Args: 33 | a: args list 34 | """ 35 | return reduce(gcd, a) 36 | 37 | 38 | def egcd(a, b): 39 | """ 40 | Calculate Extended-gcd 41 | """ 42 | x, y, u, v = 0, 1, 1, 0 43 | while a != 0: 44 | q, r = b // a, b % a 45 | m, n = x - u * q, y - v * q 46 | b, a, x, y, u, v = a, r, u, v, m, n 47 | return (b, x, y) 48 | 49 | 50 | def lcm(*a): 51 | from six.moves import reduce 52 | 53 | """ 54 | Calculate Least Common Multiple 55 | Args: 56 | *a: args list 57 | """ 58 | return reduce(op.mul, a) // gcd_multiple(*a) 59 | 60 | 61 | def crt(ak, nk): 62 | from six.moves import reduce 63 | 64 | """ 65 | Chinese-Reminders-Theorem Implementation 66 | using Gauss's proof and generalization on gcd(n1, n2) != 1 67 | Should be len(ak) == len(nk) 68 | Original: https://gist.github.com/elliptic-shiho/901d223135965308a5f9ff0cf99dd7c8 69 | Explanation: http://elliptic-shiho.hatenablog.com/entry/2016/04/03/020117 70 | 71 | Args: 72 | ak: A Numbers [a1, a2, ..., ak] 73 | nk: A Modulus [n1, n2, ..., nk] 74 | """ 75 | assert len(ak) == len(nk) 76 | N = reduce(lambda x, y: x * y, nk, 1) 77 | l = lcm(*nk) 78 | s = 0 79 | for n, a in zip(nk, ak): 80 | m = N // n 81 | g, x, y = egcd(m, n) 82 | s += (m // g) * x * a 83 | s %= l 84 | return s 85 | 86 | 87 | def legendre_symbol(a, p): 88 | """ 89 | Calculate Legendre Symbol using Euler's criterion 90 | """ 91 | if gcd(a, p) != 1: 92 | return 0 93 | d = pow(a, ((p - 1) // 2), p) 94 | if d == p - 1: 95 | return -1 96 | return 1 97 | 98 | 99 | def jacobi_symbol(a, n): 100 | """ 101 | Calculate Jacobi Symbol. 102 | """ 103 | if is_prime(n): 104 | return legendre_symbol(a, n) 105 | j = 1 106 | while a != 0: 107 | while not a % 2: 108 | a //= 2 109 | if n & 7 == 3 or n & 7 == 5: 110 | j = -j 111 | a, n = n, a 112 | if a & 3 == 3 and n & 3 == 3: 113 | j = -j 114 | a %= n 115 | if n: 116 | return j 117 | return 0 118 | 119 | 120 | def miller_rabin(x): 121 | from six.moves import xrange 122 | 123 | if x < 542: 124 | return x in [ 125 | 2, 126 | 3, 127 | 5, 128 | 7, 129 | 11, 130 | 13, 131 | 17, 132 | 19, 133 | 23, 134 | 29, 135 | 31, 136 | 37, 137 | 41, 138 | 43, 139 | 47, 140 | 53, 141 | 59, 142 | 61, 143 | 67, 144 | 71, 145 | 73, 146 | 79, 147 | 83, 148 | 89, 149 | 97, 150 | 101, 151 | 103, 152 | 107, 153 | 109, 154 | 113, 155 | 127, 156 | 131, 157 | 137, 158 | 139, 159 | 149, 160 | 151, 161 | 157, 162 | 163, 163 | 167, 164 | 173, 165 | 179, 166 | 181, 167 | 191, 168 | 193, 169 | 197, 170 | 199, 171 | 211, 172 | 223, 173 | 227, 174 | 229, 175 | 233, 176 | 239, 177 | 241, 178 | 251, 179 | 257, 180 | 263, 181 | 269, 182 | 271, 183 | 277, 184 | 281, 185 | 283, 186 | 293, 187 | 307, 188 | 311, 189 | 313, 190 | 317, 191 | 331, 192 | 337, 193 | 347, 194 | 349, 195 | 353, 196 | 359, 197 | 367, 198 | 373, 199 | 379, 200 | 383, 201 | 389, 202 | 397, 203 | 401, 204 | 409, 205 | 419, 206 | 421, 207 | 431, 208 | 433, 209 | 439, 210 | 443, 211 | 449, 212 | 457, 213 | 461, 214 | 463, 215 | 467, 216 | 479, 217 | 487, 218 | 491, 219 | 499, 220 | 503, 221 | 509, 222 | 521, 223 | 523, 224 | 541, 225 | ] 226 | 227 | if x % 2 == 0: 228 | return False 229 | 230 | s = 0 231 | while (x - 1) % 2 ** (s + 1) == 0: 232 | s += 1 233 | d = x // (2**s) 234 | prime = 0 235 | for i in xrange(10): # k = 10 236 | a = random.randint(1, x - 1) 237 | if not ( 238 | pow(a, d, x) != 1 239 | and all([pow(a, 2**r * d, x) != x - 1 for r in xrange(0, s)]) 240 | ): 241 | prime += 1 242 | return prime > 6 243 | 244 | 245 | def _check_external_modules(): 246 | global _gmpy, _is_prime, _native, is_enable_native, _primefac 247 | try: 248 | import gmpy 249 | 250 | _gmpy = gmpy 251 | _is_prime = gmpy.is_prime 252 | except ImportError: 253 | _is_prime = miller_rabin 254 | try: 255 | import ecpy.native 256 | 257 | _native = ecpy.native 258 | is_enable_native = True 259 | except ImportError: 260 | _native = None 261 | is_enable_native = False 262 | try: 263 | import primefac 264 | 265 | _primefac = primefac 266 | except ImportError: 267 | _primefac = None 268 | 269 | 270 | @memoize 271 | def is_prime(x): 272 | """ 273 | Is x prime? 274 | Args: 275 | x: Test Number (should be positive integer) 276 | """ 277 | return _is_prime(x) 278 | 279 | 280 | def modinv(a, m): 281 | """ 282 | Calculate Modular Inverse. 283 | - Find x satisfy ax \equiv 1 \mod m 284 | 285 | Args: 286 | a: target number 287 | n: modulus 288 | """ 289 | if gcd(a, m) != 1: 290 | return 0 291 | if a < 0: 292 | a %= m 293 | return egcd(a, m)[1] % m 294 | 295 | 296 | @memoize 297 | def prime_factorization(n): 298 | """ 299 | Prime factorization of `n` 300 | Args: 301 | n: A integer 302 | Return: Factored `n` 303 | 304 | e.g. n = 2, return `{2: 1}`. 305 | """ 306 | if is_prime(n): 307 | return {n: 1} 308 | if _primefac is not None: 309 | return _primefac.factorint(n) 310 | else: 311 | ret = {} 312 | # trial division method - too slow 313 | if n % 2 == 0: 314 | pow_2 = 0 315 | while n % 2 == 0: 316 | pow_2 += 1 317 | n //= 2 318 | ret[2] = pow_2 319 | while not is_prime(n): 320 | k = 3 321 | while n % k != 0: 322 | k += 2 323 | pow_k = 0 324 | while n % k == 0: 325 | pow_k += 1 326 | n //= k 327 | ret[k] = pow_k 328 | if n != 1: 329 | ret[n] = 1 330 | return ret 331 | 332 | 333 | def euler_phi(n): 334 | """ 335 | Calculate Euler's totient function 336 | Args: 337 | n: A integer 338 | Return: Order of the group (Z/nZ)^* 339 | """ 340 | from ecpy.fields import QQ 341 | 342 | ret = 1 343 | factors = prime_factorization(n) 344 | for p in factors: 345 | k = factors[p] 346 | ret *= 1 - QQ(1, p) 347 | return int(ret * n) 348 | 349 | 350 | _check_external_modules() 351 | -------------------------------------------------------------------------------- /examples/boneh_lynn_shacham_short_signature.py: -------------------------------------------------------------------------------- 1 | from ecpy import ExtendedFiniteField, EllipticCurve, MapToPoint 2 | from ecpy import symmetric_tate_pairing 3 | import hashlib 4 | import cPickle 5 | # some secret here 6 | secret = 0xdeadbeef 7 | 8 | p = int("519130854181216822940010183929228824799903608965854344652247095061840" 9 | "171046331806216450362399027718738907160814923275136184823731671523533" 10 | "69121135029626237") 11 | l = (p + 1) / 6 12 | F = ExtendedFiniteField(p, "x^2+x+1") 13 | E = EllipticCurve(F, 0, 1) 14 | 15 | P = E(6, (int("132232566129358054566854866197859888282113525457609791458267738" 16 | "093383172947853439119386209153000327873055642240731797496321750" 17 | "04531990130007962275678599731"), 18 | int("264465132258716109133709732395719776564227050915219582916535476" 19 | "186766345895706878238772418306000655746111284481463594992643500" 20 | "09063980260015924551357199462"))) 21 | 22 | sP = secret * P 23 | 24 | 25 | def sign(m): 26 | global secret, E, l 27 | # Q = MapToPoint(m) 28 | # return secret * Q 29 | h = int(hashlib.sha512(m).hexdigest(), 16) 30 | return secret * MapToPoint(E, E.field(h)) 31 | 32 | 33 | def verify(sig, msg): 34 | global secret, E, l, P, sP 35 | # a = e_l(P, secret * Q) = e_l(P, Q) ^ secret 36 | a = symmetric_tate_pairing(E, P, sig, l) 37 | # Q = MapToPoint(m') 38 | # b = e_l(secret * P, Q) = e_l(P, Q) ^ secret 39 | h = int(hashlib.sha512(msg).hexdigest(), 16) 40 | b = symmetric_tate_pairing(E, sP, MapToPoint(E, E.field(h)), l) 41 | # a = b? 42 | return a == b 43 | 44 | 45 | def main(): 46 | global secret, E, F, l, P, sP 47 | 48 | while True: 49 | print "What to do?" 50 | print "Sign -> s, Verify -> v, Quit -> q :", 51 | t = raw_input().strip().lower() 52 | if t == "s": 53 | print "[+] Message? :", 54 | m = raw_input().strip() 55 | sig = cPickle.dumps(tuple(sign(m))).encode("zlib").encode("base64") 56 | sig = sig.replace("\n", "") 57 | print "[+] Signature of %s: %s" % (m, sig) 58 | elif t == "v": 59 | print "Signature? :", 60 | x, y, z = cPickle.loads(raw_input().strip() 61 | .decode("base64").decode("zlib")) 62 | sig = E(x, y) 63 | print "Message? :", 64 | m = raw_input().strip() 65 | if verify(sig, m): 66 | print "[+] Verify: Passed." 67 | else: 68 | print "[+] Verify: Invalid Signature!" 69 | elif t == "q": 70 | print "[+] Quit" 71 | break 72 | 73 | 74 | if __name__ == "__main__": 75 | main() 76 | -------------------------------------------------------------------------------- /examples/ecdsa.py: -------------------------------------------------------------------------------- 1 | from ecpy import EllipticCurve, FiniteField, gcd, modinv 2 | from ecpy import EllipticCurveRepository 3 | 4 | F, E, G, n = EllipticCurveRepository('secp256k1') 5 | secret = 0xdeadbeef 6 | 7 | Q = secret * G 8 | 9 | public_info = (E, n, G) 10 | public_key = (Q, ) 11 | secret_key = (secret, ) 12 | 13 | def hash_int(m): 14 | ''' 15 | Hashing message and convert to integer 16 | Args: 17 | m: the message(as string) 18 | Return: 19 | SHA-512 hashed message as integer 20 | ''' 21 | import hashlib 22 | return int(hashlib.sha512(m).hexdigest(), 16) 23 | 24 | def ECDSA_sign(m, public_info, secret_key): 25 | import random 26 | E, n, G = public_info 27 | dA, = secret_key 28 | e = hash_int(m) 29 | z = e >> (e.bit_length() - n.bit_length()) 30 | while True: 31 | k = random.randint(1, n - 1) 32 | if gcd(k, n) == 1: 33 | break 34 | r = int((k * G).x) 35 | s = (modinv(k, n) * ((z + r * dA) % n)) % n 36 | return (r, s) 37 | 38 | def ECDSA_verify(m, signature, public_info, public_key): 39 | E, n, G = public_info 40 | Q, = public_key 41 | r, s = signature 42 | assert 1 <= r <= n-1 43 | assert 1 <= s <= n-1 44 | e = hash_int(m) 45 | z = e >> (e.bit_length() - n.bit_length()) 46 | w = modinv(s, n) 47 | u1 = (z * w) % n 48 | u2 = (r * w) % n 49 | if (u1 * G + u2 * Q).x == r: 50 | return True 51 | else: 52 | return False 53 | 54 | if __name__ == '__main__': 55 | import os 56 | print '=== ECDSA Tester ===' 57 | message = os.urandom(16).encode('base64') 58 | print '[+] to sign message: %s' % message 59 | signature = ECDSA_sign(message, public_info, secret_key) 60 | print '[+] Signature: %r' % (signature, ) 61 | print '[+] Verify : Correct message => %s' % ECDSA_verify(message, signature, public_info, public_key) 62 | print '[+] Verify : Invalid message => %s' % ECDSA_verify('hogefugathisisinvalidmessage', signature, public_info, public_key) 63 | -------------------------------------------------------------------------------- /examples/id_based_encryption.py: -------------------------------------------------------------------------------- 1 | from ecpy import EllipticCurve, ExtendedFiniteField, symmetric_tate_pairing 2 | import hashlib 3 | import random 4 | import cPickle 5 | 6 | # PKI secret 7 | secret = 0xdeadbeef 8 | 9 | p = int("501794446334189957604282155189438160845433783392772743395579628617109" 10 | "929160215221425142482928909270259580854362463493326988807453595748573" 11 | "76419559953437557") 12 | 13 | l = (p + 1) / 6 14 | 15 | F = ExtendedFiniteField(p, "x^2+x+1") 16 | E = EllipticCurve(F, 0, 1) 17 | 18 | P = E(3, int("1418077311270457886139292292020587683642898636677353664354101171" 19 | "7684401801069777797699258667061922178009879315047772033936311133" 20 | "535564812495329881887557081")) 21 | sP = E(int("129862491850266001914601437161941818413833907050695770313188660767" 22 | "152646233571458109764766382285470424230719843324368007925375351295" 23 | "39576510740045312772012"), 24 | int("452543250979361708074026409576755302296698208397782707067096515523" 25 | "033579018123253402743775747767548650767928190884624134827869137911" 26 | "24188897792458334596297")) 27 | 28 | 29 | def H(x): 30 | return x.x * x.field.p + x.y 31 | 32 | 33 | def get_user_public(E, P, id, l): 34 | v = int(hashlib.sha512(id).hexdigest().encode("hex"), 16) 35 | return P * v 36 | 37 | 38 | def get_user_secret(E, pubkey, l): 39 | global secret 40 | return pubkey * secret 41 | 42 | 43 | def encrypt(E, P, sP, pubkey, m, l): 44 | assert isinstance(m, (int, long)) 45 | # r = rand() 46 | r = random.randint(2**30, 2**31) 47 | # r*P, m xor e_l(secret * P, Q)^r = e_l(P, Q) ^ (secret * r) 48 | return (r * P, 49 | m ^ H(E.field(symmetric_tate_pairing(E, sP, pubkey, l) ** r))) 50 | 51 | 52 | def decrypt(E, K, c, l): 53 | # c1, c2 = r*P, m xor e_l(secret * P, Q) ^ r = e_l(P, Q) ^ (secret * r) 54 | # a = e_l(c1, K) = e_l(r*P, secret * Q) = e_l(P, Q) ^ (secret * r) 55 | return c[1] ^ H(E.field(symmetric_tate_pairing(E, c[0], K, l))) 56 | 57 | 58 | def main(): 59 | global P, sP, l 60 | print "Please tell me your ID :", 61 | ID = raw_input().strip() 62 | Q = get_user_public(E, P, ID, l) 63 | sQ = get_user_secret(E, Q, l) 64 | while True: 65 | print "What to do?" 66 | print "Encryption -> e, Decryption -> d, Quit -> q :", 67 | t = raw_input().strip().lower() 68 | if t == "e": 69 | print "[+] Message? :", 70 | m = int(raw_input().strip().encode("hex"), 16) 71 | C = encrypt(E, P, sP, Q, m, l) 72 | t = tuple(C[0]) 73 | c = cPickle.dumps((t[0], t[1], C[1])).encode("zlib").encode("base64") 74 | c = c.replace("\n", "") 75 | print "[+] Your Encrypted Message: %s" % c 76 | elif t == "d": 77 | print "Ciphertext? :", 78 | d = raw_input().strip().decode("base64").decode("zlib") 79 | x, y, c = cPickle.loads(d) 80 | C1 = E(x, y) 81 | C2 = c 82 | C = (C1, C2) 83 | m = decrypt(E, sQ, C, l) 84 | m = hex(m)[2:-1] 85 | if len(m) % 2 == 1: 86 | m = "0" + m 87 | m = m.decode("hex") 88 | print "[+] Your Message :", m 89 | elif t == "q": 90 | print "[+] Quit" 91 | break 92 | 93 | 94 | if __name__ == "__main__": 95 | main() 96 | -------------------------------------------------------------------------------- /note.md: -------------------------------------------------------------------------------- 1 | ecpy notes 2 | ======== 3 | 4 | hackmd: https://hackmd.io/JwZgJsAMDswGYFoCsBDAHAYwQFhfBARtpJAtAGxJwBMVY1AjJEkA# 5 | 6 | # C++クラス設計 7 | 8 | C++側で書くクラスの設計について 9 | 10 | ある対象を構造と値にそれぞれ分離して考える。有限体なら有限体の演算・素数を構造、実際の整数値は値として扱う。 11 | 12 | ## 構造クラス 13 | 14 | * FF 15 | * EF 16 | * EC 17 | 18 | → 値クラスに対する操作(演算)や共通保持すべきデータを保持するクラス。 19 | 20 | ## 値クラス 21 | 22 | * FF\_elem 23 | * EF\_elem 24 | * EC\_elem 25 | 26 | → 値の保持を主目的とするクラス。 27 | 28 | ## 構造・値クラスが共通に持つメンバ関数 29 | 30 | 構造/値クラス `T` が必ず持つべきメンバ関数を定義する。 31 | 32 | ```cpp 33 | struct T { 34 | T* clone(void) const; 35 | std::string to_string(void) const; 36 | }; 37 | ``` 38 | 39 | ## 構造クラスの持つメンバ関数 40 | 41 | 構造クラス `T` が必ず持つべきメンバ関数を定義する。 `E` は対応する値クラス。 42 | 43 | ```cpp 44 | template 45 | struct T { 46 | void add(E& ret, const E& a, const E& b) const; 47 | void sub(E& ret, const E& a, const E& b) const; 48 | void mul(E& ret, const E& a, const E& b) const; 49 | void div(E& ret, const E& a, const E& b) const; 50 | void pow(E& ret, const E& a, const mpz_class& b) const; 51 | bool equals(const E& a, const E& b) const; 52 | }; 53 | ``` 54 | 55 | ## 特殊メンバ関数について 56 | 57 | **これらの関数では例外は一切投げない**。 58 | 59 | ```cpp 60 | struct T { 61 | T(); 62 | ~T(); 63 | T(const T&); 64 | T(T&&); 65 | T& operator=(const T&); 66 | T& operator=(T&&); 67 | }; 68 | ``` 69 | 70 | # Pythonクラス設計 71 | 72 | Python側でのC++ラッパクラスの設計。 73 | 74 | 以下、基本的な事柄として `lib` はecpy\_nativeライブラリのctypes.CDLLインスタンスで、 `ctypes` は `from ctypes import *` でインポートされているとする。 75 | 76 | ## 構造クラスのラッパクラスの設計 77 | 78 | 基本となるクラスは以下のようにする。 構造クラスを `T` 、対応する値クラスを `E` とする。 79 | 80 | ```python 81 | class T(object): 82 | def __init__(s, params): # paramsは適宜パラメータを入れる。複数でも構わない。 83 | s.ptr = lib.T_create(params) 84 | 85 | def __to_string(s, bufsize): # to_stringのラッパ, バッファのサイズは可変 86 | b = create_string_buffer(bufsize) 87 | lib.T_to_string(s.ptr, b, bufsize) 88 | b = b.value 89 | if len(b) == 0: # not enough buffer size 90 | return s.__to_string(2*bufsize) 91 | return b 92 | 93 | def __str__(s): 94 | return s.__to_string(1024) 95 | 96 | def add(s, ret, a, b): 97 | assert isinstance(ret, E) and isinstance(a, E) and isinstance(b, E) 98 | lib.T_add(s.ptr, ret.ptr, a.ptr, b.ptr) 99 | 100 | def sub(s, ret, a, b): 101 | assert isinstance(ret, E) and isinstance(a, E) and isinstance(b, E) 102 | lib.T_sub(s.ptr, ret.ptr, a.ptr, b.ptr) 103 | 104 | def mul(s, ret, a, b): 105 | assert isinstance(ret, E) and isinstance(a, E) and isinstance(b, E) 106 | lib.T_mul(s.ptr, ret.ptr, a.ptr, b.ptr) 107 | 108 | def div(s, ret, a, b): 109 | assert isinstance(ret, E) and isinstance(a, E) and isinstance(b, E) 110 | lib.T_div(s.ptr, ret.ptr, a.ptr, b.ptr) 111 | 112 | def pow(s, ret, a, b): 113 | assert isinstance(ret, E) and isinstance(a, E) 114 | lib.T_pow(s.ptr, ret.ptr, a.ptr, str(b)) 115 | 116 | def equ(s, a, b): 117 | assert isinstance(a, E) and isinstance(b, E) 118 | return lib.T_equ(s.ptr, a.ptr, b.ptr) != 0 119 | 120 | def __del__(s): # GC deleter 121 | lib.T_delete(s.ptr) 122 | ``` 123 | 124 | ## 値クラスのラッパクラスの設計 125 | 126 | 構造クラスと大方同じだが、こちらは値の保持が目的なのでそちらを優先する。 127 | 128 | ```python 129 | class E(object): 130 | def __init__(s, params): # paramsは適宜パラメータを入れる。複数でも構わない。 131 | s.ptr = lib.E_create(params) 132 | 133 | def __to_string(s, bufsize): # to_stringのラッパ, バッファのサイズは可変 134 | b = create_string_buffer(bufsize) 135 | lib.E_to_string(s.ptr, b, bufsize) 136 | b = b.value 137 | if len(b) == 0: # not enough buffer size 138 | return s.__to_string(2*bufsize) 139 | return b 140 | 141 | def __str__(s): 142 | return s.__to_string(1024) 143 | 144 | def __del__(s): # GC deleter 145 | lib.E_delete(s.ptr) 146 | 147 | def to_python(s): 148 | # Pythonのオブジェクトに変換する。FFなら数値、EFならタプル等で、これは明確に規定する必要がある。 149 | ``` 150 | 151 | # Python<=>C++インターフェース 152 | 153 | 基本的には不透明ポインタをハンドルのように扱うことで実現する。 154 | 155 | ## 多倍長整数について 156 | 157 | Python側での多倍長整数(C APIでのPyLong型)をC\+\+へ渡す際は文字列として渡した後C\+\+側でmpz\_classへ変換する。 158 | 159 | Python\: 160 | ```python 161 | # lib.cpp_func(1<<256) # <= long型なので直接渡せない 162 | lib.cpp_func(str(1<<256)) # <= OK 163 | ``` 164 | 165 | C++\: 166 | ```cpp 167 | // __EXPORT__ void cpp_func(const mpz_class& x); <= 直接の変換は不可能 168 | __EXPORT__ void cpp_func(const char *x); // <= OK, 内部でmpz_classへ変換される 169 | ``` 170 | 171 | ## 文字列を戻り値とする関数について 172 | 173 | 文字列を戻り値に持つ関数(現在の設計では`to_string`)についてはPython ctypes APIの`ctypes.create_string_buffer`を用いて文字列バッファを用意、そこにコピーするようにする 174 | 175 | C++側では次の関数 (`ecpy_native.h` に用意されている)を用いてバッファに文字列をコピーする。 176 | 177 | ```cpp 178 | template 179 | void write_to_python_string(const T *x, char *ptr, int len) { 180 | std::stringstream ss; 181 | ss << x->to_string(); 182 | std::string r = ss.str(); 183 | if (r.size() < len) { 184 | strcpy(ptr, r.c_str()); 185 | } 186 | } 187 | ``` 188 | 189 | Python側は上のクラス設計の際のものと同じ。 190 | 191 | ```python 192 | def __to_string(s, bufsize): # to_stringのラッパ, バッファのサイズは可変 193 | b = create_string_buffer(bufsize) 194 | lib.E_to_string(s.ptr, b, bufsize) 195 | b = b.value 196 | if len(b) == 0: # not enough buffer size 197 | return s.__to_string(2*bufsize) 198 | return b 199 | 200 | def __str__(s): 201 | return s.__to_string(1024) 202 | ``` 203 | 204 | ## 構造クラスのインターフェース関数 205 | 206 | 構造クラスを `T` とし、値クラスを `E` とする 207 | 208 | ```cpp 209 | __EXPORT__ { 210 | // create T instance 211 | T *T_create(〜); 212 | // delete T instance 213 | void T_delete(const T*); 214 | // ret = a + b 215 | void T_add(const T *obj, E *ret, const E *a, const E *b); 216 | // ret = a - b 217 | void T_sub(const T *obj, E *ret, const E *a, const E *b); 218 | // ret = a * b 219 | void T_mul(const T *obj, E *ret, const E *a, const E *b); 220 | // ret = a / b 221 | void T_div(const T *obj, E *ret, const E *a, const E *b); 222 | // ret = a ^ b 223 | void T_pow(const T *obj, E *ret, const E *a, const char *b); 224 | // a == b 225 | int T_equ(const T *obj, const E *a, const E *b); 226 | // to python __str__ function 227 | void T_to_string(const T *obj, char *ptr, int len); 228 | }; 229 | ``` 230 | 231 | ## 値クラスのインターフェース関数 232 | 233 | 構造クラスを `T` とし、値クラスを `E` とする 234 | 235 | ```cpp 236 | __EXPORT__ { 237 | // create E instance 238 | E *E_create(〜); 239 | // delete E instance 240 | void E_delete(const E*); 241 | // to python __str__ function 242 | void E_to_string(const E *obj, char *ptr, int len); 243 | }; 244 | ``` 245 | 246 | 247 | # FF/FF\_elem 248 | ## FF 249 | 250 | ```cpp 251 | struct FF { 252 | mpz_class p; 253 | 254 | FF() = default; 255 | ~FF() = default; 256 | FF(const mpz_class& p) : p(p) {} 257 | FF(const FF& t) : p(t.p) {} 258 | FF(FF&& t) : p(std::move(t.p)) {}; 259 | 260 | FF& operator=(const FF&); 261 | FF& operator=(FF&&); 262 | 263 | // common functions 264 | FF* clone(void) const; 265 | std::string to_string(void) const; 266 | 267 | // structure class member functions 268 | void add(FF_elem& ret, const FF_elem& a, const FF_elem& b) const; 269 | void sub(FF_elem& ret, const FF_elem& a, const FF_elem& b) const; 270 | void mul(FF_elem& ret, const FF_elem& a, const FF_elem& b) const; 271 | void div(FF_elem& ret, const FF_elem& a, const FF_elem& b) const; 272 | void pow(FF_elem& ret, const FF_elem& a, const mpz_class& b) const; 273 | bool equ(const FF_elem& a, const FF_elem& b) const; 274 | }; 275 | ``` 276 | 277 | ## FF\_elem 278 | 279 | ```cpp 280 | struct FF_elem { 281 | mpz_class v; 282 | 283 | FF_elem(const mpz_class& v) : v(v) {}; 284 | 285 | FF_elem() = default; 286 | ~FF_elem() = default; 287 | FF_elem(const FF_elem& t) : v(t.v) {}; 288 | FF_elem(FF_elem&& t) : v(std::move(t.v)) {}; 289 | 290 | FF_elem& operator=(const FF_elem&); 291 | FF_elem& operator=(FF_elem&&); 292 | 293 | // common functions 294 | FF_elem* clone(void) const; 295 | std::string to_string(void) const; 296 | }; 297 | ``` 298 | 299 | ## FF/FF\_elem のPythonインターフェース 300 | 301 | ```cpp 302 | struct FF; 303 | struct FF_elem; 304 | // FF 305 | __EXPORT__ { 306 | // create FF instance 307 | FF *FF_create(const char *p); 308 | // delete FF instance 309 | void FF_delete(const FF*); 310 | // ret = a + b 311 | void FF_add(const FF *obj, FF_elem *ret, const FF_elem *a, const FF_elem *b); 312 | // ret = a - b 313 | void FF_sub(const FF *obj, FF_elem *ret, const FF_elem *a, const FF_elem *b); 314 | // ret = a * b 315 | void FF_mul(const FF *obj, FF_elem *ret, const FF_elem *a, const FF_elem *b); 316 | // ret = a / b 317 | void FF_div(const FF *obj, FF_elem *ret, const FF_elem *a, const FF_elem *b); 318 | // ret = a ^ b 319 | void FF_pow(const FF *obj, FF_elem *ret, const FF_elem *a, const char *b); 320 | // a == b 321 | int FF_equ(const FF *obj, const FF_elem *a, const FF_elem *b); 322 | // to python __str__ function 323 | void FF_to_string(const FF *obj, char *ptr, int len); 324 | }; 325 | 326 | // FF_elem 327 | __EXPORT__ { 328 | // create FF_elem instance 329 | FF_elem *FF_elem_create(const char *v); 330 | // delete FF_elem instance 331 | void FF_elem_delete(const FF_elem*); 332 | // to python __str__ function 333 | void FF_elem_to_string(const FF_elem *obj, char *ptr, int len); 334 | }; 335 | 336 | ``` 337 | 338 | ## to\_pythonの返り値: `FF_elem` 339 | 340 | `int(str(s))` 341 | 342 | つまり保持している数値をそのまま返す。 343 | 344 | # EF/EF\_elem 345 | 346 | 既約多項式が2種類($x^2+1$, $x^2+x+1$)あるので、これはenumにしておく 347 | 348 | [enumeration declaration - cppreference.com](http://en.cppreference.com/w/cpp/language/enum) 349 | > the keywords `class` and `struct` are exactly equivalent 350 | 351 | ```cpp 352 | enum class IrreduciblePolynomialType : int { 353 | X2_1, // x^2+1 354 | X2_X_1, // x^2+x+1 355 | }; 356 | ``` 357 | ## EF 358 | 359 | ```cpp 360 | struct EF { 361 | const FF& base; 362 | IrreduciblePolynomialType poly; 363 | 364 | EF(const FF& ff, IrreduciblePolynomialType pol) : base(ff), poly(pol) {} 365 | 366 | EF(const mpz_class& p, IrreduciblePolynomialType pol) : base(p), poly(pol) {} 367 | 368 | 369 | EF() = default; 370 | ~EF() = default; 371 | EF(const EF& ef) : base(ef.base), poly(ef.poly) {} 372 | EF(EF&& ef) : base(std::move(ef.base)), poly(ef.poly) {} 373 | 374 | EF& operator=(const EF& ef); 375 | EF& operator=(EF&& ef); 376 | 377 | // structure class member functions 378 | void add(EF_elem& ret, const EF_elem& a, const EF_elem& b) const; 379 | void sub(EF_elem& ret, const EF_elem& a, const EF_elem& b) const; 380 | void mul(EF_elem& ret, const EF_elem& a, const EF_elem& b) const; 381 | void div(EF_elem& ret, const EF_elem& a, const EF_elem& b) const; 382 | void pow(EF_elem& ret, const EF_elem& a, const mpz_class& b) const; 383 | bool equ(const EF_elem& a, const EF_elem& b) const; 384 | 385 | // common functions 386 | EF* clone(void) const; 387 | std::string to_string(void) const; 388 | }; 389 | ``` 390 | 391 | ## EF\_elem 392 | 393 | ```cpp 394 | struct EF_elem { 395 | FF_elem u, v; 396 | 397 | EF_elem(const FF_elem& u, const FF_elem& v = 0) : u(u), v(v) {} 398 | 399 | EF_elem(const mpz_class& u, const mpz_class& v = 0) : u(u), v(v) {} 400 | 401 | 402 | EF_elem() = default; 403 | ~EF_elem() = default; 404 | EF_elem(const EF_elem& ee) : u(ee.u), v(ee.v) {}; 405 | EF_elem(EF_elem&& ee) : u(std::move(ee.u)), v(std::move(ee.v)) {}; 406 | 407 | EF_elem& operator=(const EF_elem& ee); 408 | EF_elem& operator=(EF_elem&& ee); 409 | 410 | // common functions 411 | EF_elem* clone(void) const; 412 | std::string to_string(void) const; 413 | }; 414 | ``` 415 | 416 | ## EF/EF\_elemのPythonインターフェース 417 | 418 | ```cpp 419 | struct EF; 420 | struct EF_elem; 421 | 422 | // EF 423 | __EXPORT__ { 424 | // create EF instance 425 | // polynomial is string of irreducible polynomial. 426 | // e.g. x^2+x+1, x^2+1, X^2+1, x^2+ x +1 (ignore spaces and case insensitive) 427 | EF *EF_create(const char *p, const char *polynomial); 428 | // delete EF instance 429 | void EF_delete(const EF *ef); 430 | 431 | // r = a + b 432 | void EF_add(const EF *obj, EF_elem *ret, const EF_elem *a, const EF_elem *b); 433 | // r = a - b 434 | void EF_sub(const EF *obj, EF_elem *ret, const EF_elem *a, const EF_elem *b); 435 | // r = a * b 436 | void EF_mul(const EF *obj, EF_elem *ret, const EF_elem *a, const EF_elem *b); 437 | // r = a / b 438 | void EF_div(const EF *obj, EF_elem *ret, const EF_elem *a, const EF_elem *b); 439 | // r = a ^ b 440 | void EF_pow(const EF *obj, EF_elem *ret, const EF_elem *a, const char *b); 441 | // a == b 442 | int EF_equ(const EF *obj, const EF_elem *a, const EF_elem *b); 443 | void EF_to_string(const EF *obj, char *ptr, int len); 444 | }; 445 | 446 | // EF_elem 447 | __EXPORT__ { 448 | EF_elem *EF_elem_create(const char *u, const char *v); 449 | void EF_elem_delete(const EF_elem *obj); 450 | void EF_elem_to_string(const EF_elem *obj, char *ptr, int len); 451 | }; 452 | ``` 453 | 454 | ## to\_pythonの返り値: `EF_elem` 455 | 456 | `ast.literal_eval(str(s).lstrip("EF_elem")))` 457 | 458 | 二次拡大体なので2つの要素が返らなければならない。そのため返り値はタプルで内容は要素を `a+b*v` (vは基底) とした時 `(a, b)`。 459 | 460 | # EC/EC\_elem 461 | 462 | 楕円曲線クラス 463 | 464 | べき乗・除算は数式上ありえないので除外する。除外するにはdelete代入を利用する。 465 | 466 | テンプレート型引数の `T` は `FF/EF` 等構造クラスを表し、 `E` は対応する値クラスを表す。 467 | 468 | ## EC 469 | 470 | ```cpp 471 | template 472 | struct EC { 473 | const T& base; 474 | mpz_class a, b; 475 | 476 | EC(const T& base, const mpz_class& a, const mpz_class& b) : base(base), a(a), b(b) {} 477 | 478 | EC() = default; 479 | ~EC() = default; 480 | EC(const EC& ec) : base(ec.base), a(ec.a), b(ec.b) {}; 481 | EC(EC&& ec) : base(std::move(ec.base)), a(std::move(ec.a)), b(std::move(ec.b)) {}; 482 | EC& operator=(const EC& ec); 483 | EC& operator=(EC&& ec); 484 | 485 | template 486 | void add(EC_elem& ret, const EC_elem& a, const EC_elem& b) const; 487 | template 488 | void sub(EC_elem& ret, const EC_elem& a, const EC_elem& b) const; 489 | template 490 | void mul(EC_elem& ret, const EC_elem& a, const mpz_class& b) const; 491 | template 492 | bool equ(const EC_elem & a, const EC_elem& b) const; 493 | 494 | // ----------------- UNDEFINED(DELETED) ----------------- 495 | template 496 | void mul(EC_elem& ret, const EC_elem& a, const EC_elem& b) const = delete; 497 | template 498 | void div(EC_elem& ret, const EC_elem& a, const EC_elem& b) const = delete; 499 | template 500 | void pow(EC_elem& ret, const EC_elem& a, const mpz_class& b) const = delete; 501 | // ------------------------------------------------------ 502 | 503 | template 504 | EC_elem to_affine(const EC_elem& elem) const; 505 | template 506 | E line_coeff(const EC_elem& P, const EC_elem& Q) const; 507 | template 508 | bool is_on_curve(const EC_elem& elem) const; 509 | template 510 | bool is_infinity(const EC_elem& P) const; 511 | EC* clone(void) const; 512 | std::string to_string(void) const; 513 | }; 514 | ``` 515 | 516 | 追加した関数については以下の通り: 517 | 518 | ### to\_affine 519 | あるEC\_elemについて通常の射影座標からアフィン座標(xy座標)に変換して返す(z座標を1にして実質アフィン座標になるようにする) 520 | 521 | ### line\_coeff 522 | 楕円曲線の点P、点Qを通る直線 $ax + b$ の係数 $a$ を求める。もし $P=Q$ だったならば接線の係数を返す。 523 | 524 | ### is\_on\_curve 525 | ある点Pが楕円曲線上の点かどうかを判定する。 526 | 527 | ### is\_infinity 528 | ある点Pが無限遠点かどうかを判定する。 529 | 530 | ## EC\_elem 531 | 532 | ```cpp 533 | template 534 | struct EC_elem { 535 | T x, y, z; 536 | 537 | EC_elem(const mpz_class& x, const mpz_class& y, const mpz_class& z) : x(x), y(y), z(z) {} 538 | 539 | EC_elem() = default; 540 | ~EC_elem() = default; 541 | EC_elem(const EC_elem& ee) : x(ee.x), y(ee.y), z(ee.z) {}; 542 | EC_elem(EC_elem&& ee) : x(std::move(ee.x)), y(std::move(ee.y)), z(std::move(ee.z)) {}; 543 | EC_elem& operator=(const EC_elem&); 544 | EC_elem& operator=(EC_elem&&); 545 | 546 | EC_elem* clone(void) const; 547 | std::string to_string(void) const; 548 | }; 549 | ``` 550 | 551 | ## ECのPythonインターフェース 552 | ```cpp 553 | template 554 | struct EC; 555 | template 556 | struct EC_elem; 557 | 558 | __EXPORT__ { 559 | // create EC instance 560 | EC *EC_FF_create(const char *a, const char *b, const FF *base); 561 | // delete EC instance 562 | void EC_FF_delete(const EC* obj); 563 | // ret = a + b 564 | void EC_FF_add(const EC *obj, EC_elem *ret, const EC_elem *a, const EC_elem *b); 565 | // ret = a - b 566 | void EC_FF_sub(const EC *obj, EC_elem *ret, const EC_elem *a, const EC_elem *b); 567 | // ret = a * b 568 | void EC_FF_mul(const EC *obj, EC_elem *ret, const EC_elem *a, const char *b); 569 | // a == b 570 | int EC_FF_equ(const EC *obj, const EC_elem *a, const EC_elem *b); 571 | // to python __str__ function 572 | void EC_FF_to_string(const EC *obj, char *ptr, int len); 573 | }; 574 | 575 | __EXPORT__ { 576 | // create EC instance 577 | EC *EC_EF_create(const char *a, const char *b, const EF *base); 578 | // delete EC instance 579 | void EC_EF_delete(const EC* obj); 580 | // ret = a + b 581 | void EC_EF_add(const EC *obj, EC_elem *ret, const EC_elem *a, const EC_elem *b); 582 | // ret = a - b 583 | void EC_EF_sub(const EC *obj, EC_elem *ret, const EC_elem *a, const EC_elem *b); 584 | // ret = a * b 585 | void EC_EF_mul(const EC *obj, EC_elem *ret, const EC_elem *a, const char *b); 586 | // a == b 587 | int EC_EF_equ(const EC *obj, const EC_elem *a, const EC_elem *b); 588 | // to python __str__ function 589 | void EC_EF_to_string(const EC *obj, char *ptr, int len); 590 | }; 591 | ``` 592 | 593 | ## EC\_elemのPythonインターフェース 594 | 595 | ``` 596 | template 597 | struct EC; 598 | template 599 | struct EC_elem; 600 | 601 | __EXPORT__ { 602 | // create EC_elem instance 603 | EC_elem *EC_elem_FF_create(const FF_elem *x, const FF_elem *y, const FF_elem *z); 604 | // delete E instance 605 | void EC_elem_FF_delete(const EC_elem* obj); 606 | // to python __str__ function 607 | void EC_elem_FF_to_string(const EC_elem *obj, char *ptr, int len); 608 | }; 609 | 610 | __EXPORT__ { 611 | // create EC_elem instance 612 | EC_elem *EC_elem_EF_create(const EF_elem *x, const EF_elem *y, const EF_elem *z); 613 | // delete E instance 614 | void EC_elem_EF_delete(const EC_elem* obj); 615 | // to python __str__ function 616 | void EC_elem_EF_to_string(const EC_elem *obj, char *ptr, int len); 617 | }; 618 | 619 | ``` 620 | 621 | # ペアリング関数群 622 | ペアリングのために必要な関数の設計 623 | 624 | * miller 625 | * weil\_pairing 626 | * tate\_pairing 627 | 628 | ## miller関数 629 | Miller algorithmの実装, 中にラムダ式でh関数を持つ 630 | 返り値は第一引数`const E& ret`に返り、その値は因子$m(P) - m(O)$を持つ関数$f_P$に$Q$を適用した$f_P(Q)$の値。 631 | 632 | ```cpp 633 | template 634 | template 635 | void miller(const E& ret, const EC curve const EC_elem P, const EC_elem Q, const int& m); 636 | ``` 637 | 638 | ## weil\_pairing関数 639 | Weil Pairingの計算をする関数。 640 | 641 | ```cpp 642 | template 643 | template 644 | void weil_pairing(const E& ret, const EC curve const EC_elem P, const EC_elem Q, const int& m); 645 | ``` 646 | 647 | ## weil\_pairing関数 648 | Tate-Lichtenbaum Pairingの計算をする関数。 649 | 650 | ```cpp 651 | template 652 | template 653 | void tate_pairing(const E& ret, const EC curve const EC_elem P, const EC_elem Q, const int& m, const int& embedding_degree); 654 | ``` 655 | 656 | # References 657 | * [C\+\+11 時代のクラス設計に関する提案 - 野良C\+\+erの雑記帳](http://d.hatena.ne.jp/gintenlabo/20130604/1370362451) 658 | * [本の虫: C\+\+03とC\+\+11の違い: 特別なメンバー関数編](https://cpplover.blogspot.jp/2013/12/c03c11_13.html) 659 | * [Rule of Three (C++ programming)#Rule of Five](https://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29#Rule_of_Five) 660 | * Modern Effective C++ 661 | * 項目11 privateな未定義関数よりもdeleteを優先する 662 | * 項目14 例外を発生させない関数はnoexceptと宣言する 663 | * 項目17 自動的に生成される特殊メンバ関数を理解する 664 | * 項目25 右辺値参照にはstd::moveを、ユニヴァーサル参照にはstd::forwardを用いる 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | -------------------------------------------------------------------------------- /scripts/bench_pairing.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from six.moves import xrange 3 | from ecpy import * 4 | from timeit import timeit 5 | from random import randint 6 | 7 | test_param = [] 8 | 9 | 10 | def init_test(t, *args): 11 | global test_param 12 | cond = {"weil": weil_pairing, "tate": tate_pairing} 13 | test_param = [cond[t], args[0]] 14 | 15 | 16 | def do_test(): 17 | global test_param 18 | test_param[0](*test_param[1]) 19 | 20 | 21 | def show_results(name, result, count): 22 | per_pass = 1000000 * (result / count) 23 | print("%s: %.2f usec/pass" % (name, per_pass)) 24 | 25 | 26 | def main(): 27 | l = 2201426263 28 | p = 6 * l - 1 29 | F = ExtendedFiniteField(p, "x^2+x+1") 30 | E = EllipticCurve(F, 0, 1) 31 | i = 3 32 | while True: 33 | y = E.get_corresponding_y(i) 34 | if y != None: 35 | P = E(i, y) 36 | if (l * P).is_infinity(): 37 | break 38 | i += 1 39 | print(P) 40 | 41 | rand = [randint(2**31, 2**32) for _ in xrange(10)] 42 | count = 20 43 | 44 | weil_time = [] 45 | print("[+] Weil Pairing: ") 46 | for x in rand: 47 | r = timeit( 48 | "bench_pairing.do_test()", 49 | setup="import bench_pairing; from ecpy import EllipticCurve, ExtendedFiniteField; bench_pairing.init_test('weil', [%r, %r, %r.distortion_map(), %r])" 50 | % (E, P, x * P, l), 51 | number=count, 52 | ) 53 | weil_time += [r] 54 | show_results("weil", r, count) 55 | 56 | print("[+] Tate Pairing: ") 57 | tate_time = [] 58 | for x in rand: 59 | r = timeit( 60 | "bench_pairing.do_test()", 61 | setup="import bench_pairing; from ecpy import EllipticCurve, ExtendedFiniteField; bench_pairing.init_test('tate', [%r, %r, %r.distortion_map(), %r, 2])" 62 | % (E, P, x * P, l), 63 | number=count, 64 | ) 65 | tate_time += [r] 66 | show_results("tate", r, count) 67 | 68 | print("=" * 64) 69 | show_results("weil", sum(weil_time), count * 10) 70 | show_results("tate", sum(tate_time), count * 10) 71 | 72 | 73 | if __name__ == "__main__": 74 | main() 75 | -------------------------------------------------------------------------------- /scripts/graph_test.py: -------------------------------------------------------------------------------- 1 | from ecpy import ExtendedFiniteField, EllipticCurve, weil_pairing 2 | from random import randint 3 | 4 | 5 | def main(): 6 | l = 2201426263 7 | p = 6 * l - 1 8 | F = ExtendedFiniteField(p, "x^2+x+1") 9 | E = EllipticCurve(F, 0, 1) 10 | i = 3 11 | while True: 12 | y = E.get_corresponding_y(i) 13 | if y != None: 14 | P = E(i, y) 15 | if (l * P).is_infinity(): 16 | break 17 | i += 1 18 | print(P) 19 | 20 | rand = [randint(2**31, 2**32) for _ in range(10)] 21 | 22 | print("[+] Weil Pairing: ") 23 | for x in rand: 24 | print(weil_pairing(E, P, (x * P).distortion_map(), l)) 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /scripts/schoof.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division 2 | from ecpy import * 3 | from ecpy.rings.polynomial_multi import BivariatePolynomialElement 4 | from ecpy.rings.CommutativeRing import CommutativeRing 5 | import math 6 | import gmpy 7 | 8 | 9 | def y_div(pol, div): 10 | """ 11 | Calculate pol / div 12 | 13 | Args: 14 | pol : Polynomial for x, y 15 | div = Polynomial for y 16 | """ 17 | assert all([len(t) == 1 for t in div]) 18 | res = list(pol.coeffs) 19 | if len(div) == 1 and len(div[0]) == 1: 20 | return pol.ring.element_class( 21 | pol.ring, map(lambda y: map(lambda x: x / div[0][0], y), res) 22 | ) 23 | for i, t in enumerate(div): 24 | assert len(pol[0]) == 1 and pol[0][0] == 0 25 | t = t[0] 26 | if t == 0: 27 | continue 28 | res = res[i:] 29 | res = map(lambda y: list(map(lambda x: x / t, y)), res) 30 | return pol.ring.element_class(pol.ring, res) 31 | 32 | 33 | @memoize 34 | def torsion_polynomial(n, E, x, y): 35 | if n > 4: 36 | if n % 2 == 0: 37 | n = n // 2 38 | psi = torsion_polynomial 39 | pp2 = psi(n + 2, E, x, y) 40 | pp1 = psi(n + 1, E, x, y) 41 | pp0 = psi(n, E, x, y) 42 | pm1 = psi(n - 1, E, x, y) 43 | pm2 = psi(n - 2, E, x, y) 44 | R, S = pp0, 2 * y 45 | X, Y = (pp2 * pm1**2, pm2 * pp1**2) 46 | return y_div(R * (X - Y), S) 47 | else: 48 | n = (n - 1) // 2 49 | psi = torsion_polynomial 50 | pp2 = psi(n + 2, E, x, y) 51 | pp1 = psi(n + 1, E, x, y) 52 | pp0 = psi(n, E, x, y) 53 | pm1 = psi(n - 1, E, x, y) 54 | X, Y = pp2 * pp0**3, pp1**3 * pm1 55 | return X - Y 56 | if n == -1: 57 | return x - 1 - x 58 | elif n == 0: 59 | return x - x 60 | elif n == 1: 61 | return x + 1 - x 62 | elif n == 2: 63 | return 2 * y 64 | elif n == 3: 65 | return 3 * x**4 + 6 * E.a * x**2 + 12 * E.b * x - E.a**2 66 | elif n == 4: 67 | return ( 68 | 4 69 | * y 70 | * ( 71 | x**6 72 | + 5 * E.a * x**4 73 | + 20 * E.b * x**3 74 | - 5 * E.a**2 * x**2 75 | - 4 * E.a * E.b * x 76 | - 8 * E.b**2 77 | - E.a**3 78 | ) 79 | ) 80 | 81 | 82 | def schoof(F, E): 83 | def y2_reduce(pol, x, y, Fx): 84 | """ 85 | Reduce `pol` modulo (y^2 - Fx) 86 | <=> pol over F_q[x, y] / (y^2 - Fx) 87 | """ 88 | if pol.degree() < 2: 89 | return pol 90 | assert all([len(t) == 1 and t[0] == 0 for t in pol[1::2]]) 91 | for i in xrange(1, (len(pol) - 1) // 2 + 1): 92 | y2 = sum(map(lambda t: x ** t[0] * t[1], enumerate(pol[2 * i]))) 93 | pol = pol - (y ** (2 * i) * y2) + (y2 * Fx**i) 94 | return pol 95 | 96 | @memoize 97 | def division_polynomial(ell, x, y): 98 | pol = torsion_polynomial(ell, E, x, y) 99 | pol.trim() 100 | return pol 101 | 102 | def get_polynomial(ell, x0, y0): 103 | if ell == 0: 104 | return PU.element_class(PU, [0]) 105 | pp0 = division_polynomial(ell, x0, y0) 106 | pm1 = division_polynomial(ell - 1, x0, y0) 107 | pp1 = division_polynomial(ell + 1, x0, y0) 108 | pol_p = x - (pm1 * pp1) 109 | pol_q = pp0**2 110 | pol_p = y2_reduce(pol_p, x, y, Fx) 111 | pol_q = y2_reduce(pol_q, x, y, Fx) 112 | pol_p = pol_p.apply(xs, 0) 113 | pol_q = pol_q.apply(xs, 0) 114 | pol = pol_p / pol_q 115 | if not isinstance(pol, UnivariatePolynomialRing): 116 | return PU.element_class(PU, [pol]) 117 | return pol 118 | 119 | L = 2 120 | N = 1 121 | t = {} 122 | factors = {} 123 | q = F.p ** F.degree() 124 | PR = BivariatePolynomialRing(F, ["x", "y"]) 125 | PU = UnivariatePolynomialRing(F, "xs") 126 | x, y = PR.gens() 127 | Fx = x**3 + E.a * x + E.b 128 | xs = PU.gen() 129 | 130 | while N < math.sqrt(F.n) * 4: 131 | L = int(gmpy.next_prime(L)) 132 | qbar = q % L 133 | mod_poly = division_polynomial(L, x, y).apply(xs, 0) 134 | poly1 = get_polynomial(qbar + 1, x, y) % mod_poly 135 | for tbar in xrange(0, L): 136 | poly2 = get_polynomial(tbar, x, y) % mod_poly 137 | if poly1 == poly2: 138 | factors[L] = tbar 139 | N *= L 140 | break 141 | print(factors) 142 | 143 | t = crt(map(lambda x: factors[x], factors.keys()), factors.keys()) 144 | if t > N // 2: 145 | t = -(N - t) 146 | return q + 1 - t 147 | 148 | 149 | class ECPoly(BivariatePolynomialRing, CommutativeRing): 150 | def __init__(s, E): 151 | from ecpy.elliptic_curve.EllipticCurve import FiniteFieldEllipticCurve 152 | from ecpy.rings.polynomial_multi import BivariatePolynomialElement 153 | 154 | assert isinstance(E, FiniteFieldEllipticCurve) 155 | s.field = E.field 156 | BivariatePolynomialRing.__init__(s, s.field, ["x", "y"]) 157 | s.element_class = ECPolyElement 158 | s.PR = BivariatePolynomialRing(s.field, ["xs", "ys"]) 159 | xs, ys = s.PR.gens() 160 | s.curve_poly = xs**3 + E.a * xs + E.b 161 | 162 | def y2_reduce(s, pol): 163 | """ 164 | Reduce `pol` modulo (y^2 - Fx) 165 | <=> pol over F_q[x, y] / (y^2 - Fx) 166 | """ 167 | x, y = s.gens() 168 | xs, ys = s.PR.gens() 169 | pol = s.PR(tuple(pol)) 170 | if pol.degree() < 2: 171 | return pol 172 | # assert all([len(t) == 1 and t[0] == 0 for t in pol[1::2]]) 173 | for i in xrange(1, (len(pol) - 1) // 2 + 1): 174 | y2 = sum(map(lambda t: xs ** t[0] * t[1], enumerate(pol[2 * i]))) 175 | pol = pol - (ys ** (2 * i) * y2) + (y2 * s.curve_poly**i) 176 | return pol 177 | 178 | def _add(s, A, B): 179 | res = BivariatePolynomialRing._add(s, A, B) 180 | return s.element_class(s, s.y2_reduce(res)) 181 | 182 | def _mul(s, A, B): 183 | res = BivariatePolynomialRing._mul(s, A, B) 184 | return s.element_class(s, s.y2_reduce(res)) 185 | 186 | def _equ(s, A, B): 187 | a_is_none = len(A) == 1 and len(A[0]) == 1 and A[0][0] is None 188 | b_is_none = len(B) == 1 and len(B[0]) == 1 and B[0][0] is None 189 | if a_is_none and B[0][0] is not None: 190 | return False 191 | if b_is_none and A[0][0] is not None: 192 | return False 193 | A = tuple(s.y2_reduce(s.element_class(s, A))) 194 | B = tuple(s.y2_reduce(s.element_class(s, B))) 195 | return BivariatePolynomialRing._equ(s, A, B) 196 | 197 | 198 | class ECPolyElement(BivariatePolynomialElement): 199 | def __divmod__(s, rhs): 200 | pol = s 201 | div = rhs 202 | if s == rhs: 203 | return s.__class__(s.ring, [[1]]) 204 | if all([len(t) == 1 for t in div]): 205 | res = list(pol.coeffs) 206 | rem = [] 207 | if len(div) == 1: 208 | if len(div[0]) == 1: 209 | return ( 210 | pol.ring.element_class( 211 | pol.ring, 212 | map(lambda y: map(lambda x: x / div[0][0], y), res), 213 | ), 214 | 0, 215 | ) 216 | for i, t in enumerate(div): 217 | # assert len(pol[0]) == 1 and pol[0][0] == 0 218 | t = t[0] 219 | if t == 0: 220 | continue 221 | rem += res[:i] 222 | res = res[i:] 223 | res = map(lambda y: list(map(lambda x: x / t, y)), res) 224 | return ( 225 | s.ring.element_class(pol.ring, res), 226 | s.ring.element_class(s.ring, rem), 227 | ) 228 | elif len(div) == len(pol) and len(pol) == 1: 229 | PR = UnivariatePolynomialRing(s.ring.field, "xs") 230 | pol = PR(pol[0]) 231 | div = PR(div[0]) 232 | p, q = divmod(pol, div) 233 | if not hasattr(p, "__iter__"): 234 | p = [p] 235 | if not hasattr(q, "__iter__"): 236 | q = [q] 237 | return s.ring.element_class(s.ring, [list(p)]), s.ring.element_class( 238 | s.ring, [list(q)] 239 | ) 240 | elif len(div) == 1: 241 | PR = UnivariatePolynomialRing(s.ring.field, "xs") 242 | res_p = [] 243 | res_q = [] 244 | v = PR(div[0]) 245 | for pol_y in pol: 246 | u = PR(pol_y) 247 | p, q = divmod(u, v) 248 | if not hasattr(p, "__iter__"): 249 | p = [p] 250 | if not hasattr(q, "__iter__"): 251 | q = [q] 252 | res_p += [list(p)] 253 | res_q += [list(q)] 254 | return s.ring.element_class(s.ring, res_p), s.ring.element_class( 255 | s.ring, res_q 256 | ) 257 | 258 | def __rtruediv__(s, lhs): 259 | return s.__rdiv__(lhs) 260 | 261 | def __rfloordiv__(s, lhs): 262 | return s.__rdiv__(lhs) 263 | 264 | def __rdiv__(s, lhs): 265 | from ecpy.rings.QuotientRing import QuotientRingElement 266 | 267 | if isinstance(lhs, QuotientRingElement) and isinstance( 268 | lhs.ring.base_ring, ECPolyElement 269 | ): 270 | return lhs.ring(lhs.lift() / s) 271 | return ECPolyElement(s.ring, lhs) / s 272 | 273 | def __rmod__(s, lhs): 274 | from ecpy.rings.QuotientRing import QuotientRingElement 275 | 276 | if isinstance(lhs, QuotientRingElement) and isinstance( 277 | lhs.ring.base_ring, ECPolyElement 278 | ): 279 | return lhs.ring(lhs.lift() % s) 280 | return ECPolyElement(s.ring, lhs) % s 281 | 282 | def __truediv__(s, rhs): 283 | return s.__div__(rhs) 284 | 285 | def __floordiv__(s, rhs): 286 | return s.__div__(rhs) 287 | 288 | def __div__(s, rhs): 289 | if not isinstance(rhs, ECPolyElement): 290 | rhs = s._to_tuple(rhs) 291 | return divmod(s, rhs)[0] 292 | 293 | def __mod__(s, rhs): 294 | if not isinstance(rhs, ECPolyElement): 295 | rhs = s._to_tuple(rhs) 296 | return divmod(s, rhs)[1] 297 | 298 | 299 | if __name__ == "__main__": 300 | p = 137 301 | F = FiniteField(p) 302 | E = EllipticCurve(F, 2, 17) 303 | """ 304 | print(schoof(F, E)) 305 | """ 306 | EP_poly = ECPoly(E) 307 | x, y = EP_poly.gens() 308 | print(x + y) 309 | print(y**2 * (x**3 + 1) + y * (x**2 - 1) + 3) 310 | print((y**2 * (x**3 + 1) + y * (x**2 - 1) + 3) % y) 311 | print(x + y) 312 | EP = FractionField(QuotientRing(EP_poly, torsion_polynomial(3, E, x, y))) 313 | print(EP) 314 | EK = EllipticCurve(EP, 2, 17) 315 | xs = EP(x) 316 | ys = EP(y) 317 | P = EK(xs, ys) 318 | print(xs) 319 | print(P) 320 | print(2 * P) 321 | print(3 * P) 322 | print(4 * P) 323 | -------------------------------------------------------------------------------- /scripts/test.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from ecpy import * 3 | from random import randint 4 | from six.moves import xrange 5 | import sys 6 | 7 | ac_count = 0 8 | wa_count = 0 9 | 10 | 11 | def _assert(a, b, msg, cond): 12 | global ac_count, wa_count 13 | msg = msg.ljust(16) 14 | print(("[+] %s..." % (msg)).ljust(30), end=" ") 15 | var = {"a": a, "b": b} 16 | if eval("a %s b" % cond, var): 17 | print("\x1b[33m[ OK ]\x1b[0m %r" % (b,)) 18 | ac_count += 1 19 | else: 20 | print("\x1b[31m[ Fail ]\x1b[0m Expected: %r, Result: %r" % (b, a)) 21 | wa_count += 1 22 | 23 | 24 | def assert_neq(a, b, m): 25 | _assert(a, b, m, "!=") 26 | 27 | 28 | def assert_eq(a, b, m): 29 | _assert(a, b, m, "==") 30 | 31 | 32 | def test(): 33 | F = FiniteField(101) 34 | x = F(2) 35 | y = F(203) 36 | assert_neq(x, 1, "x != 1") 37 | assert_eq(x, 2, "x == 2") 38 | 39 | F = FiniteField(5) 40 | x = F(3) 41 | y = F(7) # = 2 42 | print(F) 43 | print("[+] x, y = %s, %s" % (x, y)) 44 | assert_eq(x + y, F(0), "x+y == F(0)") 45 | assert_eq(x + y, 0, "x+y == 0") 46 | assert_eq(x - y, 1, "x-y == 1") 47 | assert_eq(x * y, 1, "x*y == 1") 48 | x = F(2) 49 | y = F(3) 50 | print("[+] x, y = %s, %s" % (x, y)) 51 | # commutive! 52 | assert_eq(1 / x, y, "1/x == y") 53 | assert_eq(util.modinv(x.x, F.p), y, "modinv(x) == y") 54 | assert_eq(1 / y, x, "1/y == x") 55 | 56 | assert_eq(x**3, y, "x^3 == y") 57 | 58 | assert_eq(util.crt([3, 4], [4, 9]), 31, "CRT Test") 59 | # assert_eq(util.crt([7, 13], [12, 18]), 31, "CRT Test 2") 60 | 61 | assert_eq(F.order(), 4, "|F| = 4") 62 | assert_eq(x.order(), 4, "|x| = 4") 63 | 64 | F = FiniteField(17) 65 | E = EllipticCurve(F, 1, 0) 66 | 67 | P = E(1, 6) 68 | Q = E(11, 4) 69 | print("P, Q = %r, %r" % (P, Q)) 70 | assert_eq(P + Q, E(3, 8), "P+Q") 71 | assert_eq(P + P, E(0, 0), "P+P") 72 | assert_eq(P * 2, E(0, 0), "P*2") 73 | assert_eq(2 * P, E(0, 0), "2*P") 74 | assert_eq(P.order(), 4, "|P| = 4") 75 | 76 | print("Random Test: ") 77 | i = 0 78 | while i < 10: 79 | while True: 80 | r = randint(-50, 50) 81 | if r != 0: 82 | break 83 | print("[+] random 1 = %d" % r) 84 | assert_eq((util.modinv(r, 101) * r) % 101, 1, "modinv") 85 | while True: 86 | q = randint(-50, 50) 87 | if q != 0: 88 | break 89 | print("[+] random 2 = %d" % q) 90 | assert_eq(r * (q * P), q * (r * P), "ECDH test") 91 | i += 1 92 | 93 | # The arithmetic of elliptic curves: p.397 example of miller algorithm 94 | F = FiniteField(631) 95 | E = EllipticCurve(F, 30, 34) 96 | m = 5 97 | 98 | P = E(36, 60) 99 | Q = E(121, 387) 100 | S = E(0, 36) 101 | 102 | print("P, Q, S = %r, %r, %r" % (P, Q, S)) 103 | assert_eq(E.embedding_degree(m), 1, "embedding degree") 104 | assert_eq(miller(E, P, Q + S, m), 103, "miller(P, Q+S)") 105 | assert_eq(miller(E, P, S, m), 219, "miller(P, S)") 106 | assert_eq(miller(E, Q, P - S, m), 284, "miller(Q, P-S)") 107 | assert_eq(miller(E, Q, -S, m), 204, "miller(Q, -S)") 108 | assert_eq(weil_pairing(E, P, Q, m, S), 242, "weil_pairing") 109 | assert_eq(tate_pairing(E, P, Q, m, 1), 279, "tate_pairing") 110 | g = tate_pairing(E, P, Q, m) 111 | print("[+] g = %s" % g) 112 | assert_eq(tate_pairing(E, 2 * P, Q, m), g**2, "e(2P, Q) == g^2") 113 | assert_eq(tate_pairing(E, P, 2 * Q, m), g**2, "e(P, 2Q) == g^2") 114 | assert_eq(tate_pairing(E, P, Q, m) ** 2, g**2, "e(P, Q)^2 == g^2") 115 | 116 | print("[+] SSSA-Attack") 117 | F = FiniteField(16857450949524777441941817393974784044780411511252189319) 118 | 119 | A = 16857450949524777441941817393974784044780411507861094535 120 | B = 77986137112576 121 | 122 | E = EllipticCurve(F, A, B) 123 | 124 | """ 125 | print "Random Point" 126 | for x in xrange(10): 127 | print E.random_point() 128 | """ 129 | 130 | P = E( 131 | 5732560139258194764535999929325388041568732716579308775, 132 | 14532336890195013837874850588152996214121327870156054248, 133 | ) 134 | Q = E( 135 | 2609506039090139098835068603396546214836589143940493046, 136 | 8637771092812212464887027788957801177574860926032421582, 137 | ) 138 | 139 | assert_eq( 140 | SSSA_Attack(F, E, P, Q), 141 | 6418297401790414611703852603267852625498215178707956450, 142 | "SSSA-Attack", 143 | ) 144 | 145 | p = 0xD3CEEC4C84AF8FA5F3E9AF91E00CABACAAAECEC3DA619400E29A25ABECECFDC9BD678E2708A58ACB1BD15370ACC39C596807DAB6229DCA11FD3A217510258D1B 146 | A = 0x95FC77EB3119991A0022168C83EEE7178E6C3EEAF75E0FDF1853B8EF4CB97A9058C271EE193B8B27938A07052F918C35ECCB027B0B168B4E2566B247B91DC07 147 | B = 0x926B0E42376D112CA971569A8D3B3EDA12172DFB4929AEA13DA7F10FB81F3B96BF1E28B4A396A1FCF38D80B463582E45D06A548E0DC0D567FC668BD119C346B2 148 | Gx = 0xCF634030986CF41C1ADD87E71D638B9CC723C764059CF4C9B8ED2A0AAF5D51DC770372503EBFAAD746AB9220E992C09822916978226465AD31D354A3EFEE51DA 149 | Gy = 0x65EAAD8848B2787103FCE02358B45D8A61420031989EB6B4B70D82FE20D85583AE542EB8F76749DC640B0F13F682228819B8B2F04BD7A5A17A4C675540FE1C90 150 | Px = 10150325274093651859575658519947563789222194633356867789068177057343771571940302488270622886585658965620106459791565259790154958179860547267338437952379763 151 | Py = 6795014289013853849339410895464797184780777251924203530417684718894057583288011725702609805686960505075072642102076744937056900144377846048950215257629102 152 | 153 | F = FiniteField(p) 154 | E = EllipticCurve(F, A, B) 155 | G = E(Gx, Gy) 156 | P = E(Px, Py) 157 | assert_eq( 158 | SSSA_Attack(F, E, G, P), 159 | 0x746A6374667B6F6F70735F656C6C31707431635F6375727665735F525F683472647D, 160 | "SSSA-Attack (TJCTF 2016 Crypto 200: curvature2)\n", 161 | ) 162 | z = CC(1, 2) # 1+2i 163 | w = CC(5, 1) # 5+i 164 | print("z, w = %r, %r" % (z, w)) 165 | assert_eq(z + w, CC(6, 3), "z+w") 166 | assert_eq(z - w, CC(-4, 1), "z-w") 167 | assert_eq(z * w, CC(3, 11), "z*w") 168 | assert_eq(z / w, CC(0.2692307692307693, 0.34615384615384615), "z/w") 169 | 170 | F = ExtendedFiniteField(59) 171 | a = F(0, 1) 172 | E = EllipticCurve(F, 1, 0) 173 | P = E(25, 30) 174 | assert_eq(tuple(P), (25, 30, 1), "extended field EC") 175 | Q = P.distortion_map() 176 | assert_eq(tuple(Q), (F(34), F(0, 30), 1), "extended field EC 2") 177 | 178 | assert_eq(Q.distortion_map(), P, "distortion map") 179 | 180 | l = 56453 181 | m = l 182 | p = l * 6 - 1 183 | F = ExtendedFiniteField(p, "x^2+x+1") 184 | print("Random Test 2:") 185 | for x in xrange(10): 186 | r1 = randint(0, p) 187 | r2 = randint(0, p) 188 | r = F(r1, r2) 189 | print("[+] r = %s" % r) 190 | assert_eq(r ** (p**2), r, "r^(p^2) == r") 191 | 192 | E = EllipticCurve(F, 0, 1) 193 | P = E(3, 1164) 194 | print(P) 195 | print(P.distortion_map()) 196 | 197 | g = symmetric_weil_pairing(E, P, P, m) 198 | print("[+] g = %s" % g) 199 | 200 | assert_eq(symmetric_weil_pairing(E, P, 2 * P, m), g**2, "e(P, 2P) == g^2") 201 | assert_eq(symmetric_weil_pairing(E, 2 * P, P, m), g**2, "e(2P, 2P) == g^2") 202 | assert_eq(symmetric_weil_pairing(E, P, P, m) ** 2, g**2, "e(P, P)^2 == g^2") 203 | 204 | g = symmetric_tate_pairing(E, P, P, m) 205 | print("[+] g = %s" % g) 206 | 207 | assert_eq(symmetric_tate_pairing(E, P, 2 * P, m), g**2, "e(P, 2P) == g^2") 208 | assert_eq(symmetric_tate_pairing(E, 2 * P, P, m), g**2, "e(2P, 2P) == g^2") 209 | 210 | assert_eq( 211 | F(53521, 219283) / F(297512, 101495), F(333099, 288028), "r/prev_r test: 0" 212 | ) 213 | assert_eq(F(281317, 98371) / F(53521, 219283), F(323815, 46359), "r/prev_r test: 1") 214 | assert_eq(F(31851, 95658) / F(281317, 98371), F(5298, 9638), "r/prev_r test: 2") 215 | assert_eq(F(92937, 215632) / F(31851, 95658), F(278130, 175879), "r/prev_r test: 3") 216 | assert_eq( 217 | F(61703, 173508) / F(92937, 215632), F(189715, 176788), "r/prev_r test: 4" 218 | ) 219 | assert_eq(F(80979, 72727) / F(61703, 173508), F(15407, 212022), "r/prev_r test: 5") 220 | assert_eq(F(311516, 184895) / F(80979, 72727), F(225531, 44087), "r/prev_r test: 6") 221 | assert_eq( 222 | F(326035, 114920) / F(311516, 184895), F(213234, 100495), "r/prev_r test: 7" 223 | ) 224 | assert_eq( 225 | F(294922, 165746) / F(326035, 114920), F(113566, 200451), "r/prev_r test: 8" 226 | ) 227 | assert_eq( 228 | F(73542, 195813) / F(294922, 165746), F(201397, 252614), "r/prev_r test: 9" 229 | ) 230 | assert_eq(1 / F(338714, 3), F(37635, 188176), "division by b = -a") 231 | 232 | assert_eq(F(302128, 326350) * F(39563, 131552), F(151684, 28719), "multiple test") 233 | 234 | assert_eq( 235 | miller(E, P, P.distortion_map(), m), F(239139, 508), "miller function check" 236 | ) 237 | 238 | a = F(234687, 190012) 239 | b = F(218932, 251221) 240 | 241 | print("[+] a = %s" % a) 242 | print("[+] b = %s" % b) 243 | 244 | assert_eq(a + b, F(114902, 102516), "a+b") 245 | assert_eq(a - b, F(15755, 277508), "a-b") 246 | assert_eq(a * b, F(217278, 89209), "a*b") 247 | assert_eq(a / b, F(167345, 81997), "a/b") 248 | assert_eq(a * a * a * a, F(31723, 160374), "a*a*a*a") 249 | assert_eq(a**4, F(31723, 160374), "a^4") 250 | assert_eq(a * a * b * b * a * a * b, b * a * a * b * b * a * a, "a^4") 251 | 252 | # E, F, l = gen_supersingular_ec() 253 | l = 670879118046860960563 254 | p = 4025274708281165763377 255 | F = ExtendedFiniteField(p, "x^2+x+1") 256 | E = EllipticCurve(F, 0, 1) 257 | # P = find_point_by_order(E, l) 258 | P = E(7, 658176732497617012595, 1) 259 | Q = P.distortion_map() 260 | g = tate_pairing(E, P, Q, l) 261 | print(E) 262 | for x in xrange(10): 263 | a = randint(2**15, 2**16) 264 | b = randint(2**15, 2**16) 265 | print("Random Pairing Test: a = %d, b = %d" % (a, b)) 266 | gab = g ** (a * b) 267 | assert_eq(tate_pairing(E, a * P, b * Q, l), gab, "e(aP, bQ)") 268 | assert_eq(tate_pairing(E, a * P, Q, l) ** b, gab, "e(aP, Q)^b") 269 | assert_eq(tate_pairing(E, b * P, Q, l) ** a, gab, "e(bP, Q)^a") 270 | assert_eq(tate_pairing(E, P, a * Q, l) ** b, gab, "e(P, aQ)^b") 271 | assert_eq(tate_pairing(E, P, b * Q, l) ** a, gab, "e(P, bQ)^a") 272 | 273 | assert_eq( 274 | util.prime_factorization(12345678), 275 | {2: 1, 3: 2, 47: 1, 14593: 1}, 276 | "prime factor1", 277 | ) 278 | assert_eq(util.prime_factorization(12345), {3: 1, 5: 1, 823: 1}, "prime factor2") 279 | assert_eq(util.euler_phi(12345), 6576, "phi(12345)") 280 | 281 | for name in [ 282 | "secp192k1", 283 | "secp192r1", 284 | "secp224k1", 285 | "secp224r1", 286 | "secp256k1", 287 | "secp256r1", 288 | "secp384r1", 289 | "secp521r1", 290 | ]: 291 | F, E, G, n = EllipticCurveRepository(name) 292 | assert_eq(G * n, E.O, name) 293 | 294 | # secp224k1 bug (Issue #3) 295 | p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D 296 | a = 0 297 | b = 5 298 | F = FiniteField(p) 299 | E = EllipticCurve(F, a, b) 300 | Gx = 0xA1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C 301 | Gy = 0x7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5 302 | G = E(Gx, Gy) 303 | n = 0x010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7 304 | assert_eq(n * G, E.O, "Issue #3") 305 | 306 | PR = UnivariatePolynomialRing(RR, "X") 307 | X = PR.gen() 308 | assert_eq(str(X), "X", "Polynomial ring generator name") 309 | 310 | poly_test = lambda p, q: all(map(lambda x: x[0] == x[1], zip(p, q))) 311 | 312 | assert_eq(poly_test(X + 1, [1, 1]), True, "x+1") 313 | assert_eq(poly_test(X - 1, [-1, 1]), True, "x-1") 314 | assert_eq(poly_test(X * X, [0, 0, 1]), True, "x^2") 315 | assert_eq(poly_test((X**2 + 1) - X, [1, -1, 1]), True, "(x^2+1) - x") 316 | assert_eq( 317 | poly_test((X**3 + 8 * X**2 + x + 8) / (X**2 + 1), [8, 1]), 318 | True, 319 | "(x^3+8x^2+x+8)/(x^2+1)", 320 | ) 321 | assert_eq( 322 | poly_test((X**2 + 2 * X - 2) % (X**2 + 1), [-3, 2]), 323 | True, 324 | "(x^2+2x-2) % (x^2+1)", 325 | ) 326 | 327 | print("=== Test for Univariate Polynomial Ring over Z/5Z ===") 328 | 329 | PR = UnivariatePolynomialRing(Zmod(5)) 330 | x = PR.gen() 331 | P = x**2 + 1 332 | R = x**3 - 3 333 | assert_eq(poly_test(P * R, [2, 0, 2, 1, 0, 1]), True, "P * R") 334 | assert_eq(poly_test((P * R) / R, P), True, "(P * R) / R") 335 | assert_eq( 336 | poly_test((P * R) / (3 * x**2 + 3), [4, 0, 0, 2]), True, "(P * R) / 3x^2 + 3" 337 | ) 338 | 339 | PR = BivariatePolynomialRing(RR, ["x", "y"]) 340 | print(PR) 341 | x, y = PR.gens() 342 | assert_eq(str(x), "x", "str(x)") 343 | assert_eq(str(y), "y", "str(y)") 344 | assert_eq(str(x + y), "x+y", "str(x+y)") 345 | assert_eq(str(y * (x + y)), "xy+y^2", "str(y*(x+y))") 346 | print(y**2 - x**3 + 3 * x - 1) 347 | 348 | x = ZZ(0xCAFEBABE) 349 | y = ZZ(0xDEADBEEF) 350 | assert_eq(x + y, 7141620141, "Integer Addition") 351 | assert_eq(x - y, -330236977, "Integer Subtract") 352 | assert_eq(x * y, 12723420444339690338, "Integer Multiplication") 353 | 354 | QR = QuotientRing(ZZ, 5) 355 | print(QR) 356 | x = QR(3) 357 | y = QR(7) 358 | assert_eq(x, 3, "3 mod 5") 359 | assert_eq(y, 2, "7 mod 5") 360 | assert_eq(x + y, 0, "x+y") 361 | assert_eq(x - y, 1, "x-y") 362 | assert_eq(x * y, 1, "x*y") 363 | assert_eq(x / y, 4, "x/y") 364 | 365 | PR = UnivariatePolynomialRing(ZZ) 366 | x = PR.gen() 367 | QR = QuotientRing(PR, x**2 + 1) 368 | print(QR) 369 | a = QR(1) 370 | b = QR(x) 371 | assert_eq(a, 1, "a") 372 | assert_eq(b, x, "b") 373 | assert_eq(a + b, x + 1, "a+b") 374 | assert_eq(a * b, x, "a*b") 375 | assert_eq(b * b, -1, "b^2") 376 | assert_eq(b * b + a, 0, "b^2 + a") 377 | 378 | from ecpy import is_prime 379 | 380 | assert_eq(is_prime(10007), True, "10007 is prime") 381 | assert_eq(is_prime(2), True, "2 is prime") 382 | assert_eq(is_prime(4), False, "4 is not prime") 383 | assert_eq(is_prime(100160063), False, "10007 * 10009 is not prime") 384 | 385 | print( 386 | "[+] %d Test(s) finished. %d Test(s) success, %d Test(s) fail." 387 | % (ac_count + wa_count, ac_count, wa_count) 388 | ) 389 | sys.exit(wa_count) 390 | 391 | 392 | if __name__ == "__main__": 393 | test() 394 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = E111, E114, E711, E501 3 | 4 | exclude = __init__.py 5 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup( 4 | name="ecpy", 5 | version="1.1.1", 6 | description="A Elliptic-Curve Library", 7 | author="@elliptic_shiho", 8 | author_email="shiho.elliptic@gmail.com", 9 | url="https://github.com/elliptic-shiho/ecpy/", 10 | packages=["ecpy", "ecpy.fields", "ecpy.rings", "ecpy.utils", "ecpy.elliptic_curve"], 11 | install_requires=["six"], 12 | ) 13 | --------------------------------------------------------------------------------