├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── images ├── gen_images.py ├── performance_ec.png ├── performance_integers_modp.png ├── results_ec.csv └── results_intmodp.csv ├── pippenger.pdf ├── requirements.txt └── src ├── __init__.py ├── benchmark_ec.py ├── benchmark_modp.py ├── group.py ├── modp.py ├── pippenger.py └── tests.py /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | .hypothesis/ 50 | .pytest_cache/ 51 | 52 | # Translations 53 | *.mo 54 | *.pot 55 | 56 | # Django stuff: 57 | *.log 58 | local_settings.py 59 | db.sqlite3 60 | 61 | # Flask stuff: 62 | instance/ 63 | .webassets-cache 64 | 65 | # Scrapy stuff: 66 | .scrapy 67 | 68 | # Sphinx documentation 69 | docs/_build/ 70 | 71 | # PyBuilder 72 | target/ 73 | 74 | # Jupyter Notebook 75 | .ipynb_checkpoints 76 | 77 | # pyenv 78 | .python-version 79 | 80 | # celery beat schedule file 81 | celerybeat-schedule 82 | 83 | # SageMath parsed files 84 | *.sage.py 85 | 86 | # Environments 87 | .env 88 | .venv 89 | env/ 90 | venv/ 91 | ENV/ 92 | env.bak/ 93 | venv.bak/ 94 | 95 | # Spyder project settings 96 | .spyderproject 97 | .spyproject 98 | 99 | # Rope project settings 100 | .ropeproject 101 | 102 | # mkdocs documentation 103 | /site 104 | 105 | # mypy 106 | .mypy_cache/ 107 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | matrix: 3 | include: 4 | - python: 3.6 5 | dist: trusty 6 | sudo: false 7 | - python: 3.7 8 | dist: xenial 9 | sudo: true 10 | 11 | install: 12 | - pip install -r requirements.txt 13 | 14 | script: coverage run src/tests.py 15 | 16 | after_success: 17 | - codecov -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 wborgeaud 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python-pippenger 2 | Python3 implementation of the Pippenger algorithm for fast multi-exponentiation, following this [survey by Bootle](pippenger.pdf). 3 | 4 | ## Usage 5 | We use a `Group` class to abstract the group operation and thus make the function usable for any group (or monoid for that matter): 6 | ```python 7 | class Group(ABC): 8 | def __init__(self, unit, order): 9 | self.unit = unit 10 | self.order = order 11 | @abstractmethod 12 | def mult(self, x, y): 13 | pass 14 | def square(self, x): 15 | return self.mult(x, x) 16 | ``` 17 | Then, performing the multi-exponentaition `prod_i=1^N g_i^e_i` in an instance of the `Group` class is easy: 18 | ```python 19 | isinstance(G, Group) # True 20 | #gs is a list of elements of G, es a list of integer exponents. 21 | multiexp = Pippenger(G).multiexp(gs, es) 22 | ``` 23 | We provide `Group` classes for multiplicative subgroups of modular integers `MultIntModP` and for elliptic curves `EC`: 24 | ```python 25 | G = MultIntModP(23, 11) # cyclic subgroup of order 11 of Z_23^* 26 | gs = [ModP(3,23), ModP(12,23), ModP(6,23)] 27 | es = [9, 3, 10] 28 | multiexp = Pippenger(G).multiexp(gs, es) # returns 9 29 | ``` 30 | 31 | ## Performances 32 | We provide a benchmark for this algorighm in the case where the group `G` is: 33 | - A prime order cyclic subgroup of the multiplicative group of integers mod `q`: `Z_q^*.` 34 | - An elliptic curve with the usual group law. 35 | 36 | ### Integers mod q 37 | Here we take safe primes `p, q=2p+1` and consider the cyclic subgroup of order `p` of `Z_q^*`. We select `N` random elements in this group, as well as `N` random exponents in `(0,p)`. 38 | 39 | We then count the number of multiplications required to compute `prod_i=1^N g_i^e_i` using Pippenger's method or the naive one: 40 | ```python 41 | def naive_multi_exp(gs, es): 42 | tmp = gs[0]**es[0] 43 | for i in range(1,len(gs)): 44 | tmp *= gs[i]**es[i] 45 | return tmp 46 | ``` 47 | Here are the results for `p` a prime with 16, 32, 64, 128, 256, and 512 bits: 48 | ![IntModP](images/performance_integers_modp.png) 49 | We see that Pippenger's method requires far less multiplications. The time required for both methods is more or less the same since function calls in python are really slow. 50 | 51 | ### Elliptic curves 52 | The number of multiplications (that we'll call additions for elliptic curves) is the same as for integers (it does not depend on the group in general). 53 | 54 | Elliptic curves, however, have a far more expensive addition operation. Therefore, the savings in the total number of group operation yields great savings in time too. 55 | 56 | We use the same setup as before, this time measuring the time. 57 | 58 | Here are the results for the curves SECP256k1, NIST192p, NIST224p, NIST256p, NIST384p, NIST521p: 59 | ![EC](images/performance_ec.png) 60 | We see that Pippenger's algorithm is much faster than the naive methods for all elliptic curves. This observation holds in general for groups where the group operation is expensive. 61 | 62 | ## Where is it useful 63 | The main application (that I know of) of Pippenger's algorithm is in cryptography. Many cryptographic schemes relying on the Discrete Logarithm assumption (or related ones) perform a multi-exponentiation at some point. 64 | 65 | For example [bulletproofs](https://crypto.stanford.edu/bulletproofs/) make extensive use of multi-exponentiations **because** they are so much faster than aggregating individual exponentiations. -------------------------------------------------------------------------------- /images/gen_images.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import matplotlib.pyplot as plt 3 | 4 | df = pd.read_csv('results_intmodp.csv') 5 | fig, axs = plt.subplots(2,3, figsize=(20,15)) 6 | axs = axs.ravel() 7 | for i,bits in enumerate(df.bits.unique()): 8 | sub_df = df.loc[df.bits==bits] 9 | sub_df.plot('N',['NaiveMults', 'PipMults'], ax=axs[i]) 10 | axs[i].set_title('{}-bit prime'.format(bits)) 11 | axs[i].set_xlabel('N') 12 | axs[i].set_ylabel('# of multiplications') 13 | plt.savefig('performance_integers_modp.png', bbox_inches='tight') 14 | 15 | df = pd.read_csv('results_ec.csv') 16 | fig, axs = plt.subplots(2,3, figsize=(20,15)) 17 | axs = axs.ravel() 18 | for i,curve in enumerate(df.curve.unique()): 19 | sub_df = df.loc[df.curve==curve] 20 | sub_df.plot('N',['NaiveTime', 'PipTime'], ax=axs[i]) 21 | axs[i].set_title(curve) 22 | axs[i].set_xlabel('N') 23 | axs[i].set_ylabel('time [s]') 24 | plt.savefig('performance_ec.png', bbox_inches='tight') 25 | -------------------------------------------------------------------------------- /images/performance_ec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wborgeaud/python-pippenger/496711a3cdbe08d2af97e2910aa824e83ba5bf7b/images/performance_ec.png -------------------------------------------------------------------------------- /images/performance_integers_modp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wborgeaud/python-pippenger/496711a3cdbe08d2af97e2910aa824e83ba5bf7b/images/performance_integers_modp.png -------------------------------------------------------------------------------- /images/results_ec.csv: -------------------------------------------------------------------------------- 1 | ,N,NaiveTime,PipTime,curve,order 2 | 0,2,0.06472539901733398,0.04689192771911621,SECP256k1,256 3 | 1,8,0.27396416664123535,0.10808658599853516,SECP256k1,256 4 | 2,14,0.44565844535827637,0.14387083053588867,SECP256k1,256 5 | 3,20,0.6475412845611572,0.21631479263305664,SECP256k1,256 6 | 4,26,1.380345106124878,0.2397000789642334,SECP256k1,256 7 | 5,32,1.0171558856964111,0.2840573787689209,SECP256k1,256 8 | 6,38,1.2400245666503906,0.30193066596984863,SECP256k1,256 9 | 7,44,1.4439780712127686,0.3791792392730713,SECP256k1,256 10 | 8,50,1.6300487518310547,0.3918032646179199,SECP256k1,256 11 | 9,56,1.8678297996520996,0.445629358291626,SECP256k1,256 12 | 10,62,2.6717727184295654,0.5543093681335449,SECP256k1,256 13 | 11,68,2.1762261390686035,0.5505247116088867,SECP256k1,256 14 | 12,74,2.3769583702087402,0.5709211826324463,SECP256k1,256 15 | 13,80,2.5461618900299072,0.5843410491943359,SECP256k1,256 16 | 14,86,2.8180811405181885,0.5919549465179443,SECP256k1,256 17 | 15,92,3.659332513809204,0.8235282897949219,SECP256k1,256 18 | 16,98,3.6578807830810547,0.9833669662475586,SECP256k1,256 19 | 17,104,7.461291074752808,1.422635793685913,SECP256k1,256 20 | 18,110,6.808343887329102,1.6661009788513184,SECP256k1,256 21 | 19,116,4.067017078399658,0.8245913982391357,SECP256k1,256 22 | 20,122,4.244050979614258,0.8998541831970215,SECP256k1,256 23 | 21,128,6.251480579376221,1.3838942050933838,SECP256k1,256 24 | 22,134,5.4742515087127686,0.9138185977935791,SECP256k1,256 25 | 23,140,5.633845806121826,0.9533939361572266,SECP256k1,256 26 | 24,146,5.083017349243164,1.0961613655090332,SECP256k1,256 27 | 25,152,5.926845550537109,1.206369400024414,SECP256k1,256 28 | 26,158,6.295738697052002,1.0677769184112549,SECP256k1,256 29 | 27,164,5.500510931015015,1.0922996997833252,SECP256k1,256 30 | 28,170,6.530422687530518,1.6137661933898926,SECP256k1,256 31 | 29,176,6.078668832778931,1.2307507991790771,SECP256k1,256 32 | 30,182,6.518836736679077,1.2390103340148926,SECP256k1,256 33 | 31,188,6.209580659866333,1.2662675380706787,SECP256k1,256 34 | 32,194,6.38530969619751,1.3122448921203613,SECP256k1,256 35 | 33,200,6.623673439025879,1.33903169631958,SECP256k1,256 36 | 34,206,7.122127056121826,1.3883769512176514,SECP256k1,256 37 | 35,212,7.016238689422607,1.7203164100646973,SECP256k1,256 38 | 36,218,6.304407119750977,1.3572161197662354,SECP256k1,256 39 | 37,224,7.387728452682495,1.4936275482177734,SECP256k1,256 40 | 38,230,8.059454441070557,1.3707246780395508,SECP256k1,256 41 | 39,236,10.142349481582642,2.7030856609344482,SECP256k1,256 42 | 40,242,7.639490604400635,1.4483916759490967,SECP256k1,256 43 | 41,248,7.353198528289795,1.6456093788146973,SECP256k1,256 44 | 42,254,7.964140892028809,1.5129780769348145,SECP256k1,256 45 | 43,2,0.03605175018310547,0.026885986328125,NIST192p,192 46 | 44,6,0.10158395767211914,0.04651498794555664,NIST192p,192 47 | 45,10,0.2205204963684082,0.089385986328125,NIST192p,192 48 | 46,14,0.2995882034301758,0.09731531143188477,NIST192p,192 49 | 47,18,0.3149416446685791,0.09666919708251953,NIST192p,192 50 | 48,22,0.389873743057251,0.10461115837097168,NIST192p,192 51 | 49,26,0.4550800323486328,0.12865233421325684,NIST192p,192 52 | 50,30,0.5098361968994141,0.14651989936828613,NIST192p,192 53 | 51,34,0.6120638847351074,0.16153478622436523,NIST192p,192 54 | 52,38,0.6496212482452393,0.1628437042236328,NIST192p,192 55 | 53,42,0.7566943168640137,0.1737658977508545,NIST192p,192 56 | 54,46,0.881601095199585,0.2076406478881836,NIST192p,192 57 | 55,50,0.8090314865112305,0.2841339111328125,NIST192p,192 58 | 56,54,0.8662528991699219,0.2266228199005127,NIST192p,192 59 | 57,58,0.9345128536224365,0.21444344520568848,NIST192p,192 60 | 58,62,1.002431869506836,0.22810959815979004,NIST192p,192 61 | 59,66,1.0637683868408203,0.24225163459777832,NIST192p,192 62 | 60,70,1.142061471939087,0.26068544387817383,NIST192p,192 63 | 61,74,1.3001205921173096,0.27159976959228516,NIST192p,192 64 | 62,78,1.8609199523925781,0.35173964500427246,NIST192p,192 65 | 63,82,1.6299159526824951,0.34296369552612305,NIST192p,192 66 | 64,86,1.9881327152252197,0.37575507164001465,NIST192p,192 67 | 65,90,1.69313645362854,0.36342763900756836,NIST192p,192 68 | 66,94,1.606355905532837,0.3753681182861328,NIST192p,192 69 | 67,98,1.795337438583374,0.3845052719116211,NIST192p,192 70 | 68,102,1.6389365196228027,0.3819746971130371,NIST192p,192 71 | 69,106,2.3258283138275146,0.4521803855895996,NIST192p,192 72 | 70,110,2.408975839614868,0.5145790576934814,NIST192p,192 73 | 71,114,2.431636333465576,0.5607447624206543,NIST192p,192 74 | 72,118,2.1390671730041504,0.4794754981994629,NIST192p,192 75 | 73,122,2.323235511779785,0.5392842292785645,NIST192p,192 76 | 74,126,2.1153652667999268,0.4892582893371582,NIST192p,192 77 | 75,130,2.149507522583008,0.4709899425506592,NIST192p,192 78 | 76,134,2.7626047134399414,0.5315508842468262,NIST192p,192 79 | 77,138,2.692638635635376,0.608656644821167,NIST192p,192 80 | 78,142,4.709870100021362,0.5999422073364258,NIST192p,192 81 | 79,146,2.872025966644287,0.8807079792022705,NIST192p,192 82 | 80,150,3.3989315032958984,0.6140522956848145,NIST192p,192 83 | 81,154,4.104422569274902,0.9472076892852783,NIST192p,192 84 | 82,158,4.130974292755127,0.969099760055542,NIST192p,192 85 | 83,162,7.062756061553955,1.7566065788269043,NIST192p,192 86 | 84,166,4.270059108734131,1.000859022140503,NIST192p,192 87 | 85,170,5.0209641456604,1.1064987182617188,NIST192p,192 88 | 86,174,5.419201612472534,1.6459729671478271,NIST192p,192 89 | 87,178,6.565941572189331,1.3216564655303955,NIST192p,192 90 | 88,182,4.027960538864136,0.683513879776001,NIST192p,192 91 | 89,186,3.040423631668091,0.7656126022338867,NIST192p,192 92 | 90,190,3.3947341442108154,0.7437829971313477,NIST192p,192 93 | 0,2,0.04466676712036133,0.03444194793701172,NIST224p,224 94 | 1,7,0.15366721153259277,0.06634998321533203,NIST224p,224 95 | 2,12,0.2646608352661133,0.08802366256713867,NIST224p,224 96 | 3,17,0.37072205543518066,0.11431145668029785,NIST224p,224 97 | 4,22,0.48479223251342773,0.14207959175109863,NIST224p,224 98 | 5,27,0.5933079719543457,0.16706275939941406,NIST224p,224 99 | 6,32,0.868549108505249,0.20306825637817383,NIST224p,224 100 | 7,37,0.8501520156860352,0.22591590881347656,NIST224p,224 101 | 8,42,0.9902851581573486,0.23471403121948242,NIST224p,224 102 | 9,47,1.0421695709228516,0.3026711940765381,NIST224p,224 103 | 10,52,1.1847996711730957,0.27762794494628906,NIST224p,224 104 | 11,57,1.811431884765625,0.5006601810455322,NIST224p,224 105 | 12,62,1.4675700664520264,0.3469352722167969,NIST224p,224 106 | 13,67,1.5459280014038086,0.35353636741638184,NIST224p,224 107 | 14,72,2.0547358989715576,0.43578314781188965,NIST224p,224 108 | 15,77,2.2319793701171875,0.4728372097015381,NIST224p,224 109 | 16,82,1.9260766506195068,0.4632601737976074,NIST224p,224 110 | 17,87,2.078270435333252,0.4459824562072754,NIST224p,224 111 | 18,92,2.1871891021728516,0.600893497467041,NIST224p,224 112 | 19,97,2.4369401931762695,0.5696032047271729,NIST224p,224 113 | 20,102,2.8788013458251953,0.5404820442199707,NIST224p,224 114 | 21,107,3.1406280994415283,0.6229386329650879,NIST224p,224 115 | 22,112,2.9391822814941406,0.7724275588989258,NIST224p,224 116 | 23,117,3.333310127258301,0.766124963760376,NIST224p,224 117 | 24,122,3.4566168785095215,0.6342775821685791,NIST224p,224 118 | 25,127,3.446363687515259,0.7484617233276367,NIST224p,224 119 | 26,132,3.818582773208618,0.700930118560791,NIST224p,224 120 | 27,137,3.783071517944336,0.852705717086792,NIST224p,224 121 | 28,142,3.6996495723724365,0.8043117523193359,NIST224p,224 122 | 29,147,4.527706623077393,0.8560497760772705,NIST224p,224 123 | 30,152,3.4561405181884766,0.7485959529876709,NIST224p,224 124 | 31,157,4.489689350128174,1.0953469276428223,NIST224p,224 125 | 32,162,3.8693296909332275,0.8328595161437988,NIST224p,224 126 | 33,167,3.7825965881347656,0.8087000846862793,NIST224p,224 127 | 34,172,4.012791156768799,0.8719258308410645,NIST224p,224 128 | 35,177,4.757007122039795,1.0579984188079834,NIST224p,224 129 | 36,182,4.298690557479858,1.018404483795166,NIST224p,224 130 | 37,187,4.66446590423584,1.0998213291168213,NIST224p,224 131 | 38,192,5.46021032333374,1.112910270690918,NIST224p,224 132 | 39,197,5.092211008071899,1.0178117752075195,NIST224p,224 133 | 40,202,4.535188436508179,1.4218673706054688,NIST224p,224 134 | 41,207,5.355396509170532,1.2234766483306885,NIST224p,224 135 | 42,212,4.849812984466553,1.1023213863372803,NIST224p,224 136 | 43,217,5.082634925842285,1.6146135330200195,NIST224p,224 137 | 44,222,5.110457420349121,1.0779914855957031,NIST224p,224 138 | 91,2,0.05716061592102051,0.04451894760131836,NIST256p,256 139 | 92,8,0.23541593551635742,0.08548831939697266,NIST256p,256 140 | 93,14,0.6038863658905029,0.16164445877075195,NIST256p,256 141 | 94,20,0.7364716529846191,0.19166159629821777,NIST256p,256 142 | 95,26,0.782595157623291,0.22133398056030273,NIST256p,256 143 | 96,32,1.048440933227539,0.2546100616455078,NIST256p,256 144 | 97,38,1.2092888355255127,0.2857332229614258,NIST256p,256 145 | 98,44,1.6277055740356445,0.4589262008666992,NIST256p,256 146 | 99,50,1.8216791152954102,0.5427954196929932,NIST256p,256 147 | 100,56,1.8773996829986572,0.42464256286621094,NIST256p,256 148 | 101,62,2.159874677658081,0.5218744277954102,NIST256p,256 149 | 102,68,2.602170467376709,0.5244295597076416,NIST256p,256 150 | 103,74,2.4447576999664307,0.5324771404266357,NIST256p,256 151 | 104,80,2.454427719116211,0.576462984085083,NIST256p,256 152 | 105,86,2.869410991668701,0.6970298290252686,NIST256p,256 153 | 106,92,3.010589122772217,0.5913565158843994,NIST256p,256 154 | 107,98,3.3955130577087402,0.6939518451690674,NIST256p,256 155 | 108,104,5.121500253677368,0.7744698524475098,NIST256p,256 156 | 109,110,3.2250258922576904,0.6976413726806641,NIST256p,256 157 | 110,116,3.8497698307037354,0.8932943344116211,NIST256p,256 158 | 111,122,3.659762144088745,0.9180817604064941,NIST256p,256 159 | 112,128,4.251528978347778,0.7760365009307861,NIST256p,256 160 | 113,134,5.22513222694397,0.8524131774902344,NIST256p,256 161 | 114,140,6.106981515884399,1.2861671447753906,NIST256p,256 162 | 115,146,5.344658851623535,0.9402203559875488,NIST256p,256 163 | 116,152,7.957377910614014,1.0412375926971436,NIST256p,256 164 | 117,158,4.809235095977783,0.9244112968444824,NIST256p,256 165 | 118,164,4.852541923522949,0.9768881797790527,NIST256p,256 166 | 119,170,5.1517744064331055,1.0095758438110352,NIST256p,256 167 | 120,176,5.741623401641846,1.0626301765441895,NIST256p,256 168 | 121,182,5.8841328620910645,1.0900323390960693,NIST256p,256 169 | 122,188,9.283184051513672,1.219691514968872,NIST256p,256 170 | 123,194,6.988605976104736,1.5826923847198486,NIST256p,256 171 | 124,200,5.896798133850098,1.2362866401672363,NIST256p,256 172 | 125,206,7.3908867835998535,1.3392741680145264,NIST256p,256 173 | 126,212,6.745999097824097,1.7180767059326172,NIST256p,256 174 | 127,218,7.211648225784302,1.305415391921997,NIST256p,256 175 | 128,224,7.817424774169922,1.691195011138916,NIST256p,256 176 | 129,230,7.28767991065979,1.4973514080047607,NIST256p,256 177 | 130,236,7.042916536331177,1.5747230052947998,NIST256p,256 178 | 131,242,8.934436321258545,2.3114850521087646,NIST256p,256 179 | 132,248,8.604805946350098,1.5269510746002197,NIST256p,256 180 | 133,254,8.437598943710327,1.6379096508026123,NIST256p,256 181 | 134,2,0.2027442455291748,0.11430096626281738,NIST384p,384 182 | 135,10,1.0531656742095947,0.48355698585510254,NIST384p,384 183 | 136,18,1.5131471157073975,0.37763547897338867,NIST384p,384 184 | 137,26,2.1833152770996094,0.5246913433074951,NIST384p,384 185 | 138,34,2.876573324203491,0.683906078338623,NIST384p,384 186 | 139,42,2.842341899871826,0.6621665954589844,NIST384p,384 187 | 140,50,3.410621404647827,0.7887876033782959,NIST384p,384 188 | 141,58,4.76430082321167,0.9885177612304688,NIST384p,384 189 | 142,66,4.669563055038452,1.1562466621398926,NIST384p,384 190 | 143,74,5.6012513637542725,1.173231840133667,NIST384p,384 191 | 144,82,6.9069905281066895,1.275029182434082,NIST384p,384 192 | 145,90,6.3873701095581055,1.3732194900512695,NIST384p,384 193 | 146,98,7.8555498123168945,1.6676874160766602,NIST384p,384 194 | 147,106,10.928337574005127,1.9562792778015137,NIST384p,384 195 | 148,114,9.517289400100708,2.2526848316192627,NIST384p,384 196 | 149,122,11.51626706123352,2.4194321632385254,NIST384p,384 197 | 150,130,8.739101886749268,1.6006968021392822,NIST384p,384 198 | 151,138,9.765317916870117,1.7210631370544434,NIST384p,384 199 | 152,146,11.5929274559021,1.8852839469909668,NIST384p,384 200 | 153,154,11.054438829421997,1.9533946514129639,NIST384p,384 201 | 154,162,11.966065645217896,2.2884809970855713,NIST384p,384 202 | 155,170,11.696524620056152,2.1262662410736084,NIST384p,384 203 | 156,178,12.369197368621826,2.2329483032226562,NIST384p,384 204 | 157,186,14.287367820739746,2.630084991455078,NIST384p,384 205 | 158,194,13.406442165374756,2.784402847290039,NIST384p,384 206 | 159,202,13.73248291015625,2.556751251220703,NIST384p,384 207 | 160,210,14.3542320728302,2.7188823223114014,NIST384p,384 208 | 161,218,16.157418966293335,3.046794891357422,NIST384p,384 209 | 162,226,16.82155442237854,3.10988712310791,NIST384p,384 210 | 163,234,17.595905780792236,3.509707450866699,NIST384p,384 211 | 164,242,17.091713666915894,3.454744815826416,NIST384p,384 212 | 165,250,18.755274295806885,3.3159334659576416,NIST384p,384 213 | 166,258,18.561070680618286,3.348747968673706,NIST384p,384 214 | 167,266,18.18425416946411,3.695835828781128,NIST384p,384 215 | 168,274,20.57282257080078,3.928471565246582,NIST384p,384 216 | 169,282,20.46967101097107,4.081638813018799,NIST384p,384 217 | 170,290,20.82067346572876,3.7668263912200928,NIST384p,384 218 | 171,298,20.501762628555298,4.11134672164917,NIST384p,384 219 | 172,306,23.143458366394043,4.230232238769531,NIST384p,384 220 | 173,314,24.31265950202942,4.472182035446167,NIST384p,384 221 | 174,322,25.26913285255432,4.217308044433594,NIST384p,384 222 | 175,330,24.55200481414795,4.621685981750488,NIST384p,384 223 | 176,338,25.567491054534912,4.3569254875183105,NIST384p,384 224 | 177,346,23.006694316864014,4.319396495819092,NIST384p,384 225 | 178,354,23.62040376663208,4.384599208831787,NIST384p,384 226 | 179,362,25.85623002052307,4.477531671524048,NIST384p,384 227 | 180,370,28.93067502975464,5.484422206878662,NIST384p,384 228 | 181,378,28.523240566253662,5.1278252601623535,NIST384p,384 229 | 182,2,0.2619771957397461,0.18531560897827148,NIST521p,521 230 | 183,13,1.7005681991577148,0.5147757530212402,NIST521p,521 231 | 184,24,3.096407413482666,0.7500112056732178,NIST521p,521 232 | 185,35,4.8762054443359375,1.0202314853668213,NIST521p,521 233 | 186,46,7.053065299987793,1.5195767879486084,NIST521p,521 234 | 187,57,7.692666053771973,1.7578604221343994,NIST521p,521 235 | 188,68,9.169787406921387,1.850905179977417,NIST521p,521 236 | 189,79,11.58556079864502,2.3559463024139404,NIST521p,521 237 | 190,90,11.77851128578186,2.195110559463501,NIST521p,521 238 | 191,101,14.426555871963501,2.7160239219665527,NIST521p,521 239 | 192,112,16.46640133857727,2.9101345539093018,NIST521p,521 240 | 193,123,18.21044683456421,3.4055683612823486,NIST521p,521 241 | 194,134,18.91384243965149,3.4560489654541016,NIST521p,521 242 | 195,145,20.139220237731934,4.3169941902160645,NIST521p,521 243 | 196,156,21.116158723831177,4.340495347976685,NIST521p,521 244 | 197,167,23.72601556777954,4.56929874420166,NIST521p,521 245 | 198,178,26.109389781951904,4.191583633422852,NIST521p,521 246 | 199,189,34.10768508911133,9.272083282470703,NIST521p,521 247 | 200,200,34.53078317642212,6.387987375259399,NIST521p,521 248 | 201,211,39.33741092681885,7.163455963134766,NIST521p,521 249 | 202,222,37.81208562850952,6.979485273361206,NIST521p,521 250 | 203,233,41.486318826675415,7.1459715366363525,NIST521p,521 251 | 204,244,43.148597955703735,7.162820339202881,NIST521p,521 252 | 205,255,41.79989576339722,7.613870620727539,NIST521p,521 253 | 206,266,48.533190965652466,8.366964340209961,NIST521p,521 254 | 207,277,46.71054410934448,8.223991394042969,NIST521p,521 255 | 208,288,39.68925070762634,7.103461503982544,NIST521p,521 256 | 209,299,43.45676636695862,7.314905881881714,NIST521p,521 257 | 210,310,43.20066809654236,7.29478645324707,NIST521p,521 258 | 211,321,45.87386918067932,8.088836193084717,NIST521p,521 259 | 212,332,47.966951847076416,8.969544172286987,NIST521p,521 260 | 213,343,45.82668209075928,7.605297565460205,NIST521p,521 261 | 214,354,49.40123796463013,7.513034105300903,NIST521p,521 262 | 215,365,68.02534103393555,10.040894985198975,NIST521p,521 263 | 216,376,59.8828866481781,10.352258443832397,NIST521p,521 264 | 217,387,62.269527435302734,10.306379079818726,NIST521p,521 265 | 218,398,64.22033858299255,10.986183166503906,NIST521p,521 266 | 219,409,67.117506980896,11.188184022903442,NIST521p,521 267 | 220,420,66.95398664474487,11.251215934753418,NIST521p,521 268 | 221,431,70.3176600933075,11.732492923736572,NIST521p,521 269 | 222,442,74.55828666687012,16.91811966896057,NIST521p,521 270 | 223,453,82.17570757865906,13.380555868148804,NIST521p,521 271 | 224,464,81.02014994621277,18.32493305206299,NIST521p,521 272 | 225,475,68.02873182296753,12.281662225723267,NIST521p,521 273 | 226,486,78.01558566093445,13.10988187789917,NIST521p,521 274 | 227,497,75.39445781707764,14.293999910354614,NIST521p,521 275 | 228,508,72.9853744506836,15.531632423400879,NIST521p,521 276 | 229,519,83.42325782775879,13.231099605560303,NIST521p,521 277 | 278 | -------------------------------------------------------------------------------- /images/results_intmodp.csv: -------------------------------------------------------------------------------- 1 | ,N,NaiveMults,NaiveTime,PipMults,PipTime,bits 2 | 0,1,22,4.553794860839844e-05,36,0.0002808570861816406,16 3 | 1,2,40,8.153915405273438e-05,36,0.0002353191375732422,16 4 | 2,3,63,0.0001671314239501953,54,0.0003349781036376953,16 5 | 3,4,96,0.00019621849060058594,80,0.0005033016204833984,16 6 | 4,5,109,0.00022554397583007812,71,0.0004487037658691406,16 7 | 5,6,121,0.00022912025451660156,77,0.00048041343688964844,16 8 | 6,7,151,0.0002830028533935547,89,0.00055694580078125,16 9 | 7,8,172,0.0005974769592285156,93,0.0010089874267578125,16 10 | 8,9,211,0.0009381771087646484,114,0.0016617774963378906,16 11 | 9,10,213,0.0009200572967529297,122,0.002247333526611328,16 12 | 10,11,256,0.00080108642578125,132,0.0010094642639160156,16 13 | 11,12,243,0.0009725093841552734,134,0.0018839836120605469,16 14 | 12,13,282,0.0010933876037597656,145,0.002936840057373047,16 15 | 13,14,298,0.0016355514526367188,152,0.005583763122558594,16 16 | 14,15,340,0.002883434295654297,166,0.0035936832427978516,16 17 | 15,1,45,0.0003108978271484375,55,0.0010399818420410156,32 18 | 16,2,96,0.0005676746368408203,92,0.0014879703521728516,32 19 | 17,3,147,0.0007047653198242188,111,0.0015401840209960938,32 20 | 18,4,177,0.0009417533874511719,110,0.0012085437774658203,32 21 | 19,5,222,0.0018167495727539062,134,0.002894878387451172,32 22 | 20,6,276,0.0011692047119140625,150,0.0017368793487548828,32 23 | 21,7,326,0.0018877983093261719,172,0.0027022361755371094,32 24 | 22,8,363,0.0018239021301269531,186,0.0047724246978759766,32 25 | 23,9,423,0.00237274169921875,176,0.0024521350860595703,32 26 | 24,10,454,0.002421140670776367,193,0.004654407501220703,32 27 | 25,11,495,0.001588582992553711,204,0.002607583999633789,32 28 | 26,12,570,0.00310516357421875,230,0.005350351333618164,32 29 | 27,13,595,0.002699613571166992,242,0.005739688873291016,32 30 | 28,14,630,0.0031278133392333984,257,0.002540111541748047,32 31 | 29,15,691,0.0035848617553710938,276,0.004733085632324219,32 32 | 30,16,721,0.003497600555419922,275,0.004702329635620117,32 33 | 31,17,782,0.00407719612121582,307,0.005154132843017578,32 34 | 32,18,839,0.0023458003997802734,336,0.0033600330352783203,32 35 | 33,19,863,0.0065343379974365234,333,0.004956722259521484,32 36 | 34,20,937,0.00274658203125,361,0.00705409049987793,32 37 | 35,21,953,0.0033838748931884766,362,0.0032219886779785156,32 38 | 36,22,1015,0.0021097660064697266,368,0.004968404769897461,32 39 | 37,23,1017,0.0035676956176757812,365,0.006209373474121094,32 40 | 38,24,1098,0.0053746700286865234,391,0.0026178359985351562,32 41 | 39,25,1164,0.0022954940795898438,411,0.004956960678100586,32 42 | 40,26,1166,0.004292011260986328,428,0.00799107551574707,32 43 | 41,27,1216,0.0035991668701171875,438,0.00583648681640625,32 44 | 42,28,1269,0.003779888153076172,449,0.004928112030029297,32 45 | 43,29,1314,0.004611968994140625,463,0.003682374954223633,32 46 | 44,30,1380,0.0029761791229248047,484,0.005368471145629883,32 47 | 45,31,1413,0.004374504089355469,492,0.006772041320800781,32 48 | 46,1,88,0.0001621246337890625,116,0.0005893707275390625,64 49 | 47,3,284,0.0010561943054199219,192,0.002634286880493164,64 50 | 48,5,476,0.0030329227447509766,242,0.0024368762969970703,64 51 | 49,7,664,0.0018131732940673828,308,0.0023336410522460938,64 52 | 50,9,828,0.00366973876953125,336,0.0020940303802490234,64 53 | 51,11,1022,0.002427816390991211,402,0.003685474395751953,64 54 | 52,13,1224,0.0024743080139160156,471,0.0048694610595703125,64 55 | 53,15,1397,0.0032699108123779297,488,0.05118393898010254,64 56 | 54,17,1608,0.00525212287902832,549,0.0059282779693603516,64 57 | 55,19,1797,0.004639387130737305,602,0.004790067672729492,64 58 | 56,21,1996,0.0059413909912109375,658,0.003999948501586914,64 59 | 57,23,2172,0.006661415100097656,634,0.008095502853393555,64 60 | 58,25,2344,0.006033658981323242,681,0.00677490234375,64 61 | 59,27,2507,0.006226539611816406,721,0.006275653839111328,64 62 | 60,29,2718,0.0054666996002197266,771,0.009824275970458984,64 63 | 61,31,2872,0.008359432220458984,815,0.009097576141357422,64 64 | 62,33,3098,0.005654335021972656,881,0.009194135665893555,64 65 | 63,35,3265,0.005343437194824219,916,0.009705066680908203,64 66 | 64,37,3499,0.006722688674926758,987,0.009983539581298828,64 67 | 65,39,3645,0.0077860355377197266,1004,0.007807493209838867,64 68 | 66,41,3857,0.008709430694580078,1061,0.00677180290222168,64 69 | 67,43,4026,0.012188434600830078,1131,0.013026237487792969,64 70 | 68,45,4211,0.009329080581665039,1174,0.008977174758911133,64 71 | 69,47,4388,0.008678197860717773,1217,0.010166645050048828,64 72 | 70,49,4623,0.010704278945922852,1277,0.015345096588134766,64 73 | 71,51,4789,0.007999897003173828,1309,0.011613607406616211,64 74 | 72,53,4969,0.016644001007080078,1354,0.015079736709594727,64 75 | 73,55,5174,0.011494636535644531,1370,0.014110565185546875,64 76 | 74,57,5356,0.014333248138427734,1404,0.022150278091430664,64 77 | 75,59,5601,0.01210165023803711,1466,0.016156673431396484,64 78 | 76,61,5788,0.010193347930908203,1517,0.01487278938293457,64 79 | 77,63,5964,0.011039972305297852,1562,0.013440847396850586,64 80 | 78,1,188,0.0003199577331542969,216,0.0007622241973876953,128 81 | 79,4,751,0.0020194053649902344,373,0.0022399425506591797,128 82 | 80,7,1346,0.0039713382720947266,569,0.006777048110961914,128 83 | 81,10,1888,0.009188413619995117,702,0.013112783432006836,128 84 | 82,13,2445,0.006854057312011719,796,0.015103340148925781,128 85 | 83,16,3052,0.008110523223876953,870,0.011263847351074219,128 86 | 84,19,3572,0.014121532440185547,1013,0.012681245803833008,128 87 | 85,22,4155,0.01101064682006836,1159,0.012403011322021484,128 88 | 86,25,4802,0.013938426971435547,1321,0.016298294067382812,128 89 | 87,28,5380,0.009565114974975586,1471,0.010616064071655273,128 90 | 88,31,5891,0.011268854141235352,1621,0.016609907150268555,128 91 | 89,34,6484,0.011344194412231445,1605,0.009126901626586914,128 92 | 90,37,7045,0.015421628952026367,1719,0.014435529708862305,128 93 | 91,40,7557,0.01422119140625,1852,0.011098384857177734,128 94 | 92,43,8261,0.014678001403808594,1999,0.017034292221069336,128 95 | 93,46,8761,0.018828868865966797,2122,0.014030218124389648,128 96 | 94,49,9234,0.018044710159301758,2232,0.014920711517333984,128 97 | 95,52,9845,0.020956993103027344,2364,0.022115707397460938,128 98 | 96,55,10435,0.02411484718322754,2276,0.023642301559448242,128 99 | 97,58,11048,0.019247055053710938,2380,0.018000125885009766,128 100 | 98,61,11588,0.020303726196289062,2506,0.025642871856689453,128 101 | 99,64,12169,0.026402711868286133,2618,0.019268274307250977,128 102 | 100,67,12659,0.02739429473876953,2732,0.020496606826782227,128 103 | 101,70,13280,0.03077411651611328,2830,0.020903825759887695,128 104 | 102,73,13839,0.03679347038269043,2965,0.02825450897216797,128 105 | 103,76,14276,0.030178546905517578,3059,0.03902602195739746,128 106 | 104,79,15038,0.026111364364624023,3227,0.024930238723754883,128 107 | 105,82,15596,0.027942657470703125,3296,0.025449514389038086,128 108 | 106,85,16230,0.03859853744506836,3437,0.028646469116210938,128 109 | 107,88,16708,0.03851914405822754,3539,0.04678630828857422,128 110 | 108,91,17429,0.03801131248474121,3699,0.03169846534729004,128 111 | 109,94,17757,0.030672311782836914,3751,0.039339303970336914,128 112 | 110,97,18524,0.033437490463256836,3906,0.03804159164428711,128 113 | 111,100,18980,0.04282522201538086,3973,0.03413271903991699,128 114 | 112,103,19572,0.04064059257507324,4122,0.05068373680114746,128 115 | 113,106,20169,0.03618812561035156,4222,0.050538063049316406,128 116 | 114,109,20673,0.04317617416381836,4341,0.040015459060668945,128 117 | 115,112,21347,0.03779268264770508,4470,0.04346346855163574,128 118 | 116,115,21703,0.04735112190246582,4568,0.04164910316467285,128 119 | 117,118,22293,0.05588173866271973,4643,0.0531313419342041,128 120 | 118,121,22977,0.044786930084228516,4803,0.052278995513916016,128 121 | 119,124,23606,0.05048179626464844,4892,0.04485630989074707,128 122 | 120,127,24118,0.04465603828430176,5042,0.05202817916870117,128 123 | 121,1,384,0.0008366107940673828,411,0.0017650127410888672,256 124 | 122,7,2684,0.009601831436157227,966,0.007836103439331055,256 125 | 123,13,4965,0.016553163528442383,1451,0.017659664154052734,256 126 | 124,19,7267,0.020641803741455078,1939,0.026285171508789062,256 127 | 125,25,9590,0.02529144287109375,2490,0.030441999435424805,256 128 | 126,31,11796,0.03268122673034668,2829,0.030427932739257812,256 129 | 127,37,14116,0.04342937469482422,3011,0.03191232681274414,256 130 | 128,43,16472,0.032440900802612305,3469,0.03532862663269043,256 131 | 129,49,18776,0.04393196105957031,3911,0.03134775161743164,256 132 | 130,55,20987,0.040856361389160156,4356,0.04631209373474121,256 133 | 131,61,23280,0.04977083206176758,4801,0.04259061813354492,256 134 | 132,67,25477,0.05722832679748535,4876,0.034857749938964844,256 135 | 133,73,27844,0.08009147644042969,5282,0.05271005630493164,256 136 | 134,79,30190,0.09922552108764648,5755,0.06865525245666504,256 137 | 135,85,32525,0.09781408309936523,6149,0.06763243675231934,256 138 | 136,91,34863,0.09487271308898926,6560,0.08444571495056152,256 139 | 137,97,37120,0.09852862358093262,6960,0.08353781700134277,256 140 | 138,103,39332,0.08611631393432617,7370,0.08850979804992676,256 141 | 139,109,41515,0.08037447929382324,7738,0.06932973861694336,256 142 | 140,115,44025,0.08360886573791504,8195,0.06740474700927734,256 143 | 141,121,46308,0.08788800239562988,8596,0.07656359672546387,256 144 | 142,127,48544,0.09472012519836426,9024,0.08271479606628418,256 145 | 143,133,50807,0.09750556945800781,8695,0.08457350730895996,256 146 | 144,139,53059,0.10104537010192871,9074,0.08838772773742676,256 147 | 145,145,55224,0.1032402515411377,9401,0.09463810920715332,256 148 | 146,151,57579,0.1089773178100586,9839,0.1048288345336914,256 149 | 147,157,59962,0.11169791221618652,10200,0.10958552360534668,256 150 | 148,163,62161,0.11698269844055176,10596,0.11499142646789551,256 151 | 149,169,64575,0.12189006805419922,10948,0.11487936973571777,256 152 | 150,175,66932,0.12992072105407715,11311,0.11908531188964844,256 153 | 151,181,69238,0.1327204704284668,11704,0.12406516075134277,256 154 | 152,187,71591,0.13657832145690918,12105,0.16704034805297852,256 155 | 153,193,73713,0.1427927017211914,12471,0.13777494430541992,256 156 | 154,199,75999,0.14367985725402832,12847,0.14254069328308105,256 157 | 155,205,78281,0.14723587036132812,13187,0.14980697631835938,256 158 | 156,211,80526,0.15404343605041504,13605,0.16433477401733398,256 159 | 157,217,82960,0.15857577323913574,13921,0.17166709899902344,256 160 | 158,223,85404,0.16321587562561035,14367,0.18043875694274902,256 161 | 159,229,87598,0.1735072135925293,14716,0.18598675727844238,256 162 | 160,235,89887,0.1719505786895752,15090,0.18601441383361816,256 163 | 161,241,92011,0.173325777053833,15473,0.20185065269470215,256 164 | 162,247,94335,0.1843428611755371,15838,0.20202851295471191,256 165 | 163,253,96447,0.18215537071228027,16226,0.2129981517791748,256 166 | 164,1,766,0.0031256675720214844,760,0.004522085189819336,512 167 | 165,12,9196,0.026831865310668945,2613,0.02322554588317871,512 168 | 166,23,17683,0.045500755310058594,3843,0.03811192512512207,512 169 | 167,34,25999,0.0713493824005127,5205,0.05265307426452637,512 170 | 168,45,34492,0.09400582313537598,6805,0.07346272468566895,512 171 | 169,56,43007,0.11734366416931152,8369,0.09467649459838867,512 172 | 170,67,51328,0.14369535446166992,9539,0.09842181205749512,512 173 | 171,78,59679,0.16975688934326172,11011,0.12276148796081543,512 174 | 172,89,68195,0.1972508430480957,11304,0.17891812324523926,512 175 | 173,100,76489,0.22221946716308594,12596,0.17310404777526855,512 176 | 174,111,85016,0.25693750381469727,13947,0.2034914493560791,512 177 | 175,122,93321,0.3576083183288574,15292,0.23999786376953125,512 178 | 176,133,101901,0.30600452423095703,15548,0.30785250663757324,512 179 | 177,144,110021,0.37024402618408203,16771,0.2220933437347412,512 180 | 178,155,118890,0.33664751052856445,17978,0.22787904739379883,512 181 | 179,166,127302,0.358349084854126,19294,0.2982349395751953,512 182 | 180,177,135694,0.38901519775390625,20522,0.2746613025665283,512 183 | 181,188,144192,0.40453314781188965,21814,0.30441904067993164,512 184 | 182,199,152354,0.42836880683898926,23018,0.32468438148498535,512 185 | 183,210,160933,0.4448223114013672,24253,0.3386054039001465,512 186 | 184,221,169165,0.6352145671844482,25521,0.5710148811340332,512 187 | 185,232,177422,0.5452983379364014,26714,0.4695303440093994,512 188 | 186,243,186075,0.9656589031219482,27996,0.596696138381958,512 189 | 187,254,194368,1.3558032512664795,29234,0.8734762668609619,512 190 | 188,265,203177,1.2508745193481445,30425,0.9082210063934326,512 191 | 189,276,211627,0.5623753070831299,31768,0.8365762233734131,512 192 | 190,287,219879,0.725287675857544,32959,0.6014032363891602,512 193 | 191,298,228254,0.6928958892822266,32242,0.5409440994262695,512 194 | 192,309,236774,0.6161715984344482,33266,0.5460121631622314,512 195 | 193,320,245186,0.651496410369873,34527,0.5853362083435059,512 196 | 194,331,253492,0.6659722328186035,35766,0.5828945636749268,512 197 | 195,342,262043,0.65519118309021,36779,0.6558175086975098,512 198 | 196,353,270347,0.6976892948150635,38013,0.6409730911254883,512 199 | 197,364,279040,1.2312912940979004,39228,0.9791605472564697,512 200 | 198,375,287335,0.8885998725891113,40331,1.2190189361572266,512 201 | 199,386,296186,0.7435786724090576,41540,0.9292199611663818,512 202 | 200,397,304336,0.7584667205810547,42777,0.7900245189666748,512 203 | 201,408,312676,0.913978099822998,43788,1.172800064086914,512 204 | 202,419,321391,1.0202603340148926,45023,0.9555823802947998,512 205 | 203,430,329356,1.551659107208252,46231,1.2897100448608398,512 206 | 204,441,337867,0.9354453086853027,47288,1.0343701839447021,512 207 | 205,452,346392,1.168438196182251,48499,1.0351672172546387,512 208 | 206,463,354828,1.1404352188110352,49710,1.3162176609039307,512 209 | 207,474,363200,0.9132211208343506,50822,1.0472266674041748,512 210 | 208,485,371447,0.9542851448059082,51943,1.029712200164795,512 211 | 209,496,379909,0.9948620796203613,53202,1.120274543762207,512 212 | 210,507,388324,0.9718194007873535,54249,1.1082673072814941,512 213 | -------------------------------------------------------------------------------- /pippenger.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wborgeaud/python-pippenger/496711a3cdbe08d2af97e2910aa824e83ba5bf7b/pippenger.pdf -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2019.6.16 2 | chardet==3.0.4 3 | codecov==2.0.15 4 | coverage==4.5.3 5 | ecdsa==0.13.3 6 | idna==2.8 7 | mpmath==1.1.0 8 | requests==2.22.0 9 | sympy==1.4 10 | urllib3==1.25.3 11 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wborgeaud/python-pippenger/496711a3cdbe08d2af97e2910aa824e83ba5bf7b/src/__init__.py -------------------------------------------------------------------------------- /src/benchmark_ec.py: -------------------------------------------------------------------------------- 1 | from modp import ModP 2 | from group import MultIntModP, EC 3 | from pippenger import Pippenger 4 | from random import randint 5 | from ecdsa import SECP256k1, NIST192p, NIST224p, NIST256p, NIST256p, NIST384p, NIST521p 6 | from sympy import isprime 7 | import pandas as pd 8 | import time 9 | 10 | def naive_multi_exp_ec(gs, es): 11 | tmp = es[0] * gs[0] 12 | for i in range(1, len(gs)): 13 | tmp += es[i] * gs[i] 14 | return tmp 15 | 16 | def benchmark_ec(N, curve): 17 | G = EC(curve) 18 | order_cyclic_subgroup = curve.order 19 | 20 | g = curve.generator 21 | 22 | gs = [g*randint(1, order_cyclic_subgroup) for _ in range(N)] 23 | es = [randint(1,order_cyclic_subgroup) for _ in range(N)] 24 | 25 | start = time.time() 26 | Pip = Pippenger(G) 27 | res_pip = Pip.multiexp(gs, es) 28 | time_pip = time.time()-start 29 | 30 | start = time.time() 31 | res_naive = naive_multi_exp_ec(gs, es) 32 | time_naive = time.time()-start 33 | 34 | assert res_pip == res_naive 35 | 36 | return time_pip, time_naive 37 | 38 | results = [] 39 | for curve in [SECP256k1, NIST192p, NIST224p, NIST256p, NIST384p, NIST521p]: 40 | print(curve.name, len(bin(curve.order))) 41 | for N in range(2, len(bin(curve.order))-2, 1+len(bin(curve.order))//50): 42 | print(N) 43 | time_pip, time_naive = benchmark_ec(N, curve) 44 | results.append({ 45 | 'curve': curve.name, 46 | 'order': len(bin(curve.order))-2, 47 | 'N': N, 48 | 'PipTime': time_pip, 49 | 'NaiveTime': time_naive, 50 | }) 51 | 52 | results = pd.DataFrame(results) 53 | results.to_csv('results_ec_224.csv') 54 | -------------------------------------------------------------------------------- /src/benchmark_modp.py: -------------------------------------------------------------------------------- 1 | from modp import ModP 2 | from group import MultIntModP, EC 3 | from pippenger import Pippenger 4 | from random import randint 5 | from ecdsa import SECP256k1, NIST192p, NIST224p, NIST256p, NIST256p, NIST384p, NIST521p 6 | from sympy import isprime 7 | import pandas as pd 8 | import time 9 | 10 | def naive_multi_exp(gs, es): 11 | tmp = gs[0]**es[0] 12 | for i in range(1,len(gs)): 13 | tmp *= gs[i]**es[i] 14 | return tmp 15 | 16 | def get_good_primes(bits): 17 | p = 2**bits + randint(0,2**(bits//2)) 18 | while True: 19 | if isprime(p) and isprime(2*p+1): 20 | gen = 2 21 | while True: 22 | if pow(gen, p, 2*p+1) == 1: 23 | return p, 2*p+1, gen 24 | gen += 1 25 | p += 1 26 | 27 | def benchmark_int_mod_p(N, order_cyclic_subgroup, p, gen): 28 | G = MultIntModP(p, order_cyclic_subgroup) 29 | 30 | g = ModP(gen, p) 31 | 32 | gs = [g**randint(1, order_cyclic_subgroup) for _ in range(N)] 33 | es = [randint(1,order_cyclic_subgroup) for _ in range(N)] 34 | 35 | ModP.reset() 36 | start = time.time() 37 | Pip = Pippenger(G) 38 | res_pip = Pip.multiexp(gs, es) 39 | time_pip = time.time()-start 40 | mults_pip = ModP.num_of_mult 41 | 42 | ModP.reset() 43 | start = time.time() 44 | res_naive = naive_multi_exp(gs, es) 45 | time_naive = time.time()-start 46 | mults_naive = ModP.num_of_mult 47 | 48 | assert res_pip == res_naive 49 | 50 | return time_pip, mults_pip, time_naive, mults_naive 51 | 52 | results = [] 53 | for bits in [2**i for i in range(4,10)]: 54 | print(bits) 55 | order_cyclic_subgroup, p, gen = get_good_primes(bits) 56 | for N in range(1, bits, 1 + bits//50): 57 | print(N) 58 | time_pip, mults_pip, time_naive, mults_naive = benchmark_int_mod_p(N, order_cyclic_subgroup, p, gen) 59 | results.append({ 60 | 'bits': bits, 61 | 'N': N, 62 | 'PipTime': time_pip, 63 | 'PipMults': mults_pip, 64 | 'NaiveTime': time_naive, 65 | 'NaiveMults': mults_naive, 66 | }) 67 | 68 | results = pd.DataFrame(results) 69 | results.to_csv('results_intmodp.csv') -------------------------------------------------------------------------------- /src/group.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from modp import ModP 3 | from ecdsa.ellipticcurve import Point 4 | 5 | class Group(ABC): 6 | 7 | def __init__(self, unit, order): 8 | self.unit = unit 9 | self.order = order 10 | 11 | @abstractmethod 12 | def mult(self, x, y): 13 | pass 14 | 15 | def square(self, x): 16 | return self.mult(x, x) 17 | 18 | 19 | class MultIntModP(Group): 20 | def __init__(self, p, order): 21 | Group.__init__(self, ModP(1, p), order) 22 | 23 | def mult(self, x, y): 24 | return x*y 25 | 26 | class EC(Group): 27 | def __init__(self, curve): 28 | Group.__init__(self, Point(None,None,None), curve.order) 29 | 30 | def mult(self, x, y): 31 | return x + y -------------------------------------------------------------------------------- /src/modp.py: -------------------------------------------------------------------------------- 1 | class ModP: 2 | 3 | num_of_mult=0 4 | @classmethod 5 | def reset(cls): 6 | cls.num_of_mult = 0 7 | 8 | def __init__(self, x, p): 9 | self.x = x 10 | self.p = p 11 | 12 | def __add__(self, y): 13 | if isinstance(y, int): 14 | return ModP(self.x+y, self.p) 15 | assert self.p == y.p 16 | return ModP((self.x + y.x) % self.p, self.p) 17 | 18 | def __mul__(self, y): 19 | type(self).num_of_mult += 1 20 | if isinstance(y, int): 21 | return ModP(self.x*y, self.p) 22 | assert self.p == y.p 23 | return ModP((self.x * y.x) % self.p, self.p) 24 | 25 | def __sub__(self, y): 26 | if isinstance(y, int): 27 | return ModP(self.x-y, self.p) 28 | assert self.p == y.p 29 | return ModP((self.x - y.x) % self.p, self.p) 30 | 31 | def __pow__(self, n): 32 | # return ModP(pow(self.x, n, self.p), self.p) 33 | exp = bin(n) 34 | value = ModP(self.x, self.p) 35 | 36 | for i in range(3, len(exp)): 37 | value = value * value 38 | if(exp[i:i+1]=='1'): 39 | value = value*self 40 | return value 41 | 42 | def __neg__(self): 43 | return ModP(self.p - self.x, self.p) 44 | 45 | def __eq__(self, y): 46 | return (self.x == y.x) and (self.p == y.p) 47 | 48 | 49 | def __str__(self): 50 | return str(self.x) 51 | def __repr__(self): 52 | return str(self.x) -------------------------------------------------------------------------------- /src/pippenger.py: -------------------------------------------------------------------------------- 1 | from sympy import integer_nthroot 2 | from math import log2, floor 3 | from itertools import combinations 4 | 5 | def subset_of(l): 6 | return sum(map(lambda r: list(combinations(l, r)), range(1, len(l)+1)), []) 7 | 8 | class Pippenger: 9 | def __init__(self, group): 10 | self.G = group 11 | self.order = group.order 12 | self.lamb = group.order.bit_length() 13 | 14 | # Returns g^(2^j) 15 | def _pow2powof2(self, g, j): 16 | tmp = g 17 | for _ in range(j): 18 | tmp = self.G.square(tmp) 19 | return tmp 20 | 21 | # Returns Prod g_i ^ e_i 22 | def multiexp(self, gs, es): 23 | if len(gs) != len(es): 24 | raise Exception('Different number of group elements and exponents') 25 | 26 | es = [ei%self.G.order for ei in es] 27 | 28 | if len(gs) == 0: 29 | return self.G.unit 30 | 31 | lamb = self.lamb 32 | N = len(gs) 33 | s = integer_nthroot(lamb//N, 2)[0]+1 34 | t = integer_nthroot(lamb*N,2)[0]+1 35 | gs_bin = [] 36 | for i in range(N): 37 | tmp = [gs[i]] 38 | for j in range(1,s): 39 | tmp.append(self.G.square(tmp[-1])) 40 | gs_bin.append(tmp) 41 | es_bin = [] 42 | for i in range(N): 43 | tmp1 = [] 44 | for j in range(s): 45 | tmp2 = [] 46 | for k in range(t): 47 | tmp2.append(int( bin(es[i])[2:].zfill(s*t)[-(j+s*k+1)]) ) 48 | tmp1.append(tmp2) 49 | es_bin.append(tmp1) 50 | 51 | Gs = self._multiexp_bin( 52 | [gs_bin[i][j] for i in range(N) for j in range(s)], 53 | [es_bin[i][j] for i in range(N) for j in range(s)] 54 | ) 55 | 56 | ans2 = Gs[-1] 57 | for k in range(len(Gs)-2,-1,-1): 58 | ans2 = self._pow2powof2(ans2, s) 59 | ans2 = self.G.mult(ans2, Gs[k]) 60 | 61 | return ans2 62 | 63 | def _multiexp_bin(self, gs, es): 64 | assert len(gs) == len(es) 65 | M = len(gs) 66 | b = floor( log2(M) - log2(log2(M)) ) 67 | b = b if b else 1 68 | subsets = [list(range(i,min(i+b,M))) for i in range(0,M,b)] 69 | Ts = [{sub: None for sub in subset_of(S)} for S in subsets] 70 | 71 | for T,S in zip(Ts, subsets): 72 | for i in S: 73 | T[(i,)] = gs[i] 74 | # Recursively set the subproducts in T 75 | def set_sub(sub): 76 | if T[sub] is None: 77 | if T[sub[:-1]] is None: 78 | set_sub(sub[:-1]) 79 | T[sub] = self.G.mult(T[sub[:-1]], gs[sub[-1]]) 80 | for sub in T: 81 | set_sub(sub) 82 | 83 | Gs = [] 84 | for k in range(len(es[0])): 85 | tmp = self.G.unit 86 | for T,S in zip(Ts, subsets): 87 | sub_es = [j for j in S if es[j][k]] 88 | sub_es = tuple(sub_es) 89 | if not sub_es: 90 | continue 91 | tmp = self.G.mult(tmp, T[sub_es]) 92 | Gs.append(tmp) 93 | 94 | return Gs 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /src/tests.py: -------------------------------------------------------------------------------- 1 | from modp import ModP 2 | from group import MultIntModP, EC 3 | from pippenger import Pippenger 4 | from random import randint 5 | from ecdsa import SECP256k1, NIST192p, NIST224p, NIST256p, NIST384p, NIST521p 6 | from ecdsa.ellipticcurve import Point 7 | from sympy import isprime 8 | import time 9 | import unittest 10 | from math import log2, floor 11 | 12 | def naive_multi_exp(gs, es, p): 13 | tmp = ModP(1, p) 14 | for i in range(len(gs)): 15 | tmp *= gs[i]**es[i] 16 | return tmp 17 | 18 | def naive_multi_exp_ec(gs, es): 19 | tmp = Point(None, None, None) 20 | for i in range(len(gs)): 21 | tmp += es[i] * gs[i] 22 | return tmp 23 | 24 | def get_good_primes(start): 25 | p = start 26 | while True: 27 | if isprime(p) and isprime(2*p+1): 28 | gen = 2 29 | while True: 30 | if pow(gen, p, 2*p+1) == 1: 31 | return p, 2*p+1, gen 32 | gen += 1 33 | p += 1 34 | 35 | class StupidTests(unittest.TestCase): 36 | def test_different_length(self): 37 | order, p = 11, 23 38 | G = MultIntModP(p, order) 39 | Pip = Pippenger(G) 40 | g = ModP(3, p) 41 | with self.assertRaisesRegex(Exception, 'Different number of group elements and exponents'): 42 | Pip.multiexp([g, g**2],[1]) 43 | with self.assertRaisesRegex(Exception, 'Different number of group elements and exponents'): 44 | Pip.multiexp([g],[1, 2]) 45 | 46 | 47 | def test_zero_int_modp(self): 48 | order, p = 11, 23 49 | G = MultIntModP(p, order) 50 | Pip = Pippenger(G) 51 | g = ModP(3, p) 52 | for i in range(order): 53 | with self.subTest(i=i): 54 | self.assertEqual(Pip.multiexp([g**i],[0]), G.unit) 55 | self.assertEqual( 56 | Pip.multiexp([g**i for i in range(order)],[0 for i in range(order)]), G.unit 57 | ) 58 | 59 | def test_zero_ec(self): 60 | CURVE = NIST192p 61 | G = EC(CURVE) 62 | order_cyclic_subgroup = CURVE.order 63 | g = CURVE.generator 64 | Pip = Pippenger(G) 65 | for i in [randint(0,order_cyclic_subgroup) for _ in range(10)]: 66 | with self.subTest(i=i): 67 | self.assertEqual(Pip.multiexp([i*g],[0]), G.unit) 68 | self.assertEqual( 69 | Pip.multiexp([i*g for i in [randint(0,order_cyclic_subgroup) for _ in range(10)]], 70 | [0 for i in range(10)]), 71 | G.unit 72 | ) 73 | 74 | def test_one_int_modp(self): 75 | order, p = 11, 23 76 | G = MultIntModP(p, order) 77 | Pip = Pippenger(G) 78 | g = ModP(3, p) 79 | for i in range(order): 80 | with self.subTest(i=i): 81 | self.assertEqual(Pip.multiexp([g**i],[1]), g**i) 82 | self.assertEqual( 83 | Pip.multiexp([g for i in range(order)],[1 for i in range(order)]), G.unit 84 | ) 85 | 86 | def test_one_ec(self): 87 | CURVE = NIST192p 88 | G = EC(CURVE) 89 | order_cyclic_subgroup = CURVE.order 90 | g = CURVE.generator 91 | Pip = Pippenger(G) 92 | for i in [randint(0,order_cyclic_subgroup) for _ in range(10)]: 93 | with self.subTest(i=i): 94 | self.assertEqual(Pip.multiexp([i*g],[1]), i*g) 95 | self.assertEqual( 96 | Pip.multiexp([g for i in range(10)], [1 for i in range(10)]), 97 | 10*g 98 | ) 99 | 100 | class TestsIntModP(unittest.TestCase): 101 | def test_all_values_of_N(self): 102 | order_cyclic_subgroup, p, gen = get_good_primes(2**32) 103 | G = MultIntModP(p, order_cyclic_subgroup) 104 | Pip = Pippenger(G) 105 | g = ModP(gen, p) 106 | for N in range(order_cyclic_subgroup.bit_length()): 107 | gs = [g**randint(1, order_cyclic_subgroup) for _ in range(N)] 108 | es = [randint(1,order_cyclic_subgroup) for _ in range(N)] 109 | with self.subTest(N=N): 110 | self.assertEqual(Pip.multiexp(gs, es), naive_multi_exp(gs, es, p)) 111 | 112 | def test_all_values_of_p(self): 113 | start = 5 114 | for _ in range(50): 115 | order_cyclic_subgroup, p, gen = get_good_primes(start) 116 | G = MultIntModP(p, order_cyclic_subgroup) 117 | Pip = Pippenger(G) 118 | g = ModP(gen, p) 119 | for N in range(order_cyclic_subgroup.bit_length()): 120 | gs = [g**randint(1, order_cyclic_subgroup) for _ in range(N)] 121 | es = [randint(1,order_cyclic_subgroup) for _ in range(N)] 122 | with self.subTest(N=N, order=order_cyclic_subgroup): 123 | self.assertEqual(Pip.multiexp(gs, es), naive_multi_exp(gs, es,p)) 124 | start = order_cyclic_subgroup + 1 125 | 126 | class TestsEC(unittest.TestCase): 127 | def test_all_values_of_N(self): 128 | CURVE = NIST192p 129 | G = EC(CURVE) 130 | order_cyclic_subgroup = CURVE.order 131 | g = CURVE.generator 132 | Pip = Pippenger(G) 133 | for N in range(0, order_cyclic_subgroup.bit_length(), 20): 134 | gs = [g*randint(1, order_cyclic_subgroup) for _ in range(N)] 135 | es = [randint(1,order_cyclic_subgroup) for _ in range(N)] 136 | with self.subTest(N=N): 137 | self.assertEqual(Pip.multiexp(gs, es), naive_multi_exp_ec(gs, es)) 138 | 139 | def test_all_curves(self): 140 | curves = [SECP256k1, NIST192p, NIST224p, NIST256p, NIST384p, NIST521p] 141 | for curve in curves: 142 | G = EC(curve) 143 | order_cyclic_subgroup = curve.order 144 | g = curve.generator 145 | Pip = Pippenger(G) 146 | for _ in range(2): 147 | N = randint(0, order_cyclic_subgroup.bit_length()) 148 | gs = [g*randint(1, order_cyclic_subgroup) for _ in range(N)] 149 | es = [randint(1,order_cyclic_subgroup) for _ in range(N)] 150 | with self.subTest(curve=curve, N=N): 151 | self.assertEqual(Pip.multiexp(gs, es), naive_multi_exp_ec(gs, es)) 152 | 153 | if __name__ == '__main__': 154 | unittest.main() --------------------------------------------------------------------------------