py_ecc icon indicating copy to clipboard operation
py_ecc copied to clipboard

Test failures on Python 3.12

Open dotlambda opened this issue 1 year ago • 7 comments

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

dotlambda avatar Feb 23 '24 23:02 dotlambda

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

cre-mer avatar Jun 20 '24 09:06 cre-mer

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 avatar Jun 26 '24 21:06 pacrob

@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

jimmychu0807 avatar Jul 12 '24 04:07 jimmychu0807

@pacrob, same as @jimmychu0807:

from py_ecc.bn128 import G1, G2, pairing

pairing(G2, G1)

Please, refer to this comment for additional system information.

cre-mer avatar Jul 15 '24 11:07 cre-mer

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?

pacrob avatar Jul 15 '24 20:07 pacrob

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.

cre-mer avatar Jul 17 '24 07:07 cre-mer

@pacrob sigh, mystery of life 🤷🏻 ...

This is what I get when running in Python 3.10

Screenshot 2024-07-18 at 12 39 55

This is what I get when running in Python 3.12

Screenshot 2024-07-18 at 12 39 03

jimmychu0807 avatar Jul 18 '24 04:07 jimmychu0807