lightecc 0.0.1__py3-none-any.whl

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.
lightecc/__init__.py ADDED
@@ -0,0 +1,55 @@
1
+ # built-in dependencies
2
+ from typing import Optional
3
+
4
+ # project dependencies
5
+ from lightecc.forms.weierstrass import Weierstrass
6
+ from lightecc.forms.edwards import TwistedEdwards
7
+ from lightecc.forms.koblitz import Koblitz
8
+ from lightecc.interfaces.elliptic_curve import EllipticCurvePoint
9
+ from lightecc.commons.logger import Logger
10
+
11
+ logger = Logger(module="lightecc/__init__.py")
12
+
13
+ VERSION = "0.0.1"
14
+
15
+
16
+ # pylint: disable=too-few-public-methods
17
+ class LightECC:
18
+ __version__ = VERSION
19
+
20
+ def __init__(
21
+ self, form_name: Optional[str] = None, curve_name: Optional[str] = None
22
+ ):
23
+ """
24
+ Construct an Elliptic Curve over a finite field (prime or binary)
25
+ Args:
26
+ form_name (str): specifies the form of the elliptic curve.
27
+ Options: 'weierstrass' (default), 'edwards', 'koblitz'.
28
+ curve_name (str): specifies the elliptic curve to use.
29
+ Options:
30
+ - e.g. ed25519, ed448 for edwards form
31
+ - e.g. secp256k1 for weierstrass form
32
+ - e.g. k-409 for koblitz form
33
+ List of all available curves:
34
+ github.com/serengil/LightECC
35
+ """
36
+ if form_name is None or form_name == "weierstrass":
37
+ self.curve = Weierstrass(curve=curve_name)
38
+ elif form_name in "edwards":
39
+ self.curve = TwistedEdwards(curve=curve_name)
40
+ elif form_name in "koblitz":
41
+ self.curve = Koblitz(curve=curve_name)
42
+ else:
43
+ raise ValueError(f"unimplemented curve form - {form_name}")
44
+
45
+ # base point
46
+ self.G = EllipticCurvePoint(self.curve.G[0], self.curve.G[1], self.curve)
47
+
48
+ # order of the curve
49
+ self.n = self.curve.n
50
+
51
+ # point at infinity or neutral / identity element
52
+ self.O = EllipticCurvePoint(self.curve.O[0], self.curve.O[1], self.curve)
53
+
54
+ # modulo
55
+ self.modulo = self.curve.modulo
File without changes
@@ -0,0 +1,147 @@
1
+ """
2
+ This module is heavily inspired by repo github.com/dimitrijray/ecc-binary-field/blob/master/binop.py
3
+ """
4
+
5
+
6
+ def divide(a: int, b: int, p: int) -> int:
7
+ """
8
+ Returns a_bin * (b_bin)^-1 (mod p)
9
+ Args:
10
+ a (int): nominator
11
+ b (int): denominator
12
+ p (int): modulo
13
+ Returns:
14
+ result (int): (a_bin * (b_bin)^-1 (mod p)) mod p
15
+ """
16
+ result = mod(multi(a, inverse(b, p)), p)
17
+ return result
18
+
19
+
20
+ def multi(a: int, b: int) -> int:
21
+ """
22
+ Multiply two binary numbers in GF(2).
23
+ Args:
24
+ a (int): first number
25
+ b (int): second number
26
+ Returns:
27
+ result (int): carry-less multiplication between a and b
28
+ """
29
+ result = 0
30
+ shift = 0
31
+
32
+ while b > 0:
33
+ if b & 1: # Check if the least significant bit of b is 1
34
+ result ^= a << shift
35
+ shift += 1
36
+ b >>= 1 # Shift b to the right by 1
37
+
38
+ return result
39
+
40
+
41
+ def power_mod(num: int, exp: int, modulo: int) -> int:
42
+ """
43
+ Calculate num^exp (mod m) in GF(2).
44
+ Args:
45
+ num (int): base
46
+ exp (int): exponent
47
+ modulo (int): modulo
48
+ Returns:
49
+ result (int): num^exp (mod m)
50
+ """
51
+ result = 1
52
+ base = num % modulo
53
+
54
+ while exp > 0:
55
+ if exp & 1: # Check if the least significant bit of exp is 1
56
+ result = multi(base, result) # multiply result by base
57
+ result = mod(result, modulo) # apply modulo
58
+
59
+ base = square(base) # square the base
60
+ exp >>= 1 # right shift exp by 1
61
+
62
+ return result
63
+
64
+
65
+ def square(num: int) -> int:
66
+ """
67
+ Square a binary number in GF(2).
68
+ Args:
69
+ num (int): number
70
+ Returns:
71
+ result (int): square of num
72
+ """
73
+ result = 0
74
+ shift = 0
75
+
76
+ while num > 0:
77
+ if num & 1: # Check if the least significant bit of num is 1
78
+ result ^= 1 << (2 * shift) # Set the appropriate bit in the result
79
+
80
+ num >>= 1 # Right shift num by 1
81
+ shift += 1
82
+
83
+ return result
84
+
85
+
86
+ def mod(num: int, modulo: int) -> int:
87
+ """
88
+ Perform modulo operation for binary numbers in GF(2).
89
+ Args:
90
+ num (int): number
91
+ modulo (int): modulo
92
+ Returns:
93
+ result (int): num mod modulo
94
+ """
95
+ degP = num.bit_length() - 1
96
+ degR = modulo.bit_length() - 1
97
+
98
+ while degP >= degR and degR != 0:
99
+ shift = degP - degR
100
+ num ^= modulo << shift # Perform XOR to reduce the degree of num
101
+ degP = num.bit_length() - 1 # Update the degree of num
102
+
103
+ return num
104
+
105
+
106
+ def div(num: int, modulo: int) -> int:
107
+ """
108
+ Return the quotient of the polynomial division num / modulo in GF(2).
109
+ Args:
110
+ num (int): numerator
111
+ modulo (int): denominator
112
+ Returns:
113
+ result (int): quotient
114
+ """
115
+ deg_p = num.bit_length() - 1
116
+ deg_r = modulo.bit_length() - 1
117
+ q = 0
118
+
119
+ while deg_p >= deg_r:
120
+ shift = deg_p - deg_r
121
+ q |= 1 << shift # Set the corresponding bit in the quotient
122
+ num ^= modulo << shift # Perform XOR to reduce the degree of num
123
+ deg_p = num.bit_length() - 1 # Update the degree of num
124
+
125
+ return q
126
+
127
+
128
+ def inverse(num: int, modulo: int) -> int:
129
+ """
130
+ Calculate the inverse of a binary number modulo a polynomial in GF(2).
131
+ Args:
132
+ num (int): number
133
+ modulo (int): modulo
134
+ Returns:
135
+ result (int): inverse of num mod modulo
136
+ """
137
+ a, b = num, modulo
138
+ p1, p2 = 1, 0
139
+
140
+ while b != 1:
141
+ q = div(a, b)
142
+ r = mod(a, b)
143
+ a, b = b, r
144
+ p_a = p1 ^ multi(q, p2)
145
+ p1, p2 = p2, p_a
146
+
147
+ return p2
@@ -0,0 +1,42 @@
1
+ import os
2
+ import logging
3
+ from datetime import datetime
4
+
5
+ # pylint: disable=broad-except
6
+
7
+
8
+ class Logger:
9
+ def __init__(self, module):
10
+ self.module = module
11
+ log_level = os.environ.get("LIGHTECC_LOG_LEVEL", str(logging.INFO))
12
+ try:
13
+ self.log_level = int(log_level)
14
+ except Exception as err:
15
+ self.dump_log(
16
+ f"Exception while parsing $LIGHTECC_LOG_LEVEL."
17
+ f"Expected int but it is {log_level} ({str(err)})"
18
+ )
19
+ self.log_level = logging.INFO
20
+
21
+ def info(self, message):
22
+ if self.log_level <= logging.INFO:
23
+ self.dump_log(message)
24
+
25
+ def debug(self, message):
26
+ if self.log_level <= logging.DEBUG:
27
+ self.dump_log(f"🕷️ {message}")
28
+
29
+ def warn(self, message):
30
+ if self.log_level <= logging.WARNING:
31
+ self.dump_log(f"⚠️ {message}")
32
+
33
+ def error(self, message):
34
+ if self.log_level <= logging.ERROR:
35
+ self.dump_log(f"🔴 {message}")
36
+
37
+ def critical(self, message):
38
+ if self.log_level <= logging.CRITICAL:
39
+ self.dump_log(f"💥 {message}")
40
+
41
+ def dump_log(self, message):
42
+ print(f"{str(datetime.now())[2:-7]} - {message}")
File without changes
@@ -0,0 +1,139 @@
1
+ # project dependencies
2
+ from lightecc.interfaces.form import TwistedEdwardsInterface
3
+ from lightecc.commons.logger import Logger
4
+
5
+ logger = Logger(module="lightecc/curves/edwards.py")
6
+
7
+ DEFAULT_CURVE = "ed25519"
8
+
9
+
10
+ # pylint: disable=too-few-public-methods
11
+ class Ed25519(TwistedEdwardsInterface):
12
+ p = pow(2, 255) - 19
13
+ a = -1
14
+ d = (-121665 * pow(121666, -1, p)) % p
15
+
16
+ u = 9
17
+ g_y = ((u - 1) * pow(u + 1, -1, p)) % p
18
+ g_x = 15112221349535400772501151409588531511454012693041857206046113283949847762202
19
+ G = (g_x, g_y)
20
+
21
+ n = pow(2, 253) + 27742317777372353535851937790883648493
22
+
23
+
24
+ class Ed448(TwistedEdwardsInterface):
25
+ p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
26
+ a = 1
27
+ d = 0xD78B4BDC7F0DAF19F24F38C29373A2CCAD46157242A50F37809B1DA3412A12E79CCC9C81264CFE9AD080997058FB61C4243CC32DBAA156B9
28
+ G = (
29
+ 0x79A70B2B70400553AE7C9DF416C792C61128751AC92969240C25A07D728BDC93E21F7787ED6972249DE732F38496CD11698713093E9C04FC,
30
+ 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000000000000000000000000000001,
31
+ )
32
+ n = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7CCA23E9C44EDB49AED63690216CC2728DC58F552378C292AB5844F3
33
+
34
+
35
+ class E521(TwistedEdwardsInterface):
36
+ p = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
37
+ a = 1
38
+ d = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4331
39
+ G = (
40
+ 0x752CB45C48648B189DF90CB2296B2878A3BFD9F42FC6C818EC8BF3C9C0C6203913F6ECC5CCC72434B1AE949D568FC99C6059D0FB13364838AA302A940A2F19BA6C,
41
+ 0x0C,
42
+ )
43
+ n = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD15B6C64746FC85F736B8AF5E7EC53F04FBD8C4569A8F1F4540EA2435F5180D6B
44
+
45
+
46
+ class Curve41417(TwistedEdwardsInterface):
47
+ p = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF
48
+ a = 0x01
49
+ d = 0xE21
50
+ G = (
51
+ 0x1A334905141443300218C0631C326E5FCD46369F44C03EC7F57FF35498A4AB4D6D6BA111301A73FAA8537C64C4FD3812F3CBC595,
52
+ 0x22,
53
+ )
54
+ n = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB3CC92414CF706022B36F1C0338AD63CF181B0E71A5E106AF79
55
+
56
+
57
+ class JubJub(TwistedEdwardsInterface):
58
+ p = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001
59
+ a = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000000
60
+ d = 0x2A9318E74BFA2B48F5FD9207E6BD7FD4292D7F6D37579D2601065FD6D6343EB1
61
+ G = (
62
+ 0x11DAFE5D23E1218086A365B99FBF3D3BE72F6AFD7D1F72623E6B071492D1122B,
63
+ 0x1D523CF1DDAB1A1793132E78C866C0C33E26BA5CC220FED7CC3F870E59D292AA,
64
+ )
65
+ n = 0xE7DB4EA6533AFA906673B0101343B00A6682093CCC81082D0970E5ED6F72CB7
66
+
67
+
68
+ class MDC201601(TwistedEdwardsInterface):
69
+ p = 0xF13B68B9D456AFB4532F92FDD7A5FD4F086A9037EF07AF9EC13710405779EC13
70
+ a = 1
71
+ d = 0x571304521965B68A7CDFBFCCFB0CB9625F1270F63F21F041EE9309250300CF89
72
+ G = (
73
+ 0xB681886A7F903B83D85B421E03CBCF6350D72ABB8D2713E2232C25BFEE68363B,
74
+ 0xCA6734E1B59C0B0359814DCF6563DA421DA8BC3D81A93A3A7E73C355BD2864B5,
75
+ )
76
+ n = 0x3C4EDA2E7515ABED14CBE4BF75E97F534FB38975FAF974BB588552F421B0F7FB
77
+
78
+
79
+ class Numsp256t1(TwistedEdwardsInterface):
80
+ p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43
81
+ a = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42
82
+ d = 0x3BEE
83
+ G = (0x0D, 0x7D0AB41E2A1276DBA3D330B39FA046BFBE2A6D63824D303F707F6FB5331CADBA)
84
+ n = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE6AA55AD0A6BC64E5B84E6F1122B4AD
85
+
86
+
87
+ class Numsp384t1(TwistedEdwardsInterface):
88
+ p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC3
89
+ a = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC2
90
+ d = 0x5158A
91
+ G = (
92
+ 0x08,
93
+ 0x749CDABA136CE9B65BD4471794AA619DAA5C7B4C930BFF8EBD798A8AE753C6D72F003860FEBABAD534A4ACF5FA7F5BEE,
94
+ )
95
+ n = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFECD7D11ED5A259A25A13A0458E39F4E451D6D71F70426E25
96
+
97
+
98
+ class Numsp512t1(TwistedEdwardsInterface):
99
+ p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7
100
+ a = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC6
101
+ d = 0x9BAA8
102
+ G = (
103
+ 0x20,
104
+ 0x7D67E841DC4C467B605091D80869212F9CEB124BF726973F9FF048779E1D614E62AE2ECE5057B5DAD96B7A897C1D72799261134638750F4F0CB91027543B1C5E,
105
+ )
106
+ n = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7E50809EFDABBB9A624784F449545F0DCEA5FF0CB800F894E78D1CB0B5F0189
107
+
108
+
109
+ class Id_tc26_gost_3410_2012_256_paramSetA(TwistedEdwardsInterface):
110
+ p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97
111
+ a = 0x01
112
+ d = 0x605F6B7C183FA81578BC39CFAD518132B9DF62897009AF7E522C32D6DC7BFFB
113
+ G = (0x0D, 0x60CA1E32AA475B348488C38FAB07649CE7EF8DBE87F22E81F92B2592DBA300E7)
114
+ n = 0x400000000000000000000000000000000FD8CDDFC87B6635C115AF556C360C67
115
+
116
+
117
+ class Id_tc26_gost_3410_2012_512_paramSetC(TwistedEdwardsInterface):
118
+ p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7
119
+ a = 0x01
120
+ d = 0x9E4F5D8C017D8D9F13A5CF3CDF5BFE4DAB402D54198E31EBDE28A0621050439CA6B39E0A515C06B304E2CE43E79E369E91A0CFC2BC2A22B4CA302DBB33EE7550
121
+ G = (
122
+ 0x12,
123
+ 0x469AF79D1FB1F5E16B99592B77A01E2A0FDFB0D01794368D9A56117F7B38669522DD4B650CF789EEBF068C5D139732F0905622C04B2BAAE7600303EE73001A3D,
124
+ )
125
+ n = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC98CDBA46506AB004C33A9FF5147502CC8EDA9E7A769A12694623CEF47F023ED
126
+
127
+
128
+ class Test_Curve(TwistedEdwardsInterface):
129
+ p = 13
130
+ a = 1
131
+ d = 2
132
+ G = (9, 4)
133
+ n = 8
134
+
135
+ def __init__(self):
136
+ logger.warn(
137
+ "edwards test-curve is for development and educational purposes only"
138
+ " and should not be used in production."
139
+ )
@@ -0,0 +1,83 @@
1
+ # built-in dependencies
2
+ from typing import Union, Optional, List
3
+ import inspect
4
+
5
+ # project dependencies
6
+ from lightecc.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()