├── .gitignore ├── AUTHORS ├── LICENSE ├── ecfactory ├── __init__.py ├── bn_curves │ ├── __init__.py │ ├── bn_curves.py │ ├── bn_curves_cpp │ │ ├── README.md │ │ ├── bn_search.cpp │ │ └── bn_statistics │ ├── bn_curves_examples.py │ ├── bn_curves_tests.py │ └── readme.md ├── cocks_pinch │ ├── __init__.py │ ├── cocks_pinch.py │ ├── cocks_pinch_examples.py │ ├── cocks_pinch_tests.py │ └── readme.md ├── complex_multiplication │ ├── __init__.py │ ├── complex_multiplication.py │ ├── complex_multiplication_examples.py │ ├── complex_multiplication_tests.py │ └── readme.md ├── dupont_enge_morain │ ├── __init__.py │ ├── dupont_enge_morain.py │ ├── dupont_enge_morain_examples.py │ ├── dupont_enge_morain_tests.py │ └── readme.md ├── ec_chain │ ├── __init__.py │ ├── ec_chain.py │ ├── ec_chain_examples.py │ ├── ec_chain_tests.py │ └── readme.md ├── mnt_curves │ ├── __init__.py │ ├── mnt6_enumeration.csv │ ├── mnt_curves.py │ ├── mnt_curves_examples.py │ └── readme.md ├── mnt_cycles │ ├── __init__.py │ ├── mnt_cycles.py │ ├── mnt_cycles_examples.py │ └── readme.md ├── pell_equation_solver │ ├── __init__.py │ ├── pell_equation_solver.py │ ├── pell_equation_solver_examples.py │ ├── pell_equation_solver_test.py │ └── readme.md ├── profile │ ├── logs │ │ ├── cp │ │ │ ├── k10.csv │ │ │ ├── k11.csv │ │ │ ├── k12.csv │ │ │ ├── k13.csv │ │ │ ├── k14.csv │ │ │ ├── k15.csv │ │ │ ├── k16.csv │ │ │ ├── k17.csv │ │ │ ├── k18.csv │ │ │ ├── k19.csv │ │ │ ├── k5.csv │ │ │ ├── k52.csv │ │ │ ├── k6.csv │ │ │ ├── k7.csv │ │ │ ├── k8.csv │ │ │ └── k9.csv │ │ └── dem │ │ │ ├── k10.csv │ │ │ ├── k11.csv │ │ │ ├── k12.csv │ │ │ ├── k13.csv │ │ │ ├── k14.csv │ │ │ ├── k15.csv │ │ │ ├── k16.csv │ │ │ ├── k17.csv │ │ │ ├── k18.csv │ │ │ ├── k19.csv │ │ │ ├── k5.csv │ │ │ ├── k52.csv │ │ │ ├── k6.csv │ │ │ ├── k7.csv │ │ │ ├── k8.csv │ │ │ └── k9.csv │ ├── plot_cp.gp │ ├── plot_cp_vs_dem.gp │ ├── plot_dem.gp │ ├── plots │ │ ├── cp │ │ │ └── cp.svg │ │ ├── cp_vs_dem │ │ │ ├── k10.svg │ │ │ ├── k11.svg │ │ │ ├── k12.svg │ │ │ ├── k13.svg │ │ │ ├── k14.svg │ │ │ ├── k15.svg │ │ │ ├── k16.svg │ │ │ ├── k17.svg │ │ │ ├── k18.svg │ │ │ ├── k19.svg │ │ │ ├── k5.svg │ │ │ ├── k6.svg │ │ │ ├── k7.svg │ │ │ ├── k8.svg │ │ │ └── k9.svg │ │ └── dem │ │ │ └── dem.svg │ └── profile.py └── utils │ ├── __init__.py │ ├── readme.md │ └── utils.py ├── pyproject.toml ├── readme.md └── references ├── Barreto Naehrig 2005 --- Pairing-Friendly Elliptic Curves of Prime Order.pdf ├── Freeman Scott Teske 2010 --- A Taxonomy of Pairing-Friendly Elliptic Curves.pdf ├── Karabina Teske 2007 --- On prime-order elliptic curves with embedding degrees k = 3,4, and 6.pdf └── Washington 2008 --- Elliptic Curves Number Theory and Cryptography.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | *.sage.py 2 | *.aux 3 | *.log 4 | *.out 5 | *.synctex.gz 6 | *.pyc 7 | *.DS_Store 8 | *.class 9 | *.java 10 | __pycache__ -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Alessandro Chiesa 2 | Peter Manohar 3 | Madars Virza 4 | Howard Wu 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The ecfactory library is developed by SCIPR Lab (http://scipr-lab.org) 2 | and contributors. 3 | 4 | Copyright (c) 2016 SCIPR Lab and contributors (see AUTHORS file). 5 | 6 | All files, with the exceptions below, are released under the MIT License: 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. -------------------------------------------------------------------------------- /ecfactory/__init__.py: -------------------------------------------------------------------------------- 1 | import ecfactory.utils 2 | import ecfactory.bn_curves 3 | import ecfactory.cocks_pinch 4 | import ecfactory.complex_multiplication 5 | import ecfactory.dupont_enge_morain 6 | import ecfactory.ec_chain 7 | import ecfactory.mnt_curves 8 | import ecfactory.mnt_cycles 9 | import ecfactory.pell_equation_solver 10 | -------------------------------------------------------------------------------- /ecfactory/bn_curves/__init__.py: -------------------------------------------------------------------------------- 1 | from .bn_curves import make_curve -------------------------------------------------------------------------------- /ecfactory/bn_curves/bn_curves.py: -------------------------------------------------------------------------------- 1 | from sage.all import random, power_mod, primitive_root, Integer, random_prime, is_prime, kronecker, squarefree_part, is_square, Mod, fundamental_discriminant, sqrt, log, floor 2 | from ecfactory.utils import is_valid_curve 3 | import ecfactory.utils as utils 4 | 5 | def make_curve(num_bits, num_curves=1): 6 | """ 7 | Description: 8 | 9 | Finds num_curves Barreto-Naehrig curves with a prime order that is at least 2^num_bits. 10 | 11 | Input: 12 | 13 | num_bits - number of bits for the prime order of the curve 14 | num_curves - number of curves to find 15 | 16 | Output: 17 | 18 | curves - list of the first num_curves BN curves each of prime order at least 2^num_bits; 19 | each curve is represented as a tuple (q,t,r,k,D) 20 | 21 | """ 22 | def P(y): 23 | x = Integer(y) 24 | return 36*pow(x,4) + 36*pow(x,3) + 24*pow(x,2) + 6*x + 1 25 | x = Integer(floor(pow(2, (num_bits)/4.0)/(sqrt(6)))) 26 | q = 0 27 | r = 0 28 | t = 0 29 | curve_num = 0 30 | curves = [] 31 | while curve_num < num_curves or (log(q).n()/log(2).n() < 2*num_bits and not (utils.is_suitable_q(q) and utils.is_suitable_r(r) and utils.is_suitable_curve(q,t,r,12,-3,num_bits))): 32 | t = Integer(6*pow(x,2) + 1) 33 | q = P(-x) 34 | r = q + 1 - t 35 | b = utils.is_suitable_q(q) and utils.is_suitable_r(r) and utils.is_suitable_curve(q,t,r,12,-3,num_bits) 36 | if b: 37 | try: 38 | assert floor(log(r)/log(2)) + 1 >= num_bits, 'Subgroup not large enough' 39 | curves.append((q,t,r,12,-3)) 40 | curve_num += 1 41 | except AssertionError as e: 42 | pass 43 | if curve_num < num_curves or not b: 44 | q = P(x) 45 | r = q+1-t 46 | if (utils.is_suitable_q(q) and utils.is_suitable_r(r) and utils.is_suitable_curve(q,t,r,12,-3,num_bits)): 47 | try: 48 | assert floor(log(r)/log(2)) + 1 >= num_bits, 'Subgroup not large enough' 49 | curves.append((q,t,r,12,-3)) 50 | curve_num += 1 51 | except AssertionError as e: 52 | pass 53 | x += 1 54 | return curves -------------------------------------------------------------------------------- /ecfactory/bn_curves/bn_curves_cpp/README.md: -------------------------------------------------------------------------------- 1 | # bn_curves_cpp 2 | 3 | This module provides a fast C++ implementation for finding Barreto-Naehrig curve parameters. 4 | 5 | ## Installation 6 | 7 | ### Ubuntu 14.04 8 | 9 | Install GMP and NTL: 10 | ``` 11 | sudo apt-get install libgmp3-dev libntl27 12 | ``` 13 | 14 | ### macOS 15 | 16 | Install Homebrew: 17 | ``` 18 | ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" < /dev/null 2> /dev/null 19 | ``` 20 | 21 | Install GMP: 22 | ``` 23 | brew install gmp 24 | ``` 25 | 26 | Install NTL: 27 | ``` 28 | brew install ntl 29 | ``` 30 | 31 | ## Run 32 | 33 | Compile with: 34 | ``` 35 | g++ -o bn_search bn_search.cpp -lntl -lgmp 36 | ``` 37 | 38 | Run with: 39 | ``` 40 | ./bn_search {seed for RNG} {even_shift_of_x} {2-adicity} 41 | ``` 42 | 43 | For example, using the seed 100, and sampling values of x that are multiples of 2^2, looking for a two adicity of 10, would be: 44 | ``` 45 | ./bn_search 100 2 10 46 | ``` 47 | 48 | ## Log and analyze 49 | 50 | We provide a statistics script to generate a histogram of findings. To use it, log the output of `bn_search` as follows: 51 | ``` 52 | ./bn_search 100 2 10 > log.txt 53 | ``` 54 | 55 | Then use `bn_statistics` on the log as follows: 56 | ``` 57 | ./bn_statistics log.txt 58 | ``` 59 | -------------------------------------------------------------------------------- /ecfactory/bn_curves/bn_curves_cpp/bn_search.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | using namespace NTL; 9 | 10 | #define REPORT_INTERVAL 100000 11 | #define MAX_Q_BITS 255 12 | 13 | /* 14 | This code modifies [Algorithm 1, BN06] to search for candidate parameters of 15 | Barreto-Naehrig curves with high 2-adicity. (The curve itself can be explicitly 16 | constructed by following the second half of [Algorithm 1, BN06].) 17 | 18 | This code was used to find the BN curve in [BCTV13]. 19 | 20 | [BCTV13] = "Succinct Non-Interactive Arguments for a von Neumann Architecture" 21 | [BN06] = "Pairing-Friendly Elliptic Curves of Prime Order" 22 | */ 23 | 24 | int main(int argc, char **argv) 25 | { 26 | if (argc != 4) 27 | { 28 | cout << "usage: " << argv[0] << " [rand_seed even_offset wanted_two_adicity]\n"; 29 | return 0; 30 | } 31 | 32 | /* Collect inputs */ 33 | ZZ seed; 34 | conv(seed, atoi(argv[1])); 35 | long even_offset = atoi(argv[2]); 36 | long wanted_two_adicity = atoi(argv[3]); 37 | 38 | /* |x| ~ 64 bits so that |q| = 4 * |x| ~ 256 bits */ 39 | long num_x_bits = 63; 40 | 41 | long num_iters = 0; 42 | long num_found = 0; 43 | 44 | SetSeed(seed); 45 | while (1) 46 | { 47 | ++num_iters; 48 | 49 | /* Sample x */ 50 | ZZ x = RandomLen_ZZ(num_x_bits); 51 | 52 | /** 53 | * Make x even and divisible by a large power of 2 to improve two adicity. 54 | * The resulting q is s.t. -1 is a square in Fq. 55 | */ 56 | x = ((x >> even_offset) << even_offset); 57 | 58 | /* Uncomment to make x odd and ensure that -1 is a nonsquare in Fq. */ 59 | // SetBit(x, 0); 60 | 61 | /** 62 | * Compute candidate BN parameters using the formulas: 63 | * t = 6*x^2 + 1, 64 | * q = 36*x^4 + 36*x^3 + 24*x^2 + 6*x + 1 65 | * r = q - t + 1 66 | * (see [BN06]) 67 | */ 68 | ZZ x2 = x * x; 69 | ZZ x3 = x2 * x; 70 | ZZ x4 = x3 * x; 71 | ZZ t = 6 * x2 + 1; 72 | ZZ q = 36 * x4 + 36 * x3 + 24 * x2 + 6 * x + 1; 73 | ZZ r = q - t + 1; 74 | 75 | long num_q_bits = NumBits(q); 76 | long two_adicity = NumTwos(r-1); 77 | 78 | if (num_q_bits > MAX_Q_BITS) 79 | { 80 | continue; 81 | } 82 | 83 | if (ProbPrime(r) && ProbPrime(q) && (two_adicity >= wanted_two_adicity)) 84 | { 85 | cout << "x = " << x << "\n"; 86 | cout << "q = " << q << "\n"; 87 | cout << "r = " << r << "\n"; 88 | cout << "log2(q) =" << num_q_bits << "\n"; 89 | cout << "ord_2(r-1) = " << two_adicity << "\n"; 90 | cout.flush(); 91 | ++num_found; 92 | } 93 | 94 | if (num_iters % REPORT_INTERVAL == 0) 95 | { 96 | printf("[ num_iters = %ld , num_found = %0.2f per %d ]\n", num_iters, 1.*REPORT_INTERVAL*num_found/num_iters, REPORT_INTERVAL); 97 | fflush(stdout); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /ecfactory/bn_curves/bn_curves_cpp/bn_statistics: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | FILE=$1 4 | 5 | for i in `seq 10 64`; 6 | do 7 | echo "$i:" 8 | cat $FILE | grep "(r-1) = $i" | wc -l 9 | done 10 | -------------------------------------------------------------------------------- /ecfactory/bn_curves/bn_curves_examples.py: -------------------------------------------------------------------------------- 1 | import ecfactory.bn_curves as bn 2 | from ecfactory.utils import print_curve 3 | 4 | # Example 5 | num_bits = 100 # number of bits in r 6 | num_curves = 10 # number of curves to find 7 | curves = bn.make_curve(num_bits, num_curves) 8 | for q,t,r,k,D in curves: 9 | print_curve(q,t,r,k,D) -------------------------------------------------------------------------------- /ecfactory/bn_curves/bn_curves_tests.py: -------------------------------------------------------------------------------- 1 | from sage.all import randint 2 | import ecfactory.bn_curves as bn 3 | import ecfactory.utils as utils 4 | 5 | def test_bn(num_tests): 6 | # finds num_tests BN curves with random bit sizes; 7 | # checks that each curve found is a suitable curve 8 | print('testing BN...') 9 | fail = 0 10 | for i in range(0, num_tests): 11 | num_bits = randint(50,100) 12 | num_curves = randint(1, 20) 13 | try: 14 | curves = bn.make_curve(num_bits, num_curves) 15 | assert len(curves) == num_curves 16 | for q,t,r,k,D in curves: 17 | assert utils.is_suitable_curve(q,t,r,k,D, num_bits) 18 | except AssertionError as e: 19 | fail+=1 20 | if fail == 0: 21 | print('test passed') 22 | return True 23 | else: 24 | print("failed %.2f" %(100*fail/num_tests) + "% of tests!") 25 | return False 26 | 27 | 28 | test_bn(100) -------------------------------------------------------------------------------- /ecfactory/bn_curves/readme.md: -------------------------------------------------------------------------------- 1 | Barreto-Naehrig Curves 2 | ====================== 3 | 4 | Overview 5 | -------- 6 | 7 | This module provides functionality to construct _Barreto-Naehrig (BN) curves_, following the procedure described in [\[BN05\]](/references/Barreto%20Naehrig%202005%20---%20Pairing-Friendly%20Elliptic%20Curves%20of%20Prime%20Order.pdf). The module contains three files: 8 | 9 | * `bn_curves.py`, which contains the algorithm to construct Barreto-Naehrig curves; 10 | 11 | * `bn_curves_examples.py`, which contains code examples; 12 | 13 | * `bn_curves_tests.py`, which contains unit tests. 14 | 15 | Throughout, 16 | _q_ denotes the prime size of the base field; 17 | _t_ denotes the trace of Frobenius; 18 | _r_ denotes the prime size of the group; 19 | _k_ denotes the embedding degree; 20 | _D_ denotes the (negative) fundamental discriminant. 21 | 22 | Methods 23 | ------- 24 | 25 | The main method in `bn_curves.py` is 26 | 27 | ```python 28 | make_curve(num_bits, num_curves=1) 29 | ``` 30 | 31 | It outputs a list of the first *num\_curves* BN curves of prime order at least 2*num\_bits*. 32 | 33 | Examples 34 | -------- 35 | 36 | The code example in `bn_curves_examples.py` shows how to find 10 BN curves with a prime order that is at least 2100. 37 | 38 | Tests 39 | ----- 40 | 41 | The test in `bn_curves_tests.py` runs the algorithm on random bit-sizes and checks validity of the output. 42 | -------------------------------------------------------------------------------- /ecfactory/cocks_pinch/__init__.py: -------------------------------------------------------------------------------- 1 | from .cocks_pinch import find_element_of_order, method, run, gen_params_from_bits, gen_params_from_r, test_promise -------------------------------------------------------------------------------- /ecfactory/cocks_pinch/cocks_pinch.py: -------------------------------------------------------------------------------- 1 | from sage.all import random, power_mod, primitive_root, Integer, random_prime, is_prime, kronecker, squarefree_part, is_square, Mod, fundamental_discriminant, randint 2 | import time 3 | from ecfactory.utils import is_valid_curve 4 | import ecfactory.utils as utils 5 | 6 | def find_element_of_order(k,r): 7 | """ 8 | Description: 9 | 10 | Finds a random element of order k in Z_r^* 11 | 12 | Input: 13 | 14 | k - integer such that r % k == 1 15 | r - prime 16 | 17 | Output: 18 | 19 | h - element of order k in Z_r^* 20 | 21 | """ 22 | assert r % k == 1 23 | h = 0 24 | def order(h,k,p): 25 | bool = True 26 | g = h 27 | for i in range(1,k): 28 | bool = bool and g != 1 29 | g = Mod(g * h, p) 30 | bool = bool and g == 1 31 | return bool 32 | while not order(h,k,r): # expected number of iterations is k/euler_phi(k) 33 | h = power_mod(randint(2, r-1), (r-1)//k, r) 34 | return h 35 | 36 | 37 | def method(r,k,D,max_trials=10000, g=0): 38 | """ 39 | Description: 40 | 41 | Run the Cocks-Pinch method to find an elliptic curve 42 | 43 | Input: 44 | 45 | r - prime 46 | k - embedding degree, r % k == 1 47 | D - (negative) fundamental discriminant where D is a square mod r 48 | max_trials - the number of integers q to test for primality in the CP method 49 | g - an element of order k in Z_r^* 50 | 51 | Output: 52 | 53 | (q,t) - tuple where q is a prime and t is chosen such that there exists 54 | an elliptic curve E over F_q with trace t, and r | q+1-t; 55 | if the algorithm fails to find (q,t), it will return (0,0) 56 | 57 | """ 58 | assert test_promise(r,k,D), 'Invalid inputs' 59 | if g != 0: 60 | assert power_mod(g,k,r) == 1, 'Invalid inputs' 61 | else: 62 | g = find_element_of_order(k,r) 63 | D = Integer(D) 64 | t = Integer(g) + 1 65 | root_d = Integer(Mod(D, r).sqrt()) 66 | u = Integer(Mod((t-2)*root_d.inverse_mod(r) ,r)) 67 | q = 1 68 | j = Integer(0) 69 | i = Integer(0) 70 | count = 0 71 | while (count < max_trials): 72 | q = Integer( (t+i*r)**2 - D*(u + j*r)**2) 73 | if q % 4 ==0: 74 | q = q//4 75 | if utils.is_suitable_q(q): 76 | return (q, t+i*r) 77 | q = 1 78 | if random() < 0.5: 79 | j+=1 80 | else: 81 | i+=1 82 | count+=1 83 | return (0, 0) # no prime found, so end 84 | 85 | @utils.filter_decorator 86 | def run(r,k,D,max_run_time=20): 87 | """ 88 | Description: 89 | 90 | Runs the Cocks-Pinch method multiple times until a valid curve is found 91 | 92 | Input: 93 | 94 | r - prime 95 | k - embedding degree, r % k == 1 96 | D - (negative) fundamental discriminant where D is a square mod r 97 | max_run_time - maximum runtime of the function, in seconds 98 | 99 | Output: 100 | 101 | (q,t,r,k,D) - elliptic curve 102 | 103 | """ 104 | assert test_promise(r,k,D), 'Invalid inputs' 105 | q = 0 106 | t = 0 107 | start = time.time() 108 | while q == 0 and time.time() - start < max_run_time: # run cocks pinch method until successful 109 | q,t = method(r,k,D) 110 | assert is_valid_curve(q,t,r,k,D), 'Invalid output' 111 | return q,t,r,k,D 112 | 113 | def gen_params_from_bits(num_bits,k): 114 | """ 115 | Description: 116 | 117 | Generates a prime r with num_bits bits and a fundamental discriminant D to use as input to the Cocks-Pinch method 118 | 119 | Input: 120 | 121 | num_bits - number of bits in r 122 | k - embedding degree 123 | 124 | Output: 125 | 126 | r - prime such that r % k == 1 and r is num_bits bits long 127 | k - embedding degree 128 | D - (negative) fundamental discriminant where D is a square mod r 129 | 130 | """ 131 | r = random_prime(2**num_bits, lbound=2**(num_bits-1)) 132 | while not (r % k == 1 and utils.is_suitable_r(r)): 133 | r = random_prime(2**num_bits, lbound=2**(num_bits-1)) 134 | return gen_params_from_r(r,k) 135 | 136 | def gen_params_from_r(r,k): 137 | """ 138 | Description: 139 | 140 | Finds a fundamental discriminant D to use as input to the Cocks-Pinch method 141 | 142 | Input: 143 | 144 | r - prime such that r % k == 1 145 | k - embedding degree 146 | 147 | Output: 148 | 149 | r - prime such that r % k == 1 150 | k - embedding degree 151 | D - (negative) fundamental discriminant where D is a square mod r 152 | 153 | """ 154 | D = -Integer(Mod(int(random()*(1000)),r)) 155 | i = 0 156 | while not kronecker(D,r) == 1: # expected number of iterations of the while loop is 2 157 | D = -Integer(Mod(int(random()*(1000)),r)) 158 | i+=1 159 | D = fundamental_discriminant(D) 160 | if not (kronecker(D,r) == 1): 161 | return r, k, 0 162 | return r,k,D 163 | 164 | 165 | def test_promise(r,k,D): 166 | """ 167 | Description: 168 | 169 | Tests that r,k,D is a valid input to the Cocks-Pinch method 170 | 171 | Input: 172 | 173 | r - prime 174 | k - embedding degree 175 | D - (negative) funadmental discriminant 176 | 177 | Output: 178 | 179 | bool - true iff (r,k,D) is a valid input to the Cocks-Pinch method 180 | 181 | """ 182 | bool = (kronecker(D,r) == 1) # D is a square mod r 183 | bool = bool and ( (r-1) % k ==0) # k | r-1 184 | bool = bool and (D == fundamental_discriminant(D)) # check that D is a fundamental discriminant 185 | return bool -------------------------------------------------------------------------------- /ecfactory/cocks_pinch/cocks_pinch_examples.py: -------------------------------------------------------------------------------- 1 | import ecfactory.cocks_pinch as cp 2 | from ecfactory.utils import print_curve 3 | 4 | # Example 1 (using a known value of r) 5 | k = 5 # embedding degree 6 | r = 1743941 # size of prime order subgroup 7 | r,k,D = cp.gen_params_from_r(r,k) # find a valid D 8 | q,t,r,k,D = cp.run(r,k,D) # use CP method to solve for q and t 9 | print_curve(q,t,r,k,D) 10 | 11 | # Example 2 (algorithm generates r) 12 | k = 7 # embedding degree 13 | num_bits = 100 # number of bits in size of prime order subgroup 14 | r,k,D = cp.gen_params_from_bits(num_bits,k) 15 | q,t,r,k,D = cp.run(r,k,D) # use CP method to solve for q and t 16 | print_curve(q,t,r,k,D) 17 | 18 | # Example 3 (running cocks_pinch_method once with a specified num_times and g) 19 | k = 5 20 | r = 1743941 21 | r,k,D = cp.gen_params_from_r(r,k) 22 | g = 722825 23 | q,t = cp.method(r,k,D,max_trials=100,g=g) # might not find q and t 24 | print_curve(q,t,r,k,D) -------------------------------------------------------------------------------- /ecfactory/cocks_pinch/cocks_pinch_tests.py: -------------------------------------------------------------------------------- 1 | from sage.all import randint 2 | import time 3 | import ecfactory.cocks_pinch as cp 4 | import ecfactory.utils as utils 5 | 6 | def test_cp(num_tests,num_bits, debug=False): 7 | # runs CP method num_tests times; 8 | # each test uses a random embedding degree and an n bit prime 9 | test_cp2(num_tests,num_bits,False,debug) 10 | 11 | def test_cp2(num_tests,num_bits,k, debug=False): 12 | # runs CP method num_tests times; 13 | # uses the same embedding degree k for every test 14 | print('testing CP...') 15 | fail = 0 16 | k2 = k 17 | for i in range(0, num_tests): 18 | if not k2: 19 | k = randint(5,50) 20 | try: 21 | r,k,D = cp.gen_params_from_bits(num_bits, k) 22 | assert cp.test_promise(r,k,D) 23 | q,t,r,k,D = cp.run(r,k,D) 24 | assert utils.is_suitable_curve(q,t,r,k,D,num_bits) 25 | except AssertionError as e: 26 | fail += 1 27 | if fail == 0: 28 | print('test passed') 29 | return True 30 | else: 31 | print("failed %.2f" %(100*fail/num_tests) + "% of tests!") 32 | return False 33 | 34 | 35 | 36 | 37 | 38 | test_cp(100,50, False) 39 | test_cp(3,400,False) -------------------------------------------------------------------------------- /ecfactory/cocks_pinch/readme.md: -------------------------------------------------------------------------------- 1 | Cocks-Pinch Method 2 | ================== 3 | 4 | Overview 5 | -------- 6 | 7 | This module provides functionality to construct pairing-friendly elliptic curves via the _Cocks-Pinch (CP) method_; curves constructed via this method have ρ-value approximately 2. The implementation follows the procedure described in [\[FST10\]](/references/Freeman%20Scott%20Teske%202010%20---%20A%20Taxonomy%20of%20Pairing-Friendly%20Elliptic%20Curves.pdf). This module contains three files: 8 | 9 | * `cocks_pinch.py`, which contains the algorithm for the CP method. 10 | 11 | * `cocks_pinch_examples.py`, which contains code examples; 12 | 13 | * `cocks_pinch_tests.py`, which contains unit tests. 14 | 15 | Throughout, 16 | _q_ denotes the prime size of the base field; 17 | _t_ denotes the trace of Frobenius; 18 | _r_ denotes the prime size of the group; 19 | _k_ denotes the embedding degree; 20 | _D_ denotes the (negative) fundamental discriminant. 21 | 22 | Methods 23 | ------- 24 | 25 | Here is an overview of the methods in `cocks_pinch.py`: 26 | 27 | ```python 28 | find_element_of_order(k, r) 29 | ``` 30 | 31 | Generates a random element of order _k_ in **Z**_r_\*. 32 | 33 | ```python 34 | method(r, k, D, max_trials=10000, g=0) 35 | ``` 36 | 37 | Runs the CP method to find a valid pair (_q_,_t_). If a pair is found, the function outputs it, otherwise it outputs (0,0). Above, *max\_trials* is the number of times the algorithm runs the main loop of the CP method, and _g_ is an element of order _k_ in **Z**_r_\*. By default (if _g_ = 0), the method generates _g_ at random, using `find_element_of_order`. 38 | 39 | ```python 40 | run(r, k, D, max_run_time=20) 41 | ``` 42 | 43 | Runs `method` multiple times until a valid pair (_q_,_t_) is found, and then outputs the curve (_q_,_t_,_r_,_k_,_D_). To prevent infinite looping, after running for *max\_run\_time* seconds the function finishes its last call to `method`, and then terminates. 44 | 45 | ```python 46 | gen_params_from_bits(num_bits, k) 47 | ``` 48 | 49 | Generates a _num\_bits_ bit prime _r_ and a fundamental discriminant _D_ to use in the CP method. 50 | 51 | ```python 52 | gen_params_from_r(r, k) 53 | ``` 54 | 55 | Finds a random fundamental discriminant _D_ such that _D_ is a square mod _r_. 56 | 57 | ```python 58 | test_promise(r, k, D) 59 | ``` 60 | 61 | Tests that _r_, _k_, _D_ are valid inputs to the CP method. 62 | 63 | Examples 64 | -------- 65 | 66 | The code examples in `cocks_pinch_examples.py` show how to run the CP method using a predetermined value for _r_, and how to run the CP method by specifying the number of bits for _r_. The example code also shows how to run the CP method only once, using a given element _g_ of order _k_. 67 | 68 | Tests 69 | ----- 70 | The test in `cocks_pinch_tests.py` runs the CP method many times using random input parameters and checks validity of the output. 71 | -------------------------------------------------------------------------------- /ecfactory/complex_multiplication/__init__.py: -------------------------------------------------------------------------------- 1 | from .complex_multiplication import make_curve, small_A_twist, small_B_twist, test_curve -------------------------------------------------------------------------------- /ecfactory/complex_multiplication/complex_multiplication.py: -------------------------------------------------------------------------------- 1 | from sage.all import power_mod, primitive_root, is_square, hilbert_class_polynomial, is_prime,GF, EllipticCurve, kronecker, randint, Integer, Mod 2 | from ecfactory.utils import is_valid_curve 3 | import ecfactory.utils as utils 4 | 5 | def make_curve(q,t,r,k,D,debug=False): 6 | """ 7 | Description: 8 | 9 | Finds the curve equation for the elliptic curve (q,t,r,k,D) using the Complex Multiplication method 10 | 11 | Input: 12 | 13 | q - size of prime field 14 | t - trace of Frobenius 15 | r - size of prime order subgroup 16 | k - embedding degree 17 | D - (negative) fundamental discriminant 18 | 19 | Output: 20 | 21 | E - elliptic curve over F_q with trace t, 22 | a subgroup of order r with embedding degree k, 23 | and fundamental discriminant D 24 | 25 | """ 26 | assert is_valid_curve(q,t,r,k,D), 'Invalid input. No curve exists.' # check inputs 27 | if debug: 28 | print('Tested input') 29 | poly = hilbert_class_polynomial(D) # compute hilbert class polynomial 30 | if debug: 31 | print('Computed Hilbert class polynomial') 32 | check = False 33 | j_inv = poly.any_root(GF(q)) # find j-invariant 34 | orig_curve = EllipticCurve(GF(q), j=j_inv) # make a curve 35 | E = orig_curve 36 | check = test_curve(q,t,r,k,D,E) # see if this is the right curve 37 | twist = False 38 | if not check: # not the right curve, use quadratic twist 39 | E = E.quadratic_twist() 40 | check = test_curve(q,t,r,k,D,E) 41 | if check: 42 | twist = True 43 | else: # twist didnt work => j = 0 or 1728 44 | if j_inv == 0: # for j = 0, use sextic twists 45 | prim = primitive_root(q) 46 | i = 1 47 | while t != E.trace_of_frobenius() and i < 6: 48 | E = orig_curve.sextic_twist(power_mod(prim,i,q)) 49 | i+=1 50 | elif j_inv == 1728: # for j = 1728, use quartic twists 51 | prim = primitive_root(q) 52 | i = 1 53 | while t != E.trace_of_frobenius() and i < 4: 54 | E = orig_curve.quartic_twist(power_mod(prim,i,q)) 55 | i+=1 56 | else: # twist didnt work and j != 0, 1728. this should never happen, so write input to a file for debugging 57 | print('Error. Quadratic twist failed to find the correct curve with j != 0, 1728. Logging output to debug.txt') # this line should never be reached' 58 | f = open('debug.txt', 'w') 59 | f.write('Twist: ' + str(twist) + '\n') 60 | f.write('q: ' + str(q) + '\n') 61 | f.write('t: ' + str(t) + '\n') 62 | f.write('r: ' + str(r) + '\n') 63 | f.write('k: ' + str(k) + '\n') 64 | f.write('D: ' + str(D) + '\n') 65 | f.write('E: ' + str(E) + '\n') 66 | f.write('orig_curve: ' + str(orig_curve)) 67 | f.close() 68 | return False 69 | check = test_curve(q,t,r,k,D,E) 70 | twist = True 71 | if not check: # didnt find a curve. this should never happen, so write input to a file for debugging 72 | print('Error. Failed to find curve. Logging output to debug.txt') 73 | f = open('debug.txt', 'w') 74 | f.write('Twist: ' + str(twist) + '\n') 75 | f.write('q: ' + str(q) + '\n') 76 | f.write('t: ' + str(t) + '\n') 77 | f.write('r: ' + str(r) + '\n') 78 | f.write('k: ' + str(k) + '\n') 79 | f.write('D: ' + str(D) + '\n') 80 | f.write('E: ' + str(E) + '\n') 81 | f.write('orig_curve: ' + str(orig_curve)) 82 | f.close() 83 | return False 84 | return E 85 | 86 | def small_A_twist(E): 87 | """ 88 | Description: 89 | 90 | Finds a curve isogenous to E that has small A in the curve equation y^2 = x^3 + A*x + B 91 | 92 | Input: 93 | 94 | E - elliptic curve 95 | 96 | Output: 97 | 98 | E' - elliptic curve isogenous to E that has small A in the curve equation y^2 = x^3 + A*x + B 99 | 100 | """ 101 | a = E.ainvs()[3] 102 | q = E.base_field().order() 103 | a = power_mod(Integer(a), -1, q) 104 | if kronecker(a,q) == -1: 105 | b = 2 106 | while 1: 107 | b += 1 108 | if kronecker(b, q) == 1: 109 | continue 110 | tmp = a * b % q 111 | d = Mod(tmp, q).sqrt() 112 | if kronecker(d, q) != 1: 113 | continue 114 | break 115 | ainvs = [i for i in E.ainvs()] 116 | ainvs[3]*= d**2 117 | ainvs[4] *= d**3 118 | return EllipticCurve(E.base_field(), ainvs) 119 | 120 | def small_B_twist(E): 121 | """ 122 | Description: 123 | 124 | Finds a curve isogenous to E that has small B in the curve equation y^2 = x^3 + A*x + B 125 | 126 | Input: 127 | 128 | E - elliptic curve 129 | 130 | Output: 131 | 132 | E' - elliptic curve isogenous to E that has small B in the curve equation y^2 = x^3 + A*x + B 133 | 134 | """ 135 | b = E.ainvs()[4] 136 | q = E.base_field().order() 137 | b = power_mod(Integer(b), -1, q) 138 | d = 0 139 | s = Mod(1,q) 140 | bool = True 141 | while bool: 142 | try: 143 | d = (s*b) 144 | d = d.nth_root(3) 145 | d = Integer(d) 146 | bool = False 147 | except ValueError as e: 148 | s+=1 149 | pass 150 | ainvs = [i for i in E.ainvs()] 151 | ainvs[3] *= d**2 152 | ainvs[4] *= d**3 153 | return EllipticCurve(E.base_field(), ainvs) 154 | 155 | def test_curve(q,t,r,k,D,E): 156 | """ 157 | Description: 158 | 159 | Tests that E is an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D 160 | 161 | Input: 162 | 163 | q - size of prime field 164 | t - trace of Frobenius 165 | r - size of prime order subgroup 166 | k - embedding degree 167 | D - (negative) fundamental discriminant 168 | 169 | Output: 170 | 171 | bool - true iff E is an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D 172 | 173 | """ 174 | bool = True 175 | bool = bool and (power_mod(q, k, r) == 1) #q^k -1 ==0 mod r 176 | bool = bool and (E.trace_of_frobenius() == t) 177 | bool = bool and (kronecker((t*t-4*q) * Integer(D).inverse_mod(q),q) == 1) 178 | bool = bool and (E.cardinality() == q+1-t) 179 | bool = bool and (E.cardinality() % r ==0) 180 | return bool 181 | -------------------------------------------------------------------------------- /ecfactory/complex_multiplication/complex_multiplication_examples.py: -------------------------------------------------------------------------------- 1 | from sage.all import EllipticCurve 2 | import ecfactory.complex_multiplication as cm 3 | from ecfactory.utils import print_curve 4 | 5 | # Example 6 | q,t,r,k,D = (9118668363579256702502724196290077470606883146523450654874350215381, 650645402122989554764568571081790, 1188650876978797236509935829939, 11, -84) 7 | E = cm.make_curve(q,t,r,k,D) # takes a few seconds 8 | print(E) 9 | print_curve(q,t,r,k,D) -------------------------------------------------------------------------------- /ecfactory/complex_multiplication/complex_multiplication_tests.py: -------------------------------------------------------------------------------- 1 | from sage.all import randint 2 | import time 3 | import ecfactory.cocks_pinch as cp 4 | import ecfactory.complex_multiplication as cm 5 | from ecfactory.utils import is_valid_curve 6 | 7 | def test_cm(num_tests,num_bits, debug=False): 8 | # runs CM method num_tests times; 9 | # each test uses a random output from the CP method with a num_bits bit prime 10 | print('testing CM...') 11 | fail = 0 12 | for i in range(0, num_tests): 13 | try: 14 | k = randint(5,50) 15 | r,k,D = cp.gen_params_from_bits(num_bits,k) 16 | q,t,r,k,D = cp.run(r,k,D) 17 | E = cm.make_curve(q,t,r,k,D) 18 | assert E 19 | assert cm.test_curve(q,t,r,k,D,E) 20 | except AssertionError as e: 21 | fail += 1 22 | if fail == 0: 23 | print('test passed') 24 | return True 25 | else: 26 | print("failed %.2f" %(100*fail/num_tests) + "% of tests!") 27 | return False 28 | 29 | test_cm(20,50) 30 | 31 | print('testing CM edge cases j=0 and j=1728') 32 | 33 | # test CM method when j = 1728 34 | E = cm.make_curve(17232027701054521159192750959745535948822138513276994230516636357, 129372487574083575172689106885388, 522378919834231359250965924449, 8, -4) 35 | assert cm.test_curve(17232027701054521159192750959745535948822138513276994230516636357, 129372487574083575172689106885388, 522378919834231359250965924449, 8, -4, E), 'failed to find curve when j=1728' 36 | 37 | # test CM method when j = 0 38 | E = cm.make_curve(390834320061394909739901536101003424862215016583546821757802719, 17745279994431356955516821466193, 169356448305103304697688858051, 10, -3) 39 | assert cm.test_curve(390834320061394909739901536101003424862215016583546821757802719, 17745279994431356955516821466193, 169356448305103304697688858051, 10, -3, E), 'failed to find curve when j=0' 40 | print('test passed') -------------------------------------------------------------------------------- /ecfactory/complex_multiplication/readme.md: -------------------------------------------------------------------------------- 1 | Complex Mulitiplication 2 | ======================= 3 | 4 | Overview 5 | -------- 6 | 7 | This module provides functionality to construct elliptic curves via the _Complex Multiplication (CM) method_. The implementation follows the procedure described in [\[W08\]](/references/Washington%202008%20---%20Elliptic%20Curves%20Number%20Theory%20and%20Cryptography.pdf). This module contains three files: 8 | 9 | * `complex_multiplication.py`, which contains the algorithm for the CM method; 10 | 11 | * `complex_multiplication_examples.py`, which contains code examples; 12 | 13 | * `complex_multiplication_tests.py`, which contains unit tests. 14 | 15 | Throughout, 16 | _q_ denotes the prime size of the base field; 17 | _t_ denotes the trace of Frobenius; 18 | _r_ denotes the prime size of the group; 19 | _k_ denotes the embedding degree; 20 | _D_ denotes the (negative) fundamental discriminant. 21 | 22 | Methods 23 | ------- 24 | 25 | Here is an overview of the methods in `complex_multiplication.py`: 26 | 27 | ```python 28 | make_curve(q, t, r, k, D, debug=False) 29 | ``` 30 | 31 | Runs the CM method and returns an elliptic curve _E_(**F**_q_) that has trace _t_, a subgroup of order _r_ with embedding degree _k_, and fundamental discriminant _D_. Setting `debug=True` will output a print statement when the Hilbert class polynomial is computed, since this computation is the bottleneck of the algorithm. 32 | 33 | ```python 34 | small_A_twist(E) 35 | ``` 36 | 37 | Returns a curve E' that is isogenous to E and has small coefficient _A_ in the curve equation _y_2 = _x_3 + _Ax_ + _B_. 38 | 39 | ```python 40 | small_B_twist(E) 41 | ``` 42 | 43 | Returns a curve E' that is isogenous to E and has small coefficient _B_ in the curve equation _y_2 = _x_3 + _Ax_ + _B_. 44 | 45 | ```python 46 | test_curve(q, t, r, k, D, E) 47 | ``` 48 | 49 | Tests that *E*(**F**_q_) has trace _t_, a subgroup of order _r_ with embedding degree _k_, and fundamental discriminant _D_. 50 | 51 | Examples 52 | -------- 53 | 54 | The code examples in `complex_multiplication_examples.py` show how to run the CM method to construct an elliptic curve. 55 | 56 | 57 | Tests 58 | ----- 59 | 60 | The test in `complex_multiplication_.py` runs the CM method many times on random test cases. The test also checks the two edge cases when the _j_-invariant equals 0 and 1728. -------------------------------------------------------------------------------- /ecfactory/dupont_enge_morain/__init__.py: -------------------------------------------------------------------------------- 1 | from .dupont_enge_morain import method, run -------------------------------------------------------------------------------- /ecfactory/dupont_enge_morain/dupont_enge_morain.py: -------------------------------------------------------------------------------- 1 | from sage.all_cmdline import x 2 | from sage.all import random, power_mod, primitive_root, Integer, random_prime, is_prime, kronecker, squarefree_part, is_square, Mod, PolynomialRing, ZZ, fundamental_discriminant, randint, GF,sqrt, round, floor, ceil, euler_phi, log 3 | import time 4 | from ecfactory.utils import is_valid_curve 5 | import ecfactory.utils as utils 6 | 7 | def method(num_bits,k,D,y,max_trials=10000): 8 | """ 9 | Description: 10 | 11 | Runs the Dupont-Enge-Morain method 12 | 13 | Input: 14 | 15 | num_bits - number of bits for the prime order r 16 | k - embedding degree 17 | D - (negative) fundamental discriminant 18 | y - coefficient of D in the CM equation 19 | num_times - number of iterations of the while loop when searching for q 20 | 21 | Output: 22 | 23 | (q,t,r,k,D) - elliptic curve; 24 | returns (0,0,0,k,D) if no r was found, and (0,0,r,k,D) if no q was found 25 | 26 | """ 27 | assert fundamental_discriminant(D) == D, 'Invalid discriminant' 28 | assert k >= 1, 'Invalid embedding degree' 29 | t,r = _method_pt1(num_bits,k,D,y) 30 | if r == 0: 31 | return 0,0,0,k,D 32 | return _method_pt2(t,r,k,D,y,max_trials) 33 | 34 | def _method_pt1(num_bits,k,D,y): 35 | a = Integer(-D*y**2) 36 | R = PolynomialRing(ZZ,'x') 37 | f = R.cyclotomic_polynomial(k)(x-1).polynomial(base_ring = R) 38 | g = (a+(x-2)**2).polynomial(base_ring = R) 39 | r = Integer(f.resultant(g)) 40 | if (Mod(r, k) == 1) and r > 2**(num_bits-1) and utils.is_suitable_r(r): # found a valid r, so use it 41 | F = GF(r) 42 | f = f.change_ring(F) 43 | g = g.change_ring(F) 44 | t = Integer(f.gcd(g).any_root()) 45 | return t,r 46 | else: 47 | return 0,0 48 | 49 | def _method_pt2(t,r,k,D,y, max_trials=10000): 50 | a = Integer(-D*y**2) 51 | j = 0 52 | r2 = r**2 53 | t2 = t**2 54 | m = 2*t*r 55 | q = t2+a 56 | while j < max_trials: # iterate until a prime q is found 57 | # at the beginning of each loop, q = (t+jr)^2 + a 58 | if q % 4 == 0: 59 | q2 = q//4 60 | if utils.is_suitable_q(q2): # found a prime, so output it 61 | return q2,t+j*r,r,k,D 62 | q += m + ((2*j + 1)*r2) 63 | j+=1 64 | return 0,0,r,k,D # found nothing 65 | 66 | @utils.filter_decorator 67 | def run(num_bits,k): 68 | """ 69 | Description: 70 | 71 | Runs the Dupont-Enge-Morain method multiple times until a valid curve is found 72 | 73 | Input: 74 | 75 | num_bits - number of bits 76 | k - an embedding degree 77 | 78 | Output: 79 | 80 | (q,t,r,k,D) - an elliptic curve; 81 | if no curve is found, the algorithm returns (0,0,0,k,0) 82 | 83 | """ 84 | j,r,q,t = 0,0,0,0 85 | num_generates = 512 86 | h = num_bits/(euler_phi(k)) 87 | tried = [(0,0)] # keep track of random values tried for efficiency 88 | for i in range(0,num_generates): 89 | D = 0 90 | y = 0 91 | while (D,y) in tried: # find a pair that we have not tried 92 | D = -randint(1, 1024) # pick a small D so that the CM method is fast 93 | D = fundamental_discriminant(D) 94 | m = 0.5*(h - log(-D).n()/(2*log(2)).n()) 95 | if m < 1: 96 | m = 1 97 | y = randint(floor(2**(m-1)), floor(2**m)) 98 | tried.append((D,y)) 99 | q,t,r,k,D = method(num_bits,k,D,y) # run DEM 100 | if q != 0 and t != 0 and r != 0 and k != 0 and D != 0: # found an answer, so output it 101 | assert is_valid_curve(q,t,r,k,D), 'Invalid output' 102 | return q,t,r,k,D 103 | return 0,0,0,k,0 # found nothing -------------------------------------------------------------------------------- /ecfactory/dupont_enge_morain/dupont_enge_morain_examples.py: -------------------------------------------------------------------------------- 1 | import ecfactory.dupont_enge_morain as dem 2 | from ecfactory.utils import print_curve 3 | 4 | # Example 5 | k = 7 # embedding degree 6 | q,t,r,k,D = dem.run(10,k) # find q,t,r,k,D using DEM method, where r is at least a 10-bit prime and k = 7 7 | print_curve(q,t,r,k,D) -------------------------------------------------------------------------------- /ecfactory/dupont_enge_morain/dupont_enge_morain_tests.py: -------------------------------------------------------------------------------- 1 | from sage.all import randint 2 | import ecfactory.dupont_enge_morain as dem 3 | import time 4 | import ecfactory.utils as utils 5 | 6 | def test_dem(num_tests,num_bits, debug=False): 7 | # runs dupont enge morain method num_tests times; 8 | # each test uses a random embedding degree 9 | test_dem2(num_tests,num_bits,False,debug) 10 | 11 | def test_dem2(num_tests,num_bits,k, debug=False): 12 | # runs dupont enge morain method num_tests times; 13 | # each test uses a fixed embedding degree k 14 | print('testing DEM...') 15 | fail = 0 16 | k2 = k 17 | for i in range(0, num_tests): 18 | if not k2: 19 | k = randint(5,20) 20 | try: 21 | q,t,r,k,D = dem.run(num_bits,k) 22 | assert utils.is_suitable_curve(q,t,r,k,D,num_bits) 23 | except AssertionError as e: 24 | fail += 1 25 | if fail == 0: 26 | print('test passed') 27 | return True 28 | else: 29 | print("failed %.2f" %(100*fail/num_tests) + "% of tests!") 30 | return False 31 | 32 | test_dem(20,100) -------------------------------------------------------------------------------- /ecfactory/dupont_enge_morain/readme.md: -------------------------------------------------------------------------------- 1 | Dupont-Enge-Morain Method 2 | ========================= 3 | 4 | Overview 5 | -------- 6 | 7 | This module provides functionality to construct pairing-friendly elliptic curves via the _Dupont-Enge-Morain (DEM) method_; curves constructed via this method have ρ-value approximately 2. The implementation follows the procedure described in [\[FST10\]](/references/Freeman%20Scott%20Teske%202010%20---%20A%20Taxonomy%20of%20Pairing-Friendly%20Elliptic%20Curves.pdf). This module contains three files: 8 | 9 | * `dupont_enge_morain.py`, which contains the algorithm that implements the DEM method. 10 | 11 | * `dupont_enge_morain_examples.py`, which contains code examples; 12 | 13 | * `dupont_enge_morain_tests.py`, which contains unit tests. 14 | 15 | Throughout, 16 | _q_ denotes the prime size of the base field; 17 | _t_ denotes the trace of Frobenius; 18 | _r_ denotes the prime size of the group; 19 | _k_ denotes the embedding degree; 20 | _D_ denotes the (negative) fundamental discriminant. 21 | 22 | 23 | Methods 24 | ------- 25 | 26 | Here is an overview of the methods in `dupont_enge_morain.py`: 27 | 28 | ```python 29 | method(num_bits, k, D, y, max_trials=10000) 30 | ``` 31 | 32 | Runs the DEM method, and returns a curve (_q_,_t_,_r_,_k_,_D_), where _r_ has at least _num\_bits_ bits. If no curve was found, the method returns (0,0,0,_k_,_D_) if no _r_ was found, and (0,0,_r_,_k_,_D_) if no _q_ was found. In the input, _y_ is the coefficient of _D_ in the CM equation, i.e. *D*_y_2 = _t_2 − 4*q*. The optional parameter *max_trials* sets the maximum number of iterations of the while loop that searches for _q_. 33 | 34 | ```python 35 | run(num_bits, k) 36 | ``` 37 | 38 | Runs `method` multiple times until a valid curve (_q_,_t_,_r_,_k_,_D_) is found. If no curve is found, then the function outputs (0,0,0,_k_,0). 39 | 40 | Examples 41 | -------- 42 | 43 | The code example in `dupont_enge_morain_examples.py` shows how to run the DEM method using a predetermined embedding degree and number of bits for _r_. 44 | 45 | 46 | Tests 47 | ----- 48 | 49 | The test in `dupont_enge_morain.py` runs the DEM method many times using random input parameters and checks validity of the output. 50 | -------------------------------------------------------------------------------- /ecfactory/ec_chain/__init__.py: -------------------------------------------------------------------------------- 1 | from .ec_chain import make_chain, make_chain_from_bn, new_chain, is_chain -------------------------------------------------------------------------------- /ecfactory/ec_chain/ec_chain.py: -------------------------------------------------------------------------------- 1 | import ecfactory.bn_curves as bn 2 | import ecfactory.cocks_pinch as cp 3 | from ecfactory.utils import is_valid_curve 4 | 5 | def make_chain(curve, k_vector): 6 | """ 7 | Description: 8 | 9 | Finds an elliptic curve chain 10 | 11 | Input: 12 | 13 | curve - the first curve (q,t,r,k,D) in the chain 14 | k_vector - list of embedding degrees 15 | 16 | Output: 17 | 18 | curves - elliptic curve chain 19 | 20 | """ 21 | curves = [curve] 22 | r = curve[0] 23 | for i in range(0, len(k_vector)): 24 | k = k_vector[i] 25 | r,k,D = cp.gen_params_from_r(r,k) 26 | curve2 = cp.run(r,k,D) 27 | j = 0 28 | while i < len(k_vector) - 1 and (curve2[0] - 1) % k_vector[i+1] != 0 and j < 100: 29 | curve2 = cp.run(r,k,D) 30 | j+=1 31 | curves.append(curve2) 32 | r = curve2[0] 33 | return curves 34 | 35 | def make_chain_from_bn(num_bits, k_vector, n=1): 36 | """ 37 | Description: 38 | 39 | Finds an elliptic curve chain where the first curve is a BN curve 40 | 41 | Input: 42 | 43 | num_bits - number of bits for BN curve 44 | k_vector - list of embedding degrees 45 | n - positive integer 46 | 47 | Output: 48 | 49 | curves - elliptic curve chain where the first curve is the nth BN curve 50 | 51 | """ 52 | curve = bn.make_curve(num_bits,n)[n-1] 53 | return make_chain(curve, k_vector) 54 | 55 | def new_chain(p0, k_vector): 56 | """ 57 | Description: 58 | 59 | Finds an elliptic curve chain where the first curve has order r 60 | 61 | Input: 62 | 63 | r - prime 64 | k_vector - list of embedding degrees 65 | 66 | Output: 67 | 68 | curves - elliptic curve chain 69 | 70 | """ 71 | curves = make_chain((p0,0,0,0,0), k_vector) 72 | return curves[1:] 73 | 74 | def is_chain(curves): 75 | """ 76 | Description: 77 | 78 | Tests if curves is an elliptic curve chain 79 | 80 | Input: 81 | 82 | curves - a list of elliptic curves (q,t,r,k,D) 83 | 84 | Output: 85 | 86 | bool - true iff curves is an elliptic curve chain 87 | 88 | """ 89 | try: 90 | for c in curves: 91 | assert is_valid_curve(c[0],c[1],c[2],c[3],c[4]) 92 | for i in range(1, len(curves)): 93 | assert curves[i][2] == curves[i-1][0] 94 | except AssertionError as e: 95 | return False 96 | return True -------------------------------------------------------------------------------- /ecfactory/ec_chain/ec_chain_examples.py: -------------------------------------------------------------------------------- 1 | import ecfactory.ec_chain as ec 2 | from ecfactory.utils import curve_to_string 3 | 4 | # Example 1: (using a known starting curve) 5 | curve = (30451590496705691, 43783308, 709451, 5, -71) 6 | k_vector = [5, 11] 7 | curves = ec.make_chain(curve, k_vector) 8 | print('Chain 1:') 9 | for c in curves: 10 | print('\t' + curve_to_string(c[0], c[1], c[2], c[3], c[4])) 11 | 12 | # Example 2: (using a BN curve) 13 | k_vector = [5, 11] 14 | curves = ec.make_chain_from_bn(20, k_vector) 15 | print('Chain 2:') 16 | for c in curves: 17 | print('\t' + curve_to_string(c[0], c[1], c[2], c[3], c[4])) 18 | 19 | # Example 3: (making a chain with no initial curve) 20 | r = 11 21 | k_vector = [5,7,11] 22 | curves = ec.new_chain(r, k_vector) 23 | print('Chain 3:') 24 | for c in curves: 25 | print('\t' + curve_to_string(c[0], c[1], c[2], c[3], c[4])) -------------------------------------------------------------------------------- /ecfactory/ec_chain/ec_chain_tests.py: -------------------------------------------------------------------------------- 1 | from sage.all import randint, random_prime, is_prime 2 | import ecfactory.ec_chain as ec 3 | import time 4 | 5 | def test_ec(num_tests,num_bits, debug=False): 6 | print('testing EC chain...') 7 | func_start = time.time() 8 | fail = 0 9 | for i in range(0, num_tests): 10 | try: 11 | k = randint(5,20) 12 | r = 0 13 | while not (r % k == 1 and is_prime(r)): 14 | r = random_prime(2**(num_bits-1), 2**num_bits) 15 | k_vector = [k] 16 | k_vector.append(randint(5,20)) 17 | k_vector.append(randint(5,20)) 18 | curves = ec.new_chain(r, k_vector) 19 | assert ec.is_chain(curves) 20 | except AssertionError as e: 21 | fail += 1 22 | if fail == 0: 23 | print('test passed') 24 | return True 25 | else: 26 | print("failed %.2f" %(100*fail/num_tests) + "% of tests!") 27 | return False 28 | 29 | 30 | 31 | test_ec(20,30) 32 | 33 | 34 | -------------------------------------------------------------------------------- /ecfactory/ec_chain/readme.md: -------------------------------------------------------------------------------- 1 | Elliptic Curve Chains 2 | ===================== 3 | 4 | Overview 5 | -------- 6 | 7 | This module provides functionality to construct elliptic curve chains using the Cocks-Pinch method. An elliptic curve chain is a sequence of _n_ elliptic curves *E*1, *E*2, ... , *E*n satisfying #*E*i(**F**i) = *p*i-1, for i = 1, 2, ..., n. The module contains three files: 8 | 9 | * `ec_chain.py`, which contains the algorithm to construct elliptic curve chains 10 | 11 | * `ec_chain_examples.py`, which contains code examples; 12 | 13 | * `ec_chain_tests.py`, which contains unit tests. 14 | 15 | Throughout, 16 | _q_ denotes the prime size of the base field; 17 | _t_ denotes the trace of Frobenius; 18 | _r_ denotes the prime size of the group; 19 | _k_ denotes the embedding degree; 20 | _D_ denotes the (negative) fundamental discriminant. 21 | 22 | Methods 23 | ------- 24 | Here is an overview of the methods in `ec_chain.py`: 25 | 26 | ```python 27 | make_chain(curve, k_vector) 28 | ``` 29 | 30 | Outputs an elliptic curve chain where the first curve is _curve_, and the ith constructed curve has embedding degree k\_vector[i]; each curve is represented as a tuple (_q_,_t_,_r_,_k_,_D_). 31 | 32 | ```python 33 | make_chain_from_bn(num_bits, k_vector, n=1) 34 | ``` 35 | 36 | Outputs an elliptic curve chain where the first curve is the nth BN curve with subgroup of order at least 2num\_bits, and the ith constructed curve has embedding degree k\_vector[i]; each curve is represented as a tuple (_q_,_t_,_r_,_k_,_D_). 37 | 38 | ```python 39 | new_chain(p0, k_vector) 40 | ``` 41 | 42 | Outputs an elliptic curve chain where _p_0 = p0, and the ith constructed curve has embedding degree k\_vector[i]; each curve is represented as a tuple (_q_,_t_,_r_,_k_,_D_). 43 | 44 | ```python 45 | is_chain(curves) 46 | ``` 47 | 48 | Checks that *curves* is a valid elliptic curve chain. 49 | 50 | Examples 51 | -------- 52 | 53 | The code examples in `ec_chain_examples.py` shows how to find elliptic curve chains using each of the 3 methods. 54 | 55 | Tests 56 | ----- 57 | 58 | The test in `ec_chain_tests.py` runs the algorithm on random inputs and checks validity of the output. -------------------------------------------------------------------------------- /ecfactory/mnt_curves/__init__.py: -------------------------------------------------------------------------------- 1 | from .mnt_curves import make_curve -------------------------------------------------------------------------------- /ecfactory/mnt_curves/mnt6_enumeration.csv: -------------------------------------------------------------------------------- 1 | q,t,r,k,D 2 | 5,3,3,6,-11 3 | 37,7,31,6,-11 4 | 5,-1,7,6,-19 5 | 17,5,13,6,-43 6 | 8122501,2851,8119651,6,-67 7 | 37,-5,43,6,-123 8 | 4357,-65,4423,6,-163 9 | 197,-13,211,6,-619 10 | 4137157,2035,4135123,6,-723 11 | 257,17,241,6,-739 12 | 12076088289594082667150216839518097,-109891256656724435,12076088289594082777041473496242533,6,-947 13 | 401,-19,421,6,-1243 14 | 1163075971601,-1078459,1163077050061,6,-1723 15 | 577,-23,601,6,-1779 16 | 9834497,3137,9831361,6,-6571 17 | 33143436094813827498252193661317,-5757033619392353,33143436094813833255285813053671,6,-8499 18 | 2917,-53,2971,6,-8859 19 | 12853085414401,3585121,12853081829281,6,-12563 20 | 41617,205,41413,6,-13827 21 | 1865957,1367,1864591,6,-15499 22 | 15729157,3967,15725191,6,-18139 23 | 19411803033183317805747622285717222597,-4405882775696979185,19411803033183317810153505061414201783,6,-19587 24 | 8101,91,8011,6,-24123 25 | 8101,-89,8191,6,-24483 26 | 7397720101,-86009,7397806111,6,-24747 27 | 12101,-109,12211,6,-36523 28 | 14401,121,14281,6,-42963 29 | 147457,385,147073,6,-49067 30 | 377902946955077,-19439725,377902966394803,6,-58027 31 | 101948603922793237631175874757,319293914634767,101948603922792918337261239991,6,-60859 32 | 22501,-149,22651,6,-67803 33 | 24337,157,24181,6,-72699 34 | 17940053136494365908863149405913303297,4235569989563903537,17940053136494365904627579416349399761,6,-93259 35 | 30977,-175,31153,6,-93283 36 | 577467062369951297,-759912535,577467063129863833,6,-105883 37 | 874569730546100019601,-29573125139,874569730575673144741,6,-117667 38 | 39271348901,-198169,39271547071,6,-122923 39 | 42437,-205,42643,6,-127723 40 | 44101,211,43891,6,-131883 41 | 404497,637,403861,6,-134691 42 | 32592178609937,5708957,32592172900981,6,-154939 43 | 484417,-695,485113,6,-161627 44 | 55697,-235,55933,6,-167563 45 | -------------------------------------------------------------------------------- /ecfactory/mnt_curves/mnt_curves.py: -------------------------------------------------------------------------------- 1 | from sage.all import QuadraticField, is_prime, kronecker, fundamental_discriminant, log, sqrt, is_square, power_mod, Integer 2 | import time 3 | from ecfactory.pell_equation_solver import pell_solve 4 | from ecfactory.utils import is_valid_curve 5 | 6 | def make_curve(k,D): 7 | """ 8 | Description: 9 | 10 | Find all MNT curves with embedding degree k and fundamental discriminant D 11 | 12 | Input: 13 | 14 | k - embedding degree 15 | D - (negative) fundamental discriminant 16 | 17 | Output: 18 | 19 | curves - list of the aforementioned elliptic curves; 20 | each curve is represented as a tuple (q,t,r,k,D) 21 | 22 | """ 23 | assert k == 3 or k== 4 or k == 6, 'Invalid embedding degree' 24 | assert fundamental_discriminant(D) == D, 'Invalid discriminant' 25 | if k == 3: 26 | curves = _mnt_subcall(k,D, 24,lambda x: ((x % 24 == 19) and kronecker(6,x) == 1), 6, 3, -3, lambda x: (x -3 )//6, lambda x: (x+3)//6, lambda l: 6*l - 1, lambda l: -6*l - 1, lambda l: 12*l*l - 1) 27 | if k == 4: 28 | curves = _mnt_subcall(k,D,-8, lambda x: ( (x % 8 == 3) and kronecker(-2, x) ==1) or (x == 2) or (x == 8), 3, 2, 1, lambda x: (x-2)//3, lambda x: (x-1)//3, lambda l: -l, lambda l: l+1, lambda l: l*l + l + 1) 29 | if k == 6: 30 | curves = _mnt_subcall(k,D,-8, lambda x: (x % 8 == 3) and kronecker(-2, x) == 1, 6, 5, 1, lambda x: (x+1)//6, lambda x: (x-1)//6, lambda l: 2*l + 1, lambda l: -2*l + 1, lambda l: 4*l*l + 1) 31 | for c in curves: 32 | assert is_valid_curve(c[0],c[1],c[2],c[3],c[4]), 'Invalid output' 33 | assert k == c[3], 'Bug in code' 34 | assert D == c[4], 'Bug in code' 35 | return curves 36 | 37 | def _mnt_subcall(k,D, m, condition, modulus, c1, c2, l1, l2, t1, t2, q0): 38 | D2 = -3*D 39 | D2 = Integer(D2) 40 | assert condition(-D), 'No curve exists' 41 | pell_sols = pell_solve(D2, m) # solve the Pell equation 42 | curves = [] 43 | curves2 = [] 44 | if len(pell_sols[1])== 0: # no solutions found, so abort 45 | return curves 46 | sols = [(Integer(i[0]), Integer(i[1])) for i in pell_sols[1]] 47 | gen = (Integer(pell_sols[0][0]), Integer(pell_sols[0][1])) 48 | q = 0 49 | t = 0 50 | for i in range(0, len(sols)): 51 | if sols[i][0] < 0: 52 | sols[i] = (sols[i][0]*gen[0] + D2*sols[i][1]*gen[1], sols[i][1]*gen[0] + sols[i][0]*gen[1]) 53 | for sol in sols: 54 | check = False 55 | x = sol[0] 56 | l = 0 57 | t = 0 58 | q = 0 59 | if x % modulus == c1: 60 | l = l1(x) 61 | t = t1(l) 62 | check = True 63 | elif x % modulus == c2: 64 | l = l2(x) 65 | t = t2(l) 66 | check = True 67 | if check: 68 | q = q0(l) 69 | if is_prime(q) and is_prime(q+1-t): 70 | if ((q,t) not in curves2): 71 | curves.append((q,t,q+1-t,k,D)) 72 | curves2.append((q,t)) 73 | return curves -------------------------------------------------------------------------------- /ecfactory/mnt_curves/mnt_curves_examples.py: -------------------------------------------------------------------------------- 1 | import ecfactory.mnt_curves as mnt 2 | from ecfactory.utils import print_curve 3 | 4 | # Example (MNT curve with k = 6 and D = -19) 5 | curves = mnt.make_curve(6,-19) 6 | q,t,r,k,D = curves[0] 7 | print_curve(q,t,r,k,D) 8 | 9 | # Example (MNT curve with k = 3 and D = -19) 10 | curves = mnt.make_curve(3, -19) 11 | q,t,r,k,D = curves[0] 12 | print_curve(q,t,r,k,D) 13 | 14 | # Enumerate through all MNT curves with k = 6 and -D < 200000 15 | f = open("mnt6_enumeration.csv", 'w') 16 | f.write('q,t,r,k,D\n') 17 | D = -11 18 | while -D < 200000: 19 | try: 20 | curves = mnt.make_curve(6,D) 21 | if (len(curves) > 0): 22 | for c in curves: 23 | for i in range(0, len(c)): 24 | if i != len(c) - 1: 25 | f.write(str(c[i]) + ',') 26 | else: 27 | f.write(str(c[i]) + '\n') 28 | except AssertionError as e: 29 | pass 30 | D -= 8 31 | f.close() 32 | -------------------------------------------------------------------------------- /ecfactory/mnt_curves/readme.md: -------------------------------------------------------------------------------- 1 | MNT Curves 2 | ========== 3 | 4 | Overview 5 | -------- 6 | 7 | This module provides functionality to construct _Miyaji-Nakabayashi-Takano (MNT) curves_, following the procedure described in [\[KT07\]](/references/Karabina%20Teske%202007%20---%20On%20prime-order%20elliptic%20curves%20with%20embedding%20degrees%20k%20%3D%203%2C4%2C%20and%206.pdf). The module contains two files: 8 | 9 | * `mnt_curves.py`, which contains the algorithm to construct MNT curves; 10 | 11 | * `mnt_curves_examples.py`, which contains code examples. 12 | 13 | Throughout, 14 | _q_ denotes the prime size of the base field; 15 | _t_ denotes the trace of Frobenius; 16 | _r_ denotes the prime size of the group; 17 | _k_ denotes the embedding degree; 18 | _D_ denotes the (negative) fundamental discriminant. 19 | 20 | 21 | Methods 22 | ------- 23 | 24 | The main method in `mnt_curves.py` is 25 | 26 | ```python 27 | make_curve(k, D) 28 | ``` 29 | 30 | It finds all MNT curves with embedding degree _k_ and fundamental discriminant _D_. The method outputs a list of all such curves, with each curve represented as a tuple (_q_,_t_,_r_,_k_,_D_). 31 | 32 | Examples 33 | -------- 34 | 35 | The file `mnt6_enumeration.csv` contains a list of all MNT curves with _k_ = 6 and -_D_ < 200000, ordered by -_D_. The example code in `mnt_curves_examples.py` shows how to generate this file, and how to find an MNT curve with a given embedding degree and fundamental discriminant. -------------------------------------------------------------------------------- /ecfactory/mnt_cycles/__init__.py: -------------------------------------------------------------------------------- 1 | from .mnt_cycles import make_cycle -------------------------------------------------------------------------------- /ecfactory/mnt_cycles/mnt_cycles.py: -------------------------------------------------------------------------------- 1 | import ecfactory.mnt_curves as mnt 2 | 3 | def make_cycle(D): 4 | """ 5 | Description: 6 | 7 | Find all MNT cycles with fundamental discriminant D 8 | 9 | Input: 10 | 11 | D - (negative) fundamental discriminant 12 | 13 | Output: 14 | 15 | cycles - list of the aforementioned cycles; 16 | each cycle is a list containing the curves on the cycle; 17 | each curve is represented as a tuple (q,t,r,k,D) 18 | 19 | """ 20 | curves4 = mnt.make_curve(4,D) 21 | curves6 = mnt.make_curve(6,D) 22 | cycles = [] 23 | for c in curves4: 24 | for c2 in curves6: 25 | if (c[0] == c2[2] and c[2] == c2[0]): 26 | cycles.append([c,c2]) 27 | return cycles -------------------------------------------------------------------------------- /ecfactory/mnt_cycles/mnt_cycles_examples.py: -------------------------------------------------------------------------------- 1 | import ecfactory.mnt_cycles as mnt_cycles 2 | 3 | # Example (find an MNT cycle with D = -19) 4 | cycles = mnt_cycles.make_cycle(-19) 5 | print('Found a cycle: ' + str(cycles[0][0]) + ', ' + str(cycles[0][1])) -------------------------------------------------------------------------------- /ecfactory/mnt_cycles/readme.md: -------------------------------------------------------------------------------- 1 | MNT Cycles 2 | ========== 3 | 4 | Overview 5 | -------- 6 | 7 | This module provides functionality to construct (pairing-friendly) elliptic curve cycles (of length 2) using MNT curves, following the procedure described in [\[KT07\]](/references/Karabina%20Teske%202007%20---%20On%20prime-order%20elliptic%20curves%20with%20embedding%20degrees%20k%20%3D%203%2C4%2C%20and%206.pdf) and [\[BCTV14\]](https://eprint.iacr.org/2014/595). The module contains two files: 8 | 9 | * `mnt_cycles.py`, which contains the algorithm to construct MNT cycles; 10 | 11 | * `mnt_cycles_examples.py`, which contains code examples. 12 | 13 | Throughout, 14 | _q_ denotes the prime size of the base field; 15 | _t_ denotes the trace of Frobenius; 16 | _r_ denotes the prime size of the group; 17 | _k_ denotes the embedding degree; 18 | _D_ denotes the (negative) fundamental discriminant. 19 | 20 | Methods 21 | ------- 22 | 23 | The main method in `mnt_cycles.py` is 24 | 25 | ```python 26 | cycle(D) 27 | ``` 28 | 29 | It finds all MNT cycles with fundamental discriminant _D_. The method outputs a list of cycles, where each cycle is a list of the curves on the cycle; each curve is represented as a tuple (_q_,_t_,_r_,_k_,_D_). 30 | 31 | Examples 32 | -------- 33 | 34 | The example code in `mnt_cycles_examples.py` shows how to find an MNT cycle with a given fundamental discriminant. 35 | -------------------------------------------------------------------------------- /ecfactory/pell_equation_solver/__init__.py: -------------------------------------------------------------------------------- 1 | from .pell_equation_solver import pell_solve -------------------------------------------------------------------------------- /ecfactory/pell_equation_solver/pell_equation_solver.py: -------------------------------------------------------------------------------- 1 | from sage.all import is_square, sqrt, Integer, floor, ceil 2 | 3 | def pell_solve(D, m): 4 | """ 5 | Description: 6 | 7 | Solves the Pell equation x^2 - D*y^2 = m 8 | 9 | Input: 10 | 11 | D - nonsquare integer 12 | m - integer 13 | 14 | Output: 15 | 16 | (x0, y0) - minimal solution to x^2 - D*y^2 = 1 17 | prim_sols - list of primitive solutions for each solution class to x^2 - D*y^2 = m 18 | 19 | """ 20 | assert not is_square(D), 'D cannot be a perfect square' 21 | if m*m >= D: 22 | return _pell_solve_2(D,m) 23 | else: 24 | return _pell_solve_1(D,m) 25 | 26 | 27 | def _pell_solve_1(D,m): # m^2 < D 28 | root_d = Integer(floor(sqrt(D))) 29 | a = Integer(floor(root_d)) 30 | P = Integer(0) 31 | Q = Integer(1) 32 | p = [Integer(1),Integer(a)] 33 | q = [Integer(0),Integer(1)] 34 | i = Integer(1) 35 | x0 = Integer(0) 36 | y0 = Integer(0) 37 | prim_sols = [] 38 | test = Integer(0) 39 | while not (Q == 1 and i%2 == 1) or i == 1: 40 | test = p[i]**2 - D* (q[i]**2) 41 | if test == 1: 42 | x0 = p[i] 43 | y0 = q[i] 44 | divisible = True 45 | try: 46 | test = Integer(m/test) 47 | except TypeError: 48 | divisible = False 49 | if divisible and is_square(test) and test >= 1: 50 | prim_sols.append((test.sqrt()*p[i], test.sqrt()*q[i])) 51 | i+=1 52 | P = a*Q - P 53 | Q = (D-P**2)/Q 54 | a = Integer(floor((P+root_d)/Q)) 55 | p.append(a*p[i-1]+p[i-2]) 56 | q.append(a*q[i-1]+q[i-2]) 57 | return (x0,y0), prim_sols 58 | 59 | 60 | def _pell_solve_2(D,m): # m^2 >= D 61 | prim_sols = [] 62 | t,u = _pell_solve_1(D,1)[0] 63 | if m > 0: 64 | L = Integer(0) 65 | U = Integer(floor(sqrt(m*(t-1)/(2*D)))) 66 | else: 67 | L = Integer(ceil(sqrt(-m/D))) 68 | U = Integer(floor(sqrt(-m*(t+1)/(2*D)))) 69 | for y in range(L,U+1): 70 | y = Integer(y) 71 | x = (m + D*(y**2)) 72 | if is_square(x): 73 | x = Integer(sqrt(x)) 74 | prim_sols.append((x,y)) 75 | if not ((-x*x - y*y*D) % m == 0 and (2*y*x) % m == 0): # (x,y) and (-x,y) are in different solution classes, so add both 76 | prim_sols.append((-x,y)) 77 | return (t,u),prim_sols -------------------------------------------------------------------------------- /ecfactory/pell_equation_solver/pell_equation_solver_examples.py: -------------------------------------------------------------------------------- 1 | from pell_equation_solver import pell_solve 2 | 3 | # Example: finding solutions to x^2 - D*y^2 = m 4 | m = -8 5 | D = 33 6 | sols = pell_solve(D,m) 7 | print('Minimal solution to x^2 - D*y^ = 1 is (' + str(sols[0][0]) + ', ' + str(sols[0][1]) + ')') 8 | print('Printing primitive solutions to x^2 - D*y^2 = m...') 9 | for x,y in sols[1]: 10 | print('\t(' + str(x) + ', ' + str(y) + ')') -------------------------------------------------------------------------------- /ecfactory/pell_equation_solver/pell_equation_solver_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test the Pell Equation Solver 3 | 4 | Contains a set of test vectors for pell equation solver 5 | """ 6 | 7 | from ecfactory.pell_equation_solver import pell_solve 8 | 9 | 10 | def test_pell_equation(d, m): 11 | gen, sols = pell_solve(d, m) 12 | 13 | assert gen[0]**2 - d*gen[1]**2 == 1 14 | for sol in sols: 15 | assert sol[0]**2 - d*sol[1]**2 == m 16 | 17 | 18 | def test_vectors_pell_equation(): 19 | test_pell_equation(34, 4) 20 | test_pell_equation(2, 2) 21 | test_pell_equation(3, 5) 22 | test_pell_equation(5, 234) 23 | test_pell_equation(6, 1253) 24 | test_pell_equation(1325, 2) 25 | test_pell_equation(15251, 34) 26 | 27 | test_pell_equation(34, -4) 28 | test_pell_equation(2, -2) 29 | test_pell_equation(3, -5) 30 | test_pell_equation(5, -234) 31 | test_pell_equation(6, -1253) 32 | test_pell_equation(1325, -2) 33 | test_pell_equation(15251, -34) 34 | 35 | test_pell_equation(63*103, -180) 36 | test_pell_equation(63 * 103, -80) 37 | 38 | 39 | if __name__ == '__main__': 40 | print("Running test vectors") 41 | test_vectors_pell_equation() 42 | print("Tests finished") 43 | -------------------------------------------------------------------------------- /ecfactory/pell_equation_solver/readme.md: -------------------------------------------------------------------------------- 1 | Pell Equation Solver 2 | =================== 3 | 4 | Overview 5 | -------- 6 | 7 | This module implements an algorithm to solve generalized Pell equations, following the procedure described in [\[KT07\]](/references/Karabina%20Teske%202007%20---%20On%20prime-order%20elliptic%20curves%20with%20embedding%20degrees%20k%20%3D%203%2C4%2C%20and%206.pdf). This module contains two files: 8 | 9 | * `pell_equation_solver.py`, which contains the algorithm to solve Pell equations; 10 | 11 | * `pell_equation_solver_examples.py`, which contains code examples. 12 | 13 | Methods 14 | ------- 15 | 16 | The main method in `pell_equation_solver.py` is 17 | 18 | ```python 19 | pell_solve(D, m) 20 | ``` 21 | 22 | It solves the generalized Pell equation _x_2 - *Dy*2 = _m_. The algorithm outputs a list where: (a) the first element is the minimal solution (_x_0, _y_0) to _x_2 − *Dy*2 = 1; (2) the second element is a list containing a primitive solution to _x_2 − _Dy_2 = _m_ for each solution class. 23 | 24 | Examples 25 | -------- 26 | 27 | The example code in `pell_equation_solver_examples.py` shows how to run the code to solve generalized Pell equations. -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k10.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0183 3 | 75, 0.0649 4 | 100, 0.5258 5 | 110, 0.1968 6 | 125, 0.1292 7 | 150, 0.2303 8 | 175, 0.5919 9 | 200, 0.5579 10 | 250, 1.6185 11 | 300, 2.8322 12 | 350, 7.7248 13 | 400, 6.1373 14 | 450, 13.8992 15 | 500, 14.5270 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k11.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0143 3 | 75, 0.0634 4 | 100, 0.2400 5 | 110, 0.1906 6 | 125, 0.1451 7 | 150, 0.2403 8 | 175, 0.8989 9 | 200, 0.5363 10 | 250, 1.5983 11 | 300, 2.7577 12 | 350, 7.2658 13 | 400, 6.9564 14 | 450, 13.8457 15 | 500, 15.6244 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k12.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0168 3 | 75, 0.0611 4 | 100, 0.4544 5 | 110, 0.1462 6 | 125, 0.1261 7 | 150, 0.2405 8 | 175, 0.5472 9 | 200, 0.6384 10 | 250, 1.6444 11 | 300, 2.6549 12 | 350, 7.7787 13 | 400, 6.2357 14 | 450, 14.6129 15 | 500, 14.1519 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k13.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0182 3 | 75, 0.0412 4 | 100, 0.2908 5 | 110, 0.2063 6 | 125, 0.1649 7 | 150, 0.2229 8 | 175, 0.5655 9 | 200, 0.6049 10 | 250, 1.6825 11 | 300, 2.8239 12 | 350, 7.0253 13 | 400, 6.4332 14 | 450, 13.4940 15 | 500, 14.4716 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k14.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0172 3 | 75, 0.0568 4 | 100, 0.2895 5 | 110, 0.2283 6 | 125, 0.1339 7 | 150, 0.2450 8 | 175, 0.5465 9 | 200, 0.6251 10 | 250, 1.4922 11 | 300, 2.8659 12 | 350, 6.9264 13 | 400, 6.8136 14 | 450, 11.8824 15 | 500, 15.3142 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k15.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0164 3 | 75, 0.0594 4 | 100, 0.2915 5 | 110, 0.1863 6 | 125, 0.1362 7 | 150, 0.2453 8 | 175, 0.4838 9 | 200, 0.6005 10 | 250, 1.5330 11 | 300, 2.9436 12 | 350, 7.9105 13 | 400, 6.5515 14 | 450, 13.6899 15 | 500, 12.9738 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k16.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0161 3 | 75, 0.0450 4 | 100, 0.5058 5 | 110, 0.1717 6 | 125, 0.1301 7 | 150, 0.2420 8 | 175, 0.5812 9 | 200, 0.5947 10 | 250, 1.5595 11 | 300, 2.6083 12 | 350, 7.4855 13 | 400, 6.9182 14 | 450, 13.6138 15 | 500, 15.4257 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k17.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0163 3 | 75, 0.0597 4 | 100, 0.0787 5 | 110, 0.4211 6 | 125, 0.1315 7 | 150, 0.2482 8 | 175, 0.5937 9 | 200, 0.6382 10 | 250, 1.6426 11 | 300, 2.8743 12 | 350, 7.7661 13 | 400, 6.8475 14 | 450, 14.1084 15 | 500, 15.5266 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k18.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0179 3 | 75, 0.0616 4 | 100, 0.1061 5 | 110, 0.1825 6 | 125, 0.1241 7 | 150, 0.2736 8 | 175, 0.5073 9 | 200, 0.5151 10 | 250, 1.6654 11 | 300, 2.7342 12 | 350, 7.5133 13 | 400, 7.0088 14 | 450, 13.6967 15 | 500, 14.5821 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k19.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0147 3 | 75, 0.0722 4 | 100, 0.1067 5 | 110, 0.2278 6 | 125, 0.1312 7 | 150, 0.2669 8 | 175, 0.5778 9 | 200, 0.5278 10 | 250, 1.4024 11 | 300, 2.8728 12 | 350, 8.1350 13 | 400, 7.0097 14 | 450, 12.7148 15 | 500, 14.9805 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k5.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0166 3 | 75, 0.0641 4 | 100, 0.3217 5 | 110, 0.1399 6 | 125, 0.1329 7 | 150, 0.2535 8 | 175, 0.5437 9 | 200, 0.5839 10 | 250, 1.6123 11 | 300, 2.9331 12 | 350, 7.4601 13 | 400, 6.1367 14 | 450, 13.9865 15 | 500, 14.4172 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k52.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0170 3 | 75, 0.0709 4 | 100, 0.1546 5 | 110, 0.2635 6 | 125, 0.1718 7 | 150, 0.3531 8 | 175, 0.7979 9 | 200, 0.8527 10 | 250, 2.0826 11 | 300, 3.4050 12 | 350, 8.3247 13 | 400, 6.9064 14 | 450, 14.7344 15 | 500, 44.5963 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k6.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0159 3 | 75, 0.0699 4 | 100, 0.3403 5 | 110, 0.1808 6 | 125, 0.2978 7 | 150, 0.2659 8 | 175, 0.5411 9 | 200, 0.5636 10 | 250, 1.5995 11 | 300, 2.8896 12 | 350, 6.8259 13 | 400, 6.3716 14 | 450, 13.5945 15 | 500, 14.7129 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k7.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0157 3 | 75, 0.0454 4 | 100, 0.4940 5 | 110, 0.1839 6 | 125, 0.1409 7 | 150, 0.2214 8 | 175, 0.5293 9 | 200, 0.6286 10 | 250, 1.5090 11 | 300, 2.7879 12 | 350, 7.8398 13 | 400, 6.4712 14 | 450, 12.8557 15 | 500, 14.9717 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k8.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0170 3 | 75, 0.0704 4 | 100, 0.1277 5 | 110, 0.1727 6 | 125, 0.1357 7 | 150, 0.2521 8 | 175, 0.5238 9 | 200, 0.5661 10 | 250, 1.5188 11 | 300, 2.7794 12 | 350, 7.4601 13 | 400, 6.3239 14 | 450, 14.1512 15 | 500, 14.4590 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/cp/k9.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0159 3 | 75, 0.0365 4 | 100, 0.2760 5 | 110, 0.1763 6 | 125, 0.1424 7 | 150, 0.2390 8 | 175, 0.5524 9 | 200, 0.6472 10 | 250, 1.5178 11 | 300, 2.9129 12 | 350, 7.3960 13 | 400, 6.6650 14 | 450, 14.4211 15 | 500, 14.2729 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k10.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0694 3 | 75, 0.3313 4 | 100, 0.3828 5 | 110, 0.5521 6 | 125, 0.3103 7 | 150, 0.3747 8 | 175, 0.7179 9 | 200, 1.7082 10 | 250, 2.2827 11 | 300, 3.3546 12 | 350, 8.5561 13 | 400, 7.9767 14 | 450, 15.6251 15 | 500, 19.0718 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k11.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.1909 3 | 75, 0.6310 4 | 100, 0.3344 5 | 110, 0.4048 6 | 125, 0.4220 7 | 150, 0.7411 8 | 175, 2.0329 9 | 200, 2.0998 10 | 250, 3.1123 11 | 300, 7.2950 12 | 350, 8.4013 13 | 400, 12.5121 14 | 450, 15.0705 15 | 500, 19.5522 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k12.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0525 3 | 75, 0.1313 4 | 100, 0.1903 5 | 110, 0.2295 6 | 125, 0.2792 7 | 150, 0.4383 8 | 175, 0.8075 9 | 200, 1.6656 10 | 250, 2.0037 11 | 300, 3.3698 12 | 350, 7.6945 13 | 400, 7.6738 14 | 450, 14.6697 15 | 500, 18.8566 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k13.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.4012 3 | 75, 0.3428 4 | 100, 0.3939 5 | 110, 0.3388 6 | 125, 0.4160 7 | 150, 2.1679 8 | 175, 2.3490 9 | 200, 2.3602 10 | 250, 3.0835 11 | 300, 6.5941 12 | 350, 7.9036 13 | 400, 12.7438 14 | 450, 15.9744 15 | 500, 23.3289 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k14.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0771 3 | 75, 0.1255 4 | 100, 0.1751 5 | 110, 0.2579 6 | 125, 0.2743 7 | 150, 1.0080 8 | 175, 1.2175 9 | 200, 1.2828 10 | 250, 2.5857 11 | 300, 6.4143 12 | 350, 7.7743 13 | 400, 15.5462 14 | 450, 15.0013 15 | 500, 19.6697 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k15.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.3227 3 | 75, 0.1372 4 | 100, 0.2014 5 | 110, 0.2653 6 | 125, 0.7867 7 | 150, 0.6608 8 | 175, 1.3221 9 | 200, 1.4373 10 | 250, 2.7168 11 | 300, 5.8438 12 | 350, 8.0428 13 | 400, 12.4174 14 | 450, 13.1288 15 | 500, 21.0848 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k16.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.1311 3 | 75, 0.6725 4 | 100, 0.4648 5 | 110, 0.5574 6 | 125, 0.9971 7 | 150, 1.3924 8 | 175, 1.9343 9 | 200, 2.5913 10 | 250, 3.3183 11 | 300, 6.6669 12 | 350, 10.5154 13 | 400, 16.3312 14 | 450, 17.3413 15 | 500, 24.6339 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k17.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.5294 3 | 75, 0.5693 4 | 100, 0.4969 5 | 110, 0.7634 6 | 125, 0.8651 7 | 150, 1.3122 8 | 175, 2.0652 9 | 200, 2.7095 10 | 250, 3.3601 11 | 300, 9.2599 12 | 350, 10.4096 13 | 400, 12.2220 14 | 450, 16.9199 15 | 500, 29.1297 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k18.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0842 3 | 75, 0.1470 4 | 100, 0.6100 5 | 110, 0.2408 6 | 125, 0.3378 7 | 150, 0.6499 8 | 175, 0.9682 9 | 200, 1.2563 10 | 250, 2.5547 11 | 300, 5.3318 12 | 350, 7.8346 13 | 400, 11.7306 14 | 450, 13.8722 15 | 500, 17.7465 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k19.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.7987 3 | 75, 1.0841 4 | 100, 0.9966 5 | 110, 1.0734 6 | 125, 1.5389 7 | 150, 1.9640 8 | 175, 2.1850 9 | 200, 2.3662 10 | 250, 5.0262 11 | 300, 7.3104 12 | 350, 11.3447 13 | 400, 15.2450 14 | 450, 19.3123 15 | 500, 29.7471 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k5.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.1188 3 | 75, 0.4180 4 | 100, 0.2825 5 | 110, 0.2634 6 | 125, 0.3781 7 | 150, 0.9322 8 | 175, 0.8070 9 | 200, 2.1682 10 | 250, 2.6960 11 | 300, 3.7570 12 | 350, 8.6688 13 | 400, 9.2824 14 | 450, 14.4985 15 | 500, 19.3567 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k52.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.4281 3 | 75, 0.2274 4 | 100, 0.1455 5 | 110, 0.1493 6 | 125, 0.2303 7 | 150, 0.2973 8 | 175, 0.6106 9 | 200, 1.1269 10 | 250, 1.1216 11 | 300, 1.8803 12 | 350, 3.6806 13 | 400, 3.5502 14 | 450, 7.1119 15 | 500, 20.5438 -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k6.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0474 3 | 75, 0.1214 4 | 100, 0.1845 5 | 110, 0.3491 6 | 125, 0.2064 7 | 150, 0.2875 8 | 175, 0.7168 9 | 200, 2.1541 10 | 250, 1.9894 11 | 300, 2.9416 12 | 350, 7.3615 13 | 400, 7.2999 14 | 450, 14.4193 15 | 500, 15.0391 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k7.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0711 3 | 75, 0.3279 4 | 100, 0.2016 5 | 110, 0.2810 6 | 125, 0.2703 7 | 150, 0.5122 8 | 175, 0.7247 9 | 200, 1.6987 10 | 250, 2.5304 11 | 300, 7.3655 12 | 350, 8.4451 13 | 400, 13.7514 14 | 450, 15.2027 15 | 500, 20.3956 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k8.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.2719 3 | 75, 0.4227 4 | 100, 0.7540 5 | 110, 0.6339 6 | 125, 0.6249 7 | 150, 1.5846 8 | 175, 1.8695 9 | 200, 2.5250 10 | 250, 3.0818 11 | 300, 4.6017 12 | 350, 10.6314 13 | 400, 9.7956 14 | 450, 18.2435 15 | 500, 20.3839 16 | -------------------------------------------------------------------------------- /ecfactory/profile/logs/dem/k9.csv: -------------------------------------------------------------------------------- 1 | Number of bits, Time in seconds 2 | 50, 0.0963 3 | 75, 0.7565 4 | 100, 0.2018 5 | 110, 0.3568 6 | 125, 0.3432 7 | 150, 0.9834 8 | 175, 1.0521 9 | 200, 2.0845 10 | 250, 2.9340 11 | 300, 5.5336 12 | 350, 8.8620 13 | 400, 9.8896 14 | 450, 14.7493 15 | 500, 19.3617 16 | -------------------------------------------------------------------------------- /ecfactory/profile/plot_cp.gp: -------------------------------------------------------------------------------- 1 | set terminal svg 2 | f = "cp" 3 | set output 'plots/'.f.'/'.f.'.svg' 4 | set xlabel "Number of bits in r" 5 | set ylabel "Time in seconds" 6 | kmax = 19 7 | kmin = 5 8 | color(k) = (k-kmin)*16777215/(1.5*(kmax-kmin)) 9 | set title "" 10 | set key font ",10" 11 | set label font ",14" 12 | set xlabel font ",14" 13 | set ylabel font ",14" 14 | plot for [i=kmin:kmax] 'logs/'.f.'/k'.i.'.csv' every ::1 with lines lw 2 lt rgb color(i) title "k=".i 15 | -------------------------------------------------------------------------------- /ecfactory/profile/plot_cp_vs_dem.gp: -------------------------------------------------------------------------------- 1 | kmin=5 2 | kmax=19 3 | do for [k=kmin:kmax] { 4 | set terminal svg 5 | set output 'plots/cp_vs_dem/k'.k.'.svg' 6 | set xlabel "Number of bits in r" 7 | set ylabel "Time in seconds" 8 | set key font ",14" 9 | set label font ",14" 10 | set xlabel font ",14" 11 | set ylabel font ",14" 12 | set label "k=".k at screen 0.54,0.92 center front font ",14" 13 | plot 'logs/dem/k'.k.'.csv' every ::1 with lines lw 2 lt rgb "blue" title "dem:", 'logs/cp/k'.k.'.csv' every ::1 with lines lw 2 lt rgb "red" title "cp:" 14 | unset label 15 | unset xlabel 16 | unset ylabel 17 | unset output 18 | unset terminal 19 | unset key 20 | } 21 | -------------------------------------------------------------------------------- /ecfactory/profile/plot_dem.gp: -------------------------------------------------------------------------------- 1 | set terminal svg 2 | f = "dem" 3 | set output 'plots/'.f.'/'.f.'.svg' 4 | set xlabel "Number of bits in r" 5 | set ylabel "Time in seconds" 6 | kmax = 19 7 | kmin = 5 8 | color(k) = (k-kmin)*16777215/(1.5*(kmax-kmin)) 9 | set title "" 10 | set key font ",10" 11 | set label font ",14" 12 | set xlabel font ",14" 13 | set ylabel font ",14" 14 | plot for [i=kmin:kmax] 'logs/'.f.'/k'.i.'.csv' every ::1 with lines lw 2 lt rgb color(i) title "k=".i 15 | -------------------------------------------------------------------------------- /ecfactory/profile/plots/cp_vs_dem/k10.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | Gnuplot 12 | Produced by GNUPLOT 5.0 patchlevel 3 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 0 49 | 50 | 51 | 52 | 53 | 2 54 | 55 | 56 | 57 | 58 | 4 59 | 60 | 61 | 62 | 63 | 6 64 | 65 | 66 | 67 | 68 | 8 69 | 70 | 71 | 72 | 73 | 10 74 | 75 | 76 | 77 | 78 | 12 79 | 80 | 81 | 82 | 83 | 14 84 | 85 | 86 | 87 | 88 | 16 89 | 90 | 91 | 92 | 93 | 18 94 | 95 | 96 | 97 | 98 | 20 99 | 100 | 101 | 102 | 103 | 50 104 | 105 | 106 | 107 | 108 | 100 109 | 110 | 111 | 112 | 113 | 150 114 | 115 | 116 | 117 | 118 | 200 119 | 120 | 121 | 122 | 123 | 250 124 | 125 | 126 | 127 | 128 | 300 129 | 130 | 131 | 132 | 133 | 350 134 | 135 | 136 | 137 | 138 | 400 139 | 140 | 141 | 142 | 143 | 450 144 | 145 | 146 | 147 | 148 | 500 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | Time in seconds 158 | 159 | 160 | 161 | 162 | Number of bits in r 163 | 164 | 165 | 166 | 167 | dem: 168 | 169 | 170 | 171 | 172 | dem: 173 | 174 | 175 | 176 | 179 | 180 | cp: 181 | 182 | 183 | cp: 184 | 185 | 186 | 187 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | k=10 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | -------------------------------------------------------------------------------- /ecfactory/profile/plots/cp_vs_dem/k13.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | Gnuplot 12 | Produced by GNUPLOT 5.0 patchlevel 3 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 0 49 | 50 | 51 | 52 | 53 | 5 54 | 55 | 56 | 57 | 58 | 10 59 | 60 | 61 | 62 | 63 | 15 64 | 65 | 66 | 67 | 68 | 20 69 | 70 | 71 | 72 | 73 | 25 74 | 75 | 76 | 77 | 78 | 50 79 | 80 | 81 | 82 | 83 | 100 84 | 85 | 86 | 87 | 88 | 150 89 | 90 | 91 | 92 | 93 | 200 94 | 95 | 96 | 97 | 98 | 250 99 | 100 | 101 | 102 | 103 | 300 104 | 105 | 106 | 107 | 108 | 350 109 | 110 | 111 | 112 | 113 | 400 114 | 115 | 116 | 117 | 118 | 450 119 | 120 | 121 | 122 | 123 | 500 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | Time in seconds 133 | 134 | 135 | 136 | 137 | Number of bits in r 138 | 139 | 140 | 141 | 142 | dem: 143 | 144 | 145 | 146 | 147 | dem: 148 | 149 | 150 | 151 | 154 | 155 | cp: 156 | 157 | 158 | cp: 159 | 160 | 161 | 162 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | k=13 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /ecfactory/profile/plots/cp_vs_dem/k15.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | Gnuplot 12 | Produced by GNUPLOT 5.0 patchlevel 3 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 0 49 | 50 | 51 | 52 | 53 | 5 54 | 55 | 56 | 57 | 58 | 10 59 | 60 | 61 | 62 | 63 | 15 64 | 65 | 66 | 67 | 68 | 20 69 | 70 | 71 | 72 | 73 | 25 74 | 75 | 76 | 77 | 78 | 50 79 | 80 | 81 | 82 | 83 | 100 84 | 85 | 86 | 87 | 88 | 150 89 | 90 | 91 | 92 | 93 | 200 94 | 95 | 96 | 97 | 98 | 250 99 | 100 | 101 | 102 | 103 | 300 104 | 105 | 106 | 107 | 108 | 350 109 | 110 | 111 | 112 | 113 | 400 114 | 115 | 116 | 117 | 118 | 450 119 | 120 | 121 | 122 | 123 | 500 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | Time in seconds 133 | 134 | 135 | 136 | 137 | Number of bits in r 138 | 139 | 140 | 141 | 142 | dem: 143 | 144 | 145 | 146 | 147 | dem: 148 | 149 | 150 | 151 | 154 | 155 | cp: 156 | 157 | 158 | cp: 159 | 160 | 161 | 162 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | k=15 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /ecfactory/profile/plots/cp_vs_dem/k16.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | Gnuplot 12 | Produced by GNUPLOT 5.0 patchlevel 3 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 0 49 | 50 | 51 | 52 | 53 | 5 54 | 55 | 56 | 57 | 58 | 10 59 | 60 | 61 | 62 | 63 | 15 64 | 65 | 66 | 67 | 68 | 20 69 | 70 | 71 | 72 | 73 | 25 74 | 75 | 76 | 77 | 78 | 50 79 | 80 | 81 | 82 | 83 | 100 84 | 85 | 86 | 87 | 88 | 150 89 | 90 | 91 | 92 | 93 | 200 94 | 95 | 96 | 97 | 98 | 250 99 | 100 | 101 | 102 | 103 | 300 104 | 105 | 106 | 107 | 108 | 350 109 | 110 | 111 | 112 | 113 | 400 114 | 115 | 116 | 117 | 118 | 450 119 | 120 | 121 | 122 | 123 | 500 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | Time in seconds 133 | 134 | 135 | 136 | 137 | Number of bits in r 138 | 139 | 140 | 141 | 142 | dem: 143 | 144 | 145 | 146 | 147 | dem: 148 | 149 | 150 | 151 | 154 | 155 | cp: 156 | 157 | 158 | cp: 159 | 160 | 161 | 162 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | k=16 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /ecfactory/profile/plots/cp_vs_dem/k17.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | Gnuplot 12 | Produced by GNUPLOT 5.0 patchlevel 3 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 0 49 | 50 | 51 | 52 | 53 | 5 54 | 55 | 56 | 57 | 58 | 10 59 | 60 | 61 | 62 | 63 | 15 64 | 65 | 66 | 67 | 68 | 20 69 | 70 | 71 | 72 | 73 | 25 74 | 75 | 76 | 77 | 78 | 30 79 | 80 | 81 | 82 | 83 | 50 84 | 85 | 86 | 87 | 88 | 100 89 | 90 | 91 | 92 | 93 | 150 94 | 95 | 96 | 97 | 98 | 200 99 | 100 | 101 | 102 | 103 | 250 104 | 105 | 106 | 107 | 108 | 300 109 | 110 | 111 | 112 | 113 | 350 114 | 115 | 116 | 117 | 118 | 400 119 | 120 | 121 | 122 | 123 | 450 124 | 125 | 126 | 127 | 128 | 500 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | Time in seconds 138 | 139 | 140 | 141 | 142 | Number of bits in r 143 | 144 | 145 | 146 | 147 | dem: 148 | 149 | 150 | 151 | 152 | dem: 153 | 154 | 155 | 156 | 159 | 160 | cp: 161 | 162 | 163 | cp: 164 | 165 | 166 | 167 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | k=17 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /ecfactory/profile/plots/cp_vs_dem/k18.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | Gnuplot 12 | Produced by GNUPLOT 5.0 patchlevel 3 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 0 49 | 50 | 51 | 52 | 53 | 2 54 | 55 | 56 | 57 | 58 | 4 59 | 60 | 61 | 62 | 63 | 6 64 | 65 | 66 | 67 | 68 | 8 69 | 70 | 71 | 72 | 73 | 10 74 | 75 | 76 | 77 | 78 | 12 79 | 80 | 81 | 82 | 83 | 14 84 | 85 | 86 | 87 | 88 | 16 89 | 90 | 91 | 92 | 93 | 18 94 | 95 | 96 | 97 | 98 | 50 99 | 100 | 101 | 102 | 103 | 100 104 | 105 | 106 | 107 | 108 | 150 109 | 110 | 111 | 112 | 113 | 200 114 | 115 | 116 | 117 | 118 | 250 119 | 120 | 121 | 122 | 123 | 300 124 | 125 | 126 | 127 | 128 | 350 129 | 130 | 131 | 132 | 133 | 400 134 | 135 | 136 | 137 | 138 | 450 139 | 140 | 141 | 142 | 143 | 500 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | Time in seconds 153 | 154 | 155 | 156 | 157 | Number of bits in r 158 | 159 | 160 | 161 | 162 | dem: 163 | 164 | 165 | 166 | 167 | dem: 168 | 169 | 170 | 171 | 174 | 175 | cp: 176 | 177 | 178 | cp: 179 | 180 | 181 | 182 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | k=18 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /ecfactory/profile/plots/cp_vs_dem/k19.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | Gnuplot 12 | Produced by GNUPLOT 5.0 patchlevel 3 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 0 49 | 50 | 51 | 52 | 53 | 5 54 | 55 | 56 | 57 | 58 | 10 59 | 60 | 61 | 62 | 63 | 15 64 | 65 | 66 | 67 | 68 | 20 69 | 70 | 71 | 72 | 73 | 25 74 | 75 | 76 | 77 | 78 | 30 79 | 80 | 81 | 82 | 83 | 50 84 | 85 | 86 | 87 | 88 | 100 89 | 90 | 91 | 92 | 93 | 150 94 | 95 | 96 | 97 | 98 | 200 99 | 100 | 101 | 102 | 103 | 250 104 | 105 | 106 | 107 | 108 | 300 109 | 110 | 111 | 112 | 113 | 350 114 | 115 | 116 | 117 | 118 | 400 119 | 120 | 121 | 122 | 123 | 450 124 | 125 | 126 | 127 | 128 | 500 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | Time in seconds 138 | 139 | 140 | 141 | 142 | Number of bits in r 143 | 144 | 145 | 146 | 147 | dem: 148 | 149 | 150 | 151 | 152 | dem: 153 | 154 | 155 | 156 | 159 | 160 | cp: 161 | 162 | 163 | cp: 164 | 165 | 166 | 167 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | k=19 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /ecfactory/profile/plots/cp_vs_dem/k6.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | Gnuplot 12 | Produced by GNUPLOT 5.0 patchlevel 3 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 0 49 | 50 | 51 | 52 | 53 | 2 54 | 55 | 56 | 57 | 58 | 4 59 | 60 | 61 | 62 | 63 | 6 64 | 65 | 66 | 67 | 68 | 8 69 | 70 | 71 | 72 | 73 | 10 74 | 75 | 76 | 77 | 78 | 12 79 | 80 | 81 | 82 | 83 | 14 84 | 85 | 86 | 87 | 88 | 16 89 | 90 | 91 | 92 | 93 | 50 94 | 95 | 96 | 97 | 98 | 100 99 | 100 | 101 | 102 | 103 | 150 104 | 105 | 106 | 107 | 108 | 200 109 | 110 | 111 | 112 | 113 | 250 114 | 115 | 116 | 117 | 118 | 300 119 | 120 | 121 | 122 | 123 | 350 124 | 125 | 126 | 127 | 128 | 400 129 | 130 | 131 | 132 | 133 | 450 134 | 135 | 136 | 137 | 138 | 500 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | Time in seconds 148 | 149 | 150 | 151 | 152 | Number of bits in r 153 | 154 | 155 | 156 | 157 | dem: 158 | 159 | 160 | 161 | 162 | dem: 163 | 164 | 165 | 166 | 169 | 170 | cp: 171 | 172 | 173 | cp: 174 | 175 | 176 | 177 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | k=6 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /ecfactory/profile/plots/cp_vs_dem/k7.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | Gnuplot 12 | Produced by GNUPLOT 5.0 patchlevel 3 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 0 49 | 50 | 51 | 52 | 53 | 5 54 | 55 | 56 | 57 | 58 | 10 59 | 60 | 61 | 62 | 63 | 15 64 | 65 | 66 | 67 | 68 | 20 69 | 70 | 71 | 72 | 73 | 25 74 | 75 | 76 | 77 | 78 | 50 79 | 80 | 81 | 82 | 83 | 100 84 | 85 | 86 | 87 | 88 | 150 89 | 90 | 91 | 92 | 93 | 200 94 | 95 | 96 | 97 | 98 | 250 99 | 100 | 101 | 102 | 103 | 300 104 | 105 | 106 | 107 | 108 | 350 109 | 110 | 111 | 112 | 113 | 400 114 | 115 | 116 | 117 | 118 | 450 119 | 120 | 121 | 122 | 123 | 500 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | Time in seconds 133 | 134 | 135 | 136 | 137 | Number of bits in r 138 | 139 | 140 | 141 | 142 | dem: 143 | 144 | 145 | 146 | 147 | dem: 148 | 149 | 150 | 151 | 154 | 155 | cp: 156 | 157 | 158 | cp: 159 | 160 | 161 | 162 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | k=7 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /ecfactory/profile/plots/cp_vs_dem/k8.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | Gnuplot 12 | Produced by GNUPLOT 5.0 patchlevel 3 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 0 49 | 50 | 51 | 52 | 53 | 5 54 | 55 | 56 | 57 | 58 | 10 59 | 60 | 61 | 62 | 63 | 15 64 | 65 | 66 | 67 | 68 | 20 69 | 70 | 71 | 72 | 73 | 25 74 | 75 | 76 | 77 | 78 | 50 79 | 80 | 81 | 82 | 83 | 100 84 | 85 | 86 | 87 | 88 | 150 89 | 90 | 91 | 92 | 93 | 200 94 | 95 | 96 | 97 | 98 | 250 99 | 100 | 101 | 102 | 103 | 300 104 | 105 | 106 | 107 | 108 | 350 109 | 110 | 111 | 112 | 113 | 400 114 | 115 | 116 | 117 | 118 | 450 119 | 120 | 121 | 122 | 123 | 500 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | Time in seconds 133 | 134 | 135 | 136 | 137 | Number of bits in r 138 | 139 | 140 | 141 | 142 | dem: 143 | 144 | 145 | 146 | 147 | dem: 148 | 149 | 150 | 151 | 154 | 155 | cp: 156 | 157 | 158 | cp: 159 | 160 | 161 | 162 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | k=8 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /ecfactory/profile/profile.py: -------------------------------------------------------------------------------- 1 | import ecfactory.cocks_pinch as cp 2 | import ecfactory.dupont_enge_morain as dem 3 | import time 4 | 5 | bits = [50,75,100,110,125,150,175,200,250,300,350,400,450,500] 6 | eds = [5,6,7,8,9,10,11,12,13,14,15,16,17,18,19] #, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30] 7 | 8 | num_times = 10 9 | def call_dem(n,k): 10 | start = time.time(); 11 | dem.run(n,k) 12 | return time.time()-start 13 | 14 | def call_cp(n,k): 15 | r,k,D = cp.gen_params_from_bits(n,k) 16 | start = time.time(); 17 | cp.run(r,k,D) 18 | return time.time()-start 19 | 20 | def profile(p): 21 | if p == "dem": 22 | f = call_dem 23 | if p == "cp": 24 | f = call_cp 25 | for k in eds: 26 | file = open("logs/" + p + "/k" + str(k) + ".csv", 'w') 27 | file.write("Number of bits, Time in seconds\n") 28 | for n in bits: 29 | print(n,k) 30 | total_time = 0 31 | for i in range(0,num_times): 32 | total_time += f(n,k) 33 | print(total_time) 34 | file.write(str(n) + ", %.4f\n" %(total_time/num_times)) 35 | file.close() 36 | 37 | profile("dem") 38 | profile("cp") 39 | 40 | -------------------------------------------------------------------------------- /ecfactory/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .utils import is_valid_curve, filter_decorator, is_suitable_curve, is_suitable_q, is_suitable_r, print_curve, curve_to_string -------------------------------------------------------------------------------- /ecfactory/utils/readme.md: -------------------------------------------------------------------------------- 1 | Utils 2 | ===== 3 | 4 | Overview 5 | -------- 6 | 7 | This module provides functionality to filter the set of elliptic curves found by all algorithms in the library. The methods are designed to be overriden by the user. 8 | 9 | Throughout, 10 | _q_ denotes the prime size of the base field; 11 | _t_ denotes the trace of Frobenius; 12 | _r_ denotes the prime size of the group; 13 | _k_ denotes the embedding degree; 14 | _D_ denotes the (negative) fundamental discriminant. 15 | 16 | Methods 17 | ------- 18 | 19 | Here is an overview of the methods in `utils.py`: 20 | 21 | ```python 22 | is_valid_curve(q, t, r, k, D) 23 | ``` 24 | 25 | Checks that (_q_,_t_,_r_,_k_,_D_) is a valid elliptic curve. 26 | 27 | ```python 28 | is_suitable_curve(q, t, r, k, D, num_bits) 29 | ``` 30 | 31 | All algorithms that output an elliptic curve call this method to check if the curve found is suitable. If not, then the algorithm will retry to find a new curve. By default, the method returns *true* if (_q_,_t_,_r_,_k_,_D_) is a valid elliptic curve and _r_ has at least *num_bits* bits 32 | 33 | ```python 34 | is_suitable_q(q) 35 | ``` 36 | 37 | All algorithms that search for _q_ separately from the rest of the parameters call this method to determine if _q_ is suitable. By default, the method returns *true* if _q_ is prime. 38 | 39 | ```python 40 | is_suitable_r(r) 41 | ``` 42 | 43 | All algorithms that search for _r_ separately from the rest of the parameters call this method to determine if _r_ is suitable. By default, the method returns *true* if _r_ is prime. 44 | 45 | ```python 46 | print_curve(q, t, k, r, D): 47 | ``` 48 | 49 | Prints the curve (_q_,_t_,_r_,_k_,_D_). 50 | 51 | ```python 52 | curve_to_string(q, t, k, r, D): 53 | ``` 54 | 55 | Returns a string representation of the curve (_q_,_t_,_r_,_k_,_D_). 56 | 57 | 58 | 59 | Examples 60 | -------- 61 | 62 | All of the methods above are designed to be overriden by the user. The following code shows how to do this for `is_suitable_q`. All other methods can be overriden in the same way. **WARNING** Overriding methods improperly may cause algorithms to loop indefinitely. Take care to check that there are curves that will satisfy the constraints implied by the 3 methods. 63 | 64 | Overriding `is_suitable_q` 65 | 66 | ```python 67 | import ecfactory.utils as utils 68 | utils.is_suitable_q = lambda q: is_prime(q) and q % 6 == 1 69 | ``` 70 | 71 | Now all algorithms that search for _q_ will only find primes congruent to 1 mod 6. Check that this is true with DEM 72 | 73 | ```python 74 | import ecfactory.dupont_enge_morain as dem 75 | q, t, r, k, D = dem.run(50, 5) 76 | assert q % 6 == 1 77 | ``` 78 | 79 | 80 | -------------------------------------------------------------------------------- /ecfactory/utils/utils.py: -------------------------------------------------------------------------------- 1 | import time 2 | from sage.all import is_prime, is_square, power_mod, fundamental_discriminant, log, floor 3 | 4 | def is_valid_curve(q,t,r,k,D): 5 | """ 6 | Description: 7 | 8 | Tests that (q,t,r,k,D) is a valid elliptic curve 9 | 10 | Input: 11 | 12 | q - size of prime field 13 | t - trace of Frobenius 14 | r - size of prime order subgroup 15 | k - embedding degree 16 | D - (negative) fundamental discriminant 17 | 18 | Output: 19 | 20 | bool - true iff there exists an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D 21 | 22 | """ 23 | if q == 0 or t == 0 or r == 0 or k == 0 or D == 0: 24 | return False 25 | if not is_prime(q): 26 | return False 27 | if not is_prime(r): 28 | return False 29 | if not fundamental_discriminant(D) == D: 30 | return False 31 | if D % 4 == 0: #check CM equation 32 | if not is_square(4*(t*t - 4*q)//D): 33 | return False 34 | if D % 4 == 1: 35 | if not is_square((t*t - 4*q)//D): 36 | return False 37 | if not (q+1-t) % r == 0: #check r | #E(F_q) 38 | return False 39 | if not power_mod(q,k,r) == 1: #check embedding degree is k 40 | return False 41 | return True 42 | 43 | def filter_decorator(f): 44 | def helper(*args): 45 | q,t,r,k,D = f(*args) 46 | num_bits = _number_of_bits(r) 47 | while not is_suitable_curve(q,t,r,k,D, num_bits): 48 | q,t,r,k,D = f(*args) 49 | num_bits = _number_of_bits(r) 50 | return q,t,r,k,D 51 | return helper 52 | 53 | def _number_of_bits(n): 54 | """ 55 | Description: 56 | 57 | Returns the number of bits in the binary representation of n 58 | 59 | Input: 60 | 61 | n - integer 62 | 63 | Output: 64 | 65 | num_bits - number of bits 66 | 67 | """ 68 | if n == 0: 69 | return 1 70 | else: 71 | return floor(log(n).n()/log(2).n()) + 1 72 | 73 | def is_suitable_curve(q,t,r,k,D, num_bits): 74 | """ 75 | Description: 76 | 77 | User-defined method that filters the set of curves that are returned. By default checks if (q,t,r,k,D) is a valid curve 78 | 79 | Input: 80 | 81 | q - size of prime field 82 | t - trace of Frobenius 83 | r - size of prime order subgroup 84 | k - embedding degree 85 | D - (negative) fundamental discriminant 86 | num_bits - desired number of bits in r 87 | 88 | Output: 89 | 90 | bool - true iff (q,t,r,k,D) is suitable 91 | 92 | """ 93 | return _number_of_bits(r) >= num_bits and is_valid_curve(q,t,r,k,D) 94 | 95 | def is_suitable_q(q): 96 | """ 97 | Description: 98 | 99 | User-defined method that filters the set of primes q that are returned. By default checks if q is prime 100 | 101 | Input: 102 | 103 | q - integer 104 | 105 | Output: 106 | 107 | bool - true iff q is suitable 108 | 109 | """ 110 | return is_prime(q) 111 | 112 | def is_suitable_r(r): 113 | """ 114 | Description: 115 | 116 | User-defined method that filters the set of primes r that are returned. By default checks if r is prime 117 | 118 | Input: 119 | 120 | r - integer 121 | 122 | Output: 123 | 124 | bool - true iff r is suitable 125 | 126 | """ 127 | return is_prime(r) 128 | 129 | 130 | def print_curve(q,t,r,k,D): 131 | """ 132 | Description: 133 | 134 | Prints the curve (q,t,r,k,D) 135 | 136 | Input: 137 | 138 | q - size of prime field 139 | t - trace of Frobenius 140 | r - size of prime order subgroup 141 | k - embedding degree 142 | D - (negative) fundamental discriminant 143 | 144 | Output: 145 | 146 | None 147 | 148 | """ 149 | print(curve_to_string(q,t,k,r,D)) 150 | 151 | def curve_to_string(q,t,k,r,D): 152 | """ 153 | Description: 154 | 155 | Returns a string representation of the curve (q,t,r,k,D) 156 | 157 | Input: 158 | 159 | q - size of prime field 160 | t - trace of Frobenius 161 | r - size of prime order subgroup 162 | k - embedding degree 163 | D - (negative) fundamental discriminant 164 | 165 | Output: 166 | 167 | s - string representation of (q,t,r,k,D) 168 | 169 | """ 170 | if q == 0 or t == 0 or r == 0 or k == 0 or D == 0: 171 | return 'Failed to find an elliptic curve' 172 | else: 173 | return 'Elliptic curve over a field of size ' + str(q) + ' with trace ' + str(t) + ', a subgroup of order ' + str(r) + ' with embedding degree ' + str(k) + ', and fundamental discriminant ' + str(D) 174 | 175 | 176 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "ecfactory" 3 | version = "0.1.0" 4 | description = "A SageMath Library for Constructing Elliptic Curves" 5 | authors = ["See AUTHORS file"] 6 | license = "MIT" 7 | readme = "readme.md" 8 | 9 | [tool.poetry.dependencies] 10 | python = "^3.7" 11 | 12 | 13 | [build-system] 14 | requires = ["poetry-core"] 15 | build-backend = "poetry.core.masonry.api" -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ecfactory: A SageMath Library for Constructing Elliptic Curves 2 | ============================================================== 3 | 4 | 5 | Overview 6 | -------- 7 | 8 | The __ecfactory library__ is developed by the [SCIPR Lab](http://www.scipr-lab.org/) project and contributors (see [AUTHORS](AUTHORS) file) and is released under the MIT License (see [LICENSE](LICENSE) file). The library implements algorithms to construct elliptic curves with certain desired properties; specifically, it provides the following functionality. 9 | 10 | 1. [Complex Multiplication method](/ecfactory/complex_multiplication) 11 | 2. [Cocks-Pinch method](/ecfactory/cocks_pinch) 12 | 3. [Dupont-Enge-Morain method](/ecfactory/dupont_enge_morain) 13 | 4. [Solver for Pell equations](/ecfactory/pell_equation_solver) 14 | 5. [Miyaji-Nakabayashi-Takano curves](/ecfactory/mnt_curves) 15 | 6. [Barreto-Naehrig curves](/ecfactory/bn_curves) 16 | 7. [Elliptic-curve chains](/ecfactory/ec_chain) (via the Cocks-Pinch method) 17 | 8. [Elliptic-curve cycles](/ecfactory/mnt_cycles) (via MNT curves) 18 | 19 | Each of the above is packaged as a Python module in a corresponding subfolder under the [ecfactory folder](/ecfactory). 20 | 21 | Throughout, a curve _E_ is specified as a tuple (_q_,_t_,_r_,_k_,_D_) where: 22 | _q_ is the prime size of the base field; 23 | _t_ is the trace of Frobenius; 24 | _r_ is the prime size of the subgroup (which can be the size of the entire group); 25 | _k_ is the embedding degree; and 26 | _D_ is the (negative) fundamental discriminant. 27 | From the tuple (_q_,_t_,_r_,_k_,_D_), the curve equation can be found using the _Complex Multiplication method_. 28 | 29 | Requirements 30 | ------------ 31 | 32 | The library requires a working [SageMath](http://www.sagemath.org) installation, and has been tested on SageMath version 6.8, 7.2 and 9.7. 33 | 34 | Installation 35 | ----------- 36 | 37 | To install, use sage pip: 38 | 39 | $ git clone https://github.com/scipr-lab/ecfactory.git && cd ecfactory && sage -pip install . 40 | 41 | To import and use the library, write 42 | 43 | ```python 44 | import ecfactory 45 | ``` 46 | 47 | Methods can now be invoked as 48 | 49 | ```python 50 | ecfactory.module_name.method_name 51 | ``` 52 | 53 | For example, 54 | 55 | ```python 56 | ecfactory.dupont_enge_morain.run(50,5) 57 | ``` 58 | 59 | To import only one module, write 60 | 61 | ```python 62 | import ecfactory.module_name as other_name 63 | ``` 64 | 65 | Methods can now be invoked more concisely as 66 | 67 | ```python 68 | other_name.method_name 69 | ``` 70 | 71 | For example, 72 | 73 | ```python 74 | import ecfactory.dupont_enge_morain as dem 75 | dem.run(50,5) 76 | ``` 77 | 78 | Tutorials 79 | --------- 80 | 81 | Each subfolder contains a readme, code examples, and unit tests. The methods are described in the readme, and the code examples show how to run the relevant methods. Many of the algorithms and tests are probabilistic, and the random seed can be set using `set_random_seed(s)`. 82 | 83 | Additionally, the `utils` module contains global functions that filter the curves found by all algorithms. See the [utils folder](ecfactory/utils) for more details. -------------------------------------------------------------------------------- /references/Barreto Naehrig 2005 --- Pairing-Friendly Elliptic Curves of Prime Order.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scipr-lab/ecfactory/e1c918165a21adb0651e2aa0f5d3f8107fa9bddc/references/Barreto Naehrig 2005 --- Pairing-Friendly Elliptic Curves of Prime Order.pdf -------------------------------------------------------------------------------- /references/Freeman Scott Teske 2010 --- A Taxonomy of Pairing-Friendly Elliptic Curves.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scipr-lab/ecfactory/e1c918165a21adb0651e2aa0f5d3f8107fa9bddc/references/Freeman Scott Teske 2010 --- A Taxonomy of Pairing-Friendly Elliptic Curves.pdf -------------------------------------------------------------------------------- /references/Karabina Teske 2007 --- On prime-order elliptic curves with embedding degrees k = 3,4, and 6.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scipr-lab/ecfactory/e1c918165a21adb0651e2aa0f5d3f8107fa9bddc/references/Karabina Teske 2007 --- On prime-order elliptic curves with embedding degrees k = 3,4, and 6.pdf -------------------------------------------------------------------------------- /references/Washington 2008 --- Elliptic Curves Number Theory and Cryptography.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scipr-lab/ecfactory/e1c918165a21adb0651e2aa0f5d3f8107fa9bddc/references/Washington 2008 --- Elliptic Curves Number Theory and Cryptography.pdf --------------------------------------------------------------------------------