lightphe 0.0.13__tar.gz → 0.0.14__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. {lightphe-0.0.13 → lightphe-0.0.14}/PKG-INFO +1 -3
  2. {lightphe-0.0.13 → lightphe-0.0.14}/README.md +0 -2
  3. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/__init__.py +1 -1
  4. lightphe-0.0.14/lightphe/standard_curves/edwards.py +144 -0
  5. lightphe-0.0.14/lightphe/standard_curves/inventory.py +83 -0
  6. lightphe-0.0.14/lightphe/standard_curves/koblitz.py +433 -0
  7. lightphe-0.0.14/lightphe/standard_curves/weierstrass.py +936 -0
  8. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe.egg-info/PKG-INFO +1 -3
  9. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe.egg-info/SOURCES.txt +5 -0
  10. {lightphe-0.0.13 → lightphe-0.0.14}/setup.py +1 -1
  11. lightphe-0.0.14/tests/__init__.py +0 -0
  12. {lightphe-0.0.13 → lightphe-0.0.14}/LICENSE +0 -0
  13. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/commons/__init__.py +0 -0
  14. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/commons/binary_operations.py +0 -0
  15. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/commons/logger.py +0 -0
  16. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/commons/phe_utils.py +0 -0
  17. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/cryptosystems/Benaloh.py +0 -0
  18. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/cryptosystems/DamgardJurik.py +0 -0
  19. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/cryptosystems/ElGamal.py +0 -0
  20. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/cryptosystems/EllipticCurveElGamal.py +0 -0
  21. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/cryptosystems/GoldwasserMicali.py +0 -0
  22. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/cryptosystems/NaccacheStern.py +0 -0
  23. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/cryptosystems/OkamotoUchiyama.py +0 -0
  24. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/cryptosystems/Paillier.py +0 -0
  25. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/cryptosystems/RSA.py +0 -0
  26. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/cryptosystems/__init__.py +0 -0
  27. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/elliptic_curve_forms/__init__.py +0 -0
  28. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/elliptic_curve_forms/edwards.py +0 -0
  29. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/elliptic_curve_forms/koblitz.py +0 -0
  30. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/elliptic_curve_forms/weierstrass.py +0 -0
  31. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/models/Algorithm.py +0 -0
  32. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/models/Ciphertext.py +0 -0
  33. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/models/Curve.py +0 -0
  34. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/models/EllipticCurve.py +0 -0
  35. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/models/Homomorphic.py +0 -0
  36. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/models/Tensor.py +0 -0
  37. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe/models/__init__.py +0 -0
  38. {lightphe-0.0.13/tests → lightphe-0.0.14/lightphe/standard_curves}/__init__.py +0 -0
  39. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe.egg-info/dependency_links.txt +0 -0
  40. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe.egg-info/requires.txt +0 -0
  41. {lightphe-0.0.13 → lightphe-0.0.14}/lightphe.egg-info/top_level.txt +0 -0
  42. {lightphe-0.0.13 → lightphe-0.0.14}/requirements.txt +0 -0
  43. {lightphe-0.0.13 → lightphe-0.0.14}/setup.cfg +0 -0
  44. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_benaloh.py +0 -0
  45. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_ciphertexts.py +0 -0
  46. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_cloud.py +0 -0
  47. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_damgard.py +0 -0
  48. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_elgamal.py +0 -0
  49. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_ellipticcurve.py +0 -0
  50. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_ellipticcurveelgamal.py +0 -0
  51. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_exporting_keys.py +0 -0
  52. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_goldwasser.py +0 -0
  53. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_keys.py +0 -0
  54. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_naccache.py +0 -0
  55. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_okamoto.py +0 -0
  56. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_paillier.py +0 -0
  57. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_rsa.py +0 -0
  58. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_salary.py +0 -0
  59. {lightphe-0.0.13 → lightphe-0.0.14}/tests/test_tensors.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightphe
3
- Version: 0.0.13
3
+ Version: 0.0.14
4
4
  Summary: A Lightweight Partially Homomorphic Encryption Library for Python
5
5
  Home-page: https://github.com/serengil/LightPHE
6
6
  Author: Sefik Ilkin Serengil
