aboutsummaryrefslogtreecommitdiff
path: root/frozen_deps/ecdsa/eddsa.py
diff options
context:
space:
mode:
Diffstat (limited to 'frozen_deps/ecdsa/eddsa.py')
-rw-r--r--frozen_deps/ecdsa/eddsa.py252
1 files changed, 252 insertions, 0 deletions
diff --git a/frozen_deps/ecdsa/eddsa.py b/frozen_deps/ecdsa/eddsa.py
new file mode 100644
index 0000000..9769cfd
--- /dev/null
+++ b/frozen_deps/ecdsa/eddsa.py
@@ -0,0 +1,252 @@
+"""Implementation of Edwards Digital Signature Algorithm."""
+
+import hashlib
+from ._sha3 import shake_256
+from . import ellipticcurve
+from ._compat import (
+ remove_whitespace,
+ bit_length,
+ bytes_to_int,
+ int_to_bytes,
+ compat26_str,
+)
+
+# edwards25519, defined in RFC7748
+_p = 2**255 - 19
+_a = -1
+_d = int(
+ remove_whitespace(
+ "370957059346694393431380835087545651895421138798432190163887855330"
+ "85940283555"
+ )
+)
+_h = 8
+
+_Gx = int(
+ remove_whitespace(
+ "151122213495354007725011514095885315114540126930418572060461132"
+ "83949847762202"
+ )
+)
+_Gy = int(
+ remove_whitespace(
+ "463168356949264781694283940034751631413079938662562256157830336"
+ "03165251855960"
+ )
+)
+_r = 2**252 + 0x14DEF9DEA2F79CD65812631A5CF5D3ED
+
+
+def _sha512(data):
+ return hashlib.new("sha512", compat26_str(data)).digest()
+
+
+curve_ed25519 = ellipticcurve.CurveEdTw(_p, _a, _d, _h, _sha512)
+generator_ed25519 = ellipticcurve.PointEdwards(
+ curve_ed25519, _Gx, _Gy, 1, _Gx * _Gy % _p, _r, generator=True
+)
+
+
+# edwards448, defined in RFC7748
+_p = 2**448 - 2**224 - 1
+_a = 1
+_d = -39081 % _p
+_h = 4
+
+_Gx = int(
+ remove_whitespace(
+ "224580040295924300187604334099896036246789641632564134246125461"
+ "686950415467406032909029192869357953282578032075146446173674602635"
+ "247710"
+ )
+)
+_Gy = int(
+ remove_whitespace(
+ "298819210078481492676017930443930673437544040154080242095928241"
+ "372331506189835876003536878655418784733982303233503462500531545062"
+ "832660"
+ )
+)
+_r = 2**446 - 0x8335DC163BB124B65129C96FDE933D8D723A70AADC873D6D54A7BB0D
+
+
+def _shake256(data):
+ return shake_256(data, 114)
+
+
+curve_ed448 = ellipticcurve.CurveEdTw(_p, _a, _d, _h, _shake256)
+generator_ed448 = ellipticcurve.PointEdwards(
+ curve_ed448, _Gx, _Gy, 1, _Gx * _Gy % _p, _r, generator=True
+)
+
+
+class PublicKey(object):
+ """Public key for the Edwards Digital Signature Algorithm."""
+
+ def __init__(self, generator, public_key, public_point=None):
+ self.generator = generator
+ self.curve = generator.curve()
+ self.__encoded = public_key
+ # plus one for the sign bit and round up
+ self.baselen = (bit_length(self.curve.p()) + 1 + 7) // 8
+ if len(public_key) != self.baselen:
+ raise ValueError(
+ "Incorrect size of the public key, expected: {0} bytes".format(
+ self.baselen
+ )
+ )
+ if public_point:
+ self.__point = public_point
+ else:
+ self.__point = ellipticcurve.PointEdwards.from_bytes(
+ self.curve, public_key
+ )
+
+ def __eq__(self, other):
+ if isinstance(other, PublicKey):
+ return (
+ self.curve == other.curve and self.__encoded == other.__encoded
+ )
+ return NotImplemented
+
+ def __ne__(self, other):
+ return not self == other
+
+ @property
+ def point(self):
+ return self.__point
+
+ @point.setter
+ def point(self, other):
+ if self.__point != other:
+ raise ValueError("Can't change the coordinates of the point")
+ self.__point = other
+
+ def public_point(self):
+ return self.__point
+
+ def public_key(self):
+ return self.__encoded
+
+ def verify(self, data, signature):
+ """Verify a Pure EdDSA signature over data."""
+ data = compat26_str(data)
+ if len(signature) != 2 * self.baselen:
+ raise ValueError(
+ "Invalid signature length, expected: {0} bytes".format(
+ 2 * self.baselen
+ )
+ )
+ R = ellipticcurve.PointEdwards.from_bytes(
+ self.curve, signature[: self.baselen]
+ )
+ S = bytes_to_int(signature[self.baselen :], "little")
+ if S >= self.generator.order():
+ raise ValueError("Invalid signature")
+
+ dom = bytearray()
+ if self.curve == curve_ed448:
+ dom = bytearray(b"SigEd448" + b"\x00\x00")
+
+ k = bytes_to_int(
+ self.curve.hash_func(dom + R.to_bytes() + self.__encoded + data),
+ "little",
+ )
+
+ if self.generator * S != self.__point * k + R:
+ raise ValueError("Invalid signature")
+
+ return True
+
+
+class PrivateKey(object):
+ """Private key for the Edwards Digital Signature Algorithm."""
+
+ def __init__(self, generator, private_key):
+ self.generator = generator
+ self.curve = generator.curve()
+ # plus one for the sign bit and round up
+ self.baselen = (bit_length(self.curve.p()) + 1 + 7) // 8
+ if len(private_key) != self.baselen:
+ raise ValueError(
+ "Incorrect size of private key, expected: {0} bytes".format(
+ self.baselen
+ )
+ )
+ self.__private_key = bytes(private_key)
+ self.__h = bytearray(self.curve.hash_func(private_key))
+ self.__public_key = None
+
+ a = self.__h[: self.baselen]
+ a = self._key_prune(a)
+ scalar = bytes_to_int(a, "little")
+ self.__s = scalar
+
+ @property
+ def private_key(self):
+ return self.__private_key
+
+ def __eq__(self, other):
+ if isinstance(other, PrivateKey):
+ return (
+ self.curve == other.curve
+ and self.__private_key == other.__private_key
+ )
+ return NotImplemented
+
+ def __ne__(self, other):
+ return not self == other
+
+ def _key_prune(self, key):
+ # make sure the key is not in a small subgroup
+ h = self.curve.cofactor()
+ if h == 4:
+ h_log = 2
+ elif h == 8:
+ h_log = 3
+ else:
+ raise ValueError("Only cofactor 4 and 8 curves supported")
+ key[0] &= ~((1 << h_log) - 1)
+
+ # ensure the highest bit is set but no higher
+ l = bit_length(self.curve.p())
+ if l % 8 == 0:
+ key[-1] = 0
+ key[-2] |= 0x80
+ else:
+ key[-1] = key[-1] & (1 << (l % 8)) - 1 | 1 << (l % 8) - 1
+ return key
+
+ def public_key(self):
+ """Generate the public key based on the included private key"""
+ if self.__public_key:
+ return self.__public_key
+
+ public_point = self.generator * self.__s
+
+ self.__public_key = PublicKey(
+ self.generator, public_point.to_bytes(), public_point
+ )
+
+ return self.__public_key
+
+ def sign(self, data):
+ """Perform a Pure EdDSA signature over data."""
+ data = compat26_str(data)
+ A = self.public_key().public_key()
+
+ prefix = self.__h[self.baselen :]
+
+ dom = bytearray()
+ if self.curve == curve_ed448:
+ dom = bytearray(b"SigEd448" + b"\x00\x00")
+
+ r = bytes_to_int(self.curve.hash_func(dom + prefix + data), "little")
+ R = (self.generator * r).to_bytes()
+
+ k = bytes_to_int(self.curve.hash_func(dom + R + A + data), "little")
+ k %= self.generator.order()
+
+ S = (r + k * self.__s) % self.generator.order()
+
+ return R + int_to_bytes(S, self.baselen, "little")