py_ecc
py_ecc copied to clipboard
Test failures on Python 3.12
What happened?
When running pytest
on Python 3.12 a bunch of tests fail with
RecursionError: maximum recursion depth exceeded
which seems to stem from
AttributeError("'bls12_381_FQ12' object has no attribute 'coeffs'") raised in repr()
Code that produced the error
No response
Full error output
No response
Fill this section in if you know how this could or should be fixed
No response
py-ecc Version
7.0.0
Python Version
3.12.2
Operating System
Linux
Output from pip freeze
No response
I have the same issue while pairing
two points using py_ecc.bn128
with the following setup:
py-ecc Version
7.0.1
Python Version
3.12.0
Operating System
macOS Sonoma 14.5, Apple M1 Pro
When switching to [email protected]
it worked fine
I've just passed all tests locally with py==3.12.3
and py_ecc==7.0.1
on Linux. Could you post the code that's giving the error?
@pacrob this is my code:
from py_ecc.bn128 import G1, G2, pairing, multiply
pairing(G2, G1)
Python version: 3.12.2
py-ecc version: 7.0.1
This is the whole error trace
---------------------------------------------------------------------------
RecursionError Traceback (most recent call last)
Cell In[16], line 13
10 C = multiply(G2, 5 * 6)
11 # D = multiply(G1, 5 * 6)
---> 13 pairing(G2, G1)
File [~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/bn128/bn128_pairing.py:106](http://localhost:8888/lab/tree/~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/bn128/bn128_pairing.py#line=105), in pairing(Q, P)
104 assert is_on_curve(Q, b2)
105 assert is_on_curve(P, b)
--> 106 return miller_loop(twist(Q), cast_point_to_fq12(P))
File [~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/bn128/bn128_pairing.py:99](http://localhost:8888/lab/tree/~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/bn128/bn128_pairing.py#line=98), in miller_loop(Q, P)
97 f = f * linefunc(R, nQ2, P)
98 # R = add(R, nQ2) This line is in many specifications but technically does nothing
---> 99 return f ** ((field_modulus**12 - 1) // curve_order)
File ~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py:276, in FQP.__pow__(self, other)
274 return type(self)(self.coeffs)
275 elif other % 2 == 0:
--> 276 return (self * self) ** (other // 2)
277 else:
278 return ((self * self) ** int(other // 2)) * self
File [~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py:276](http://localhost:8888/lab/tree/~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py#line=275), in FQP.__pow__(self, other)
274 return type(self)(self.coeffs)
275 elif other % 2 == 0:
--> 276 return (self * self) ** (other // 2)
277 else:
278 return ((self * self) ** int(other // 2)) * self
[... skipping similar frames: FQP.__pow__ at line 276 (3 times)]
File [~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py:278](http://localhost:8888/lab/tree/~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py#line=277), in FQP.__pow__(self, other)
276 return (self * self) ** (other // 2)
277 else:
--> 278 return ((self * self) ** int(other // 2)) * self
[... skipping similar frames: FQP.__pow__ at line 276 (2 times)]
File [~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py:278](http://localhost:8888/lab/tree/~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py#line=277), in FQP.__pow__(self, other)
276 return (self * self) ** (other // 2)
277 else:
--> 278 return ((self * self) ** int(other // 2)) * self
[... skipping similar frames: FQP.__pow__ at line 276 (368 times), FQP.__pow__ at line 278 (359 times)]
File [~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py:278](http://localhost:8888/lab/tree/~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py#line=277), in FQP.__pow__(self, other)
276 return (self * self) ** (other // 2)
277 else:
--> 278 return ((self * self) ** int(other // 2)) * self
File [~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py:276](http://localhost:8888/lab/tree/~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py#line=275), in FQP.__pow__(self, other)
274 return type(self)(self.coeffs)
275 elif other % 2 == 0:
--> 276 return (self * self) ** (other // 2)
277 else:
278 return ((self * self) ** int(other // 2)) * self
File [~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py:246](http://localhost:8888/lab/tree/~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py#line=245), in FQP.__mul__(self, other)
242 for i in range(self.degree):
243 b[exp + i] -= top * self.FQP_corresponding_FQ_class(
244 self.modulus_coeffs[i]
245 )
--> 246 return type(self)(b)
247 else:
248 raise TypeError(
249 "Expected an int or FQ object or FQP object, "
250 f"but got object of type {type(other)}"
251 )
File [~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py:374](http://localhost:8888/lab/tree/~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py#line=373), in FQ12.__init__(self, coeffs)
371 if self.FQ12_MODULUS_COEFFS is None:
372 raise AttributeError("FQ12 Modulus Coeffs haven't been specified")
--> 374 super().__init__(coeffs, self.FQ12_MODULUS_COEFFS)
File [~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py:208](http://localhost:8888/lab/tree/~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py#line=207), in FQP.__init__(self, coeffs, modulus_coeffs)
204 # Encoding all coefficients in the corresponding type FQ
205 self.FQP_corresponding_FQ_class = type(
206 "FQP_corresponding_FQ_class", (FQ,), {"field_modulus": self.field_modulus}
207 ) # type: Type[FQ]
--> 208 self.coeffs = tuple(
209 self.FQP_corresponding_FQ_class(c) for c in coeffs
210 ) # type: Tuple[IntOrFQ, ...]
211 # The coefficients of the modulus, without the leading [1]
212 self.modulus_coeffs = tuple(modulus_coeffs) # type: Tuple[IntOrFQ, ...]
File [~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py:209](http://localhost:8888/lab/tree/~/.pyenv/versions/miniconda3-latest/lib/python3.12/site-packages/py_ecc/fields/field_elements.py#line=208), in <genexpr>(.0)
204 # Encoding all coefficients in the corresponding type FQ
205 self.FQP_corresponding_FQ_class = type(
206 "FQP_corresponding_FQ_class", (FQ,), {"field_modulus": self.field_modulus}
207 ) # type: Type[FQ]
208 self.coeffs = tuple(
--> 209 self.FQP_corresponding_FQ_class(c) for c in coeffs
210 ) # type: Tuple[IntOrFQ, ...]
211 # The coefficients of the modulus, without the leading [1]
212 self.modulus_coeffs = tuple(modulus_coeffs) # type: Tuple[IntOrFQ, ...]
RecursionError: maximum recursion depth exceeded
@pacrob, same as @jimmychu0807:
from py_ecc.bn128 import G1, G2, pairing
pairing(G2, G1)
Please, refer to this comment for additional system information.
I've tried it locally with py3.12.3, 3.12.2, and 3.12.1, and had a colleague check with 3.12.3 on a mac M3, everything working fine.
In [1]: from py_ecc.bn128 import G1, G2, pairing
...:
...: pairing(G2, G1)
Out[1]: (18443897754565973717256850119554731228214108935025491924036055734000366132575, 10734401203193558706037776473742910696504851986739882094082017010340198538454, 5985796159921227033560968606339653189163760772067273492369082490994528765680, 4093294155816392700623820137842432921872230622290337094591654151434545306688, 642121370160833232766181493494955044074321385528883791668868426879070103434, 4527449849947601357037044178952942489926487071653896435602814872334098625391, 3758435817766288188804561253838670030762970764366672594784247447067868088068, 18059168546148152671857026372711724379319778306792011146784665080987064164612, 14656606573936501743457633041048024656612227301473084805627390748872617280984, 17918828665069491344039743589118342552553375221610735811112289083834142789347, 19455424343576886430889849773367397946457449073528455097210946839000147698372, 7484542354754424633621663080190936924481536615300815203692506276894207018007)
In [2]: import sys
In [3]: print(sys.getrecursionlimit())
100000
What's your recursion limit set to? I can actually replicate if I set my recursion limit to 2500, works again at 3000. Maybe the default was higher in your 3.10 install than in your 3.12?
My default recursion limit is 1000. I changed it to very high numbers to rule out the possibility, but it still fails with the same error.
@pacrob sigh, mystery of life 🤷🏻 ...
This is what I get when running in Python 3.10
This is what I get when running in Python 3.12