@@ -23,8 +23,6 @@ License-File: LICENSE
23
23
  [![Tests](https://github.com/serengil/LightPHE/actions/workflows/tests.yml/badge.svg)](https://github.com/serengil/LightPHE/actions/workflows/tests.yml)
24
24
  [![License](http://img.shields.io/:license-MIT-green.svg?style=flat)](https://github.com/serengil/LightPHE/blob/master/LICENSE)
25
25
  [![arXiv](https://img.shields.io/badge/arXiv-2408.05219-b31b1b.svg?logo=arXiv)](https://arxiv.org/abs/2408.05219)
26
- [![Hacker News](https://img.shields.io/badge/dynamic/json?color=orange&label=Hacker%20News&query=score&url=https%3A%2F%2Fhacker-news.firebaseio.com%2Fv0%2Fitem%2F43024283.json&logo=y-combinator)](https://news.ycombinator.com/item?id=43024283)
27
- <!-- [![DOI](http://img.shields.io/:DOI-10.48550/arXiv.2408.05219-blue.svg?style=flat)](https://arxiv.org/abs/2408.05219) -->
28
26
 
29
27
  [![Blog](https://img.shields.io/:blog-sefiks.com-blue.svg?style=flat&logo=wordpress)](https://sefiks.com)
30
28
  [![YouTube](https://img.shields.io/:youtube-@sefiks-red.svg?style=flat&logo=youtube)](https://www.youtube.com/@sefiks?sub_confirmation=1)
@@ -7,8 +7,6 @@
7
7
  [![Tests](https://github.com/serengil/LightPHE/actions/workflows/tests.yml/badge.svg)](https://github.com/serengil/LightPHE/actions/workflows/tests.yml)
8
8
  [![License](http://img.shields.io/:license-MIT-green.svg?style=flat)](https://github.com/serengil/LightPHE/blob/master/LICENSE)
9
9
  [![arXiv](https://img.shields.io/badge/arXiv-2408.05219-b31b1b.svg?logo=arXiv)](https://arxiv.org/abs/2408.05219)
10
- [![Hacker News](https://img.shields.io/badge/dynamic/json?color=orange&label=Hacker%20News&query=score&url=https%3A%2F%2Fhacker-news.firebaseio.com%2Fv0%2Fitem%2F43024283.json&logo=y-combinator)](https://news.ycombinator.com/item?id=43024283)
11
- <!-- [![DOI](http://img.shields.io/:DOI-10.48550/arXiv.2408.05219-blue.svg?style=flat)](https://arxiv.org/abs/2408.05219) -->
12
10
 
13
11
  [![Blog](https://img.shields.io/:blog-sefiks.com-blue.svg?style=flat&logo=wordpress)](https://sefiks.com)
14
12
  [![YouTube](https://img.shields.io/:youtube-@sefiks-red.svg?style=flat&logo=youtube)](https://www.youtube.com/@sefiks?sub_confirmation=1)
@@ -38,7 +38,7 @@ from lightphe.elliptic_curve_forms.koblitz import Koblitz
38
38
 
39
39
  logger = Logger(module="lightphe/__init__.py")
40
40
 
41
- VERSION = "0.0.13"
41
+ VERSION = "0.0.14"
42
42
 
43
43
 
44
44
  class LightPHE:
@@ -0,0 +1,144 @@
1
+ """
2
+ Curves in this class are heavily inspired from
3
+ - https://neuromancer.sk/std/search/
4
+ """
5
+
6
+ # project dependencies
7
+ from lightphe.models.Curve import TwistedEdwardsInterface
8
+ from lightphe.commons.logger import Logger
9
+
10
+ logger = Logger(module="lightphe/standard_curves/edwards.py")
11
+
12
+ DEFAULT_CURVE = "ed25519"
13
+
14
+
15
+ # pylint: disable=too-few-public-methods
16
+ class Ed25519(TwistedEdwardsInterface):
17
+ p = pow(2, 255) - 19
18
+ a = -1
19
+ d = (-121665 * pow(121666, -1, p)) % p
20
+
21
+ u = 9
22
+ g_y = ((u - 1) * pow(u + 1, -1, p)) % p
23
+ g_x = 15112221349535400772501151409588531511454012693041857206046113283949847762202
24
+ G = (g_x, g_y)
25
+
26
+ n = pow(2, 253) + 27742317777372353535851937790883648493
27
+
28
+
29
+ class Ed448(TwistedEdwardsInterface):
30
+ p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
31
+ a = 1
32
+ d = 0xD78B4BDC7F0DAF19F24F38C29373A2CCAD46157242A50F37809B1DA3412A12E79CCC9C81264CFE9AD080997058FB61C4243CC32DBAA156B9
33
+ G = (
34
+ 0x79A70B2B70400553AE7C9DF416C792C61128751AC92969240C25A07D728BDC93E21F7787ED6972249DE732F38496CD11698713093E9C04FC,
35
+ 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000000000000000000000000000001,
36
+ )
37
+ n = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7CCA23E9C44EDB49AED63690216CC2728DC58F552378C292AB5844F3
38
+
39
+
40
+ class E521(TwistedEdwardsInterface):
41
+ p = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
42
+ a = 1
43
+ d = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4331
44
+ G = (
45
+ 0x752CB45C48648B189DF90CB2296B2878A3BFD9F42FC6C818EC8BF3C9C0C6203913F6ECC5CCC72434B1AE949D568FC99C6059D0FB13364838AA302A940A2F19BA6C,
46
+ 0x0C,
47
+ )
48
+ n = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD15B6C64746FC85F736B8AF5E7EC53F04FBD8C4569A8F1F4540EA2435F5180D6B
49
+
50
+
51
+ class Curve41417(TwistedEdwardsInterface):
52
+ p = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF
53
+ a = 0x01
54
+ d = 0xE21
55
+ G = (
56
+ 0x1A334905141443300218C0631C326E5FCD46369F44C03EC7F57FF35498A4AB4D6D6BA111301A73FAA8537C64C4FD3812F3CBC595,
57
+ 0x22,
58
+ )
59
+ n = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB3CC92414CF706022B36F1C0338AD63CF181B0E71A5E106AF79
60
+
61
+
62
+ class JubJub(TwistedEdwardsInterface):
63
+ p = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001
64
+ a = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000000
65
+ d = 0x2A9318E74BFA2B48F5FD9207E6BD7FD4292D7F6D37579D2601065FD6D6343EB1
66
+ G = (
67
+ 0x11DAFE5D23E1218086A365B99FBF3D3BE72F6AFD7D1F72623E6B071492D1122B,
68
+ 0x1D523CF1DDAB1A1793132E78C866C0C33E26BA5CC220FED7CC3F870E59D292AA,
69
+ )
70
+ n = 0xE7DB4EA6533AFA906673B0101343B00A6682093CCC81082D0970E5ED6F72CB7
71
+
72
+
73
+ class MDC201601(TwistedEdwardsInterface):
74
+ p = 0xF13B68B9D456AFB4532F92FDD7A5FD4F086A9037EF07AF9EC13710405779EC13
75
+ a = 1
76
+ d = 0x571304521965B68A7CDFBFCCFB0CB9625F1270F63F21F041EE9309250300CF89
77
+ G = (
78
+ 0xB681886A7F903B83D85B421E03CBCF6350D72ABB8D2713E2232C25BFEE68363B,
79
+ 0xCA6734E1B59C0B0359814DCF6563DA421DA8BC3D81A93A3A7E73C355BD2864B5,
80
+ )
81
+ n = 0x3C4EDA2E7515ABED14CBE4BF75E97F534FB38975FAF974BB588552F421B0F7FB
82
+
83
+
84
+ class Numsp256t1(TwistedEdwardsInterface):
85
+ p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43
86
+ a = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42
87
+ d = 0x3BEE
88
+ G = (0x0D, 0x7D0AB41E2A1276DBA3D330B39FA046BFBE2A6D63824D303F707F6FB5331CADBA)
89
+ n = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE6AA55AD0A6BC64E5B84E6F1122B4AD
90
+
91
+
92
+ class Numsp384t1(TwistedEdwardsInterface):
93
+ p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC3
94
+ a = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC2
95
+ d = 0x5158A
96
+ G = (
97
+ 0x08,
98
+ 0x749CDABA136CE9B65BD4471794AA619DAA5C7B4C930BFF8EBD798A8AE753C6D72F003860FEBABAD534A4ACF5FA7F5BEE,
99
+ )
100
+ n = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFECD7D11ED5A259A25A13A0458E39F4E451D6D71F70426E25
101
+
102
+
103
+ class Numsp512t1(TwistedEdwardsInterface):
104
+ p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7
105
+ a = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC6
106
+ d = 0x9BAA8
107
+ G = (
108
+ 0x20,
109
+ 0x7D67E841DC4C467B605091D80869212F9CEB124BF726973F9FF048779E1D614E62AE2ECE5057B5DAD96B7A897C1D72799261134638750F4F0CB91027543B1C5E,
110
+ )
111
+ n = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7E50809EFDABBB9A624784F449545F0DCEA5FF0CB800F894E78D1CB0B5F0189
112
+
113
+
114
+ class Id_tc26_gost_3410_2012_256_paramSetA(TwistedEdwardsInterface):
115
+ p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97
116
+ a = 0x01
117
+ d = 0x605F6B7C183FA81578BC39CFAD518132B9DF62897009AF7E522C32D6DC7BFFB
118
+ G = (0x0D, 0x60CA1E32AA475B348488C38FAB07649CE7EF8DBE87F22E81F92B2592DBA300E7)
119
+ n = 0x400000000000000000000000000000000FD8CDDFC87B6635C115AF556C360C67
120
+
121
+
122
+ class Id_tc26_gost_3410_2012_512_paramSetC(TwistedEdwardsInterface):
123
+ p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7
124
+ a = 0x01
125
+ d = 0x9E4F5D8C017D8D9F13A5CF3CDF5BFE4DAB402D54198E31EBDE28A0621050439CA6B39E0A515C06B304E2CE43E79E369E91A0CFC2BC2A22B4CA302DBB33EE7550
126
+ G = (
127
+ 0x12,
128
+ 0x469AF79D1FB1F5E16B99592B77A01E2A0FDFB0D01794368D9A56117F7B38669522DD4B650CF789EEBF068C5D139732F0905622C04B2BAAE7600303EE73001A3D,
129
+ )
130
+ n = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC98CDBA46506AB004C33A9FF5147502CC8EDA9E7A769A12694623CEF47F023ED
131
+
132
+
133
+ class Test_Curve(TwistedEdwardsInterface):
134
+ p = 13
135
+ a = 1
136
+ d = 2
137
+ G = (9, 4)
138
+ n = 8
139
+
140
+ def __init__(self):
141
+ logger.warn(
142
+ "edwards test-curve is for development and educational purposes only"
143
+ " and should not be used in production."
144
+ )
@@ -0,0 +1,83 @@
1
+ # built-in dependencies
2
+ from typing import Union, Optional, List
3
+ import inspect
4
+
5
+ # project dependencies
6
+ from lightphe.standard_curves import weierstrass, edwards, koblitz
7
+
8
+ FORM_MODULES = {
9
+ "weierstrass": weierstrass,
10
+ "edwards": edwards,
11
+ "koblitz": koblitz,
12
+ }
13
+
14
+
15
+ def list_curves(form_name: str) -> List[str]:
16
+ """
17
+ Lists the supported curves for a given form
18
+
19
+ Args:
20
+ form_name (str): curve form name
21
+
22
+ Returns:
23
+ List[str]: The list of supported curves
24
+ """
25
+
26
+ if FORM_MODULES.get(form_name) is None:
27
+ raise ValueError(f"Unsupported curve form - {form_name}")
28
+
29
+ module = FORM_MODULES[form_name]
30
+ module_file = inspect.getsourcefile(module)
31
+
32
+ return [
33
+ cls[0].lower().replace("_", "-")
34
+ for cls in inspect.getmembers(module, inspect.isclass)
35
+ if inspect.getsourcefile(cls[1]) == module_file # exclude imported classes
36
+ ]
37
+
38
+
39
+ def build_curve(form_name: str, curve_name: Optional[str] = None) -> Union[
40
+ "weierstrass.WeierstrassInterface",
41
+ "edwards.TwistedEdwardsInterface",
42
+ "koblitz.KoblitzInterface",
43
+ ]:
44
+ """
45
+ Builds a curve arguments based on the form and curve name
46
+
47
+ Args:
48
+ form_name (str): curve form name
49
+ curve_name (str): curve name
50
+
51
+ Returns:
52
+ Union[WeierstrassInterface, TwistedEdwardsInterface, KoblitzInterface]:
53
+ The constructed curve instance
54
+
55
+ Raises:
56
+ ValueError: If the form or curve name is unsupported
57
+ """
58
+
59
+ curve_map = {
60
+ name: {
61
+ cls[0].lower().replace("_", "-"): cls[0]
62
+ for cls in inspect.getmembers(module, inspect.isclass)
63
+ }
64
+ for name, module in FORM_MODULES.items()
65
+ }
66
+
67
+ if form_name not in curve_map:
68
+ raise ValueError(f"Unsupported curve form - {form_name}")
69
+
70
+ if curve_name is None:
71
+ module = FORM_MODULES[form_name]
72
+ curve_name = getattr(module, "DEFAULT_CURVE", None)
73
+ if curve_name is None:
74
+ raise ValueError(f"Default curve not defined for {form_name}")
75
+
76
+ if curve_name not in curve_map[form_name]:
77
+ raise ValueError(f"Unsupported {form_name} curve - {curve_name}")
78
+
79
+ curve_class_name = curve_map[form_name][curve_name]
80
+ module = FORM_MODULES[form_name]
81
+ curve_class = getattr(module, curve_class_name)
82
+
83
+ return curve_class()