summaryrefslogtreecommitdiff
path: root/src/pycryptopp/publickey/ed25519
diff options
context:
space:
mode:
Diffstat (limited to 'src/pycryptopp/publickey/ed25519')
-rw-r--r--src/pycryptopp/publickey/ed25519/__init__.py7
-rw-r--r--src/pycryptopp/publickey/ed25519/_version.py11
-rw-r--r--src/pycryptopp/publickey/ed25519/keys.py70
3 files changed, 88 insertions, 0 deletions
diff --git a/src/pycryptopp/publickey/ed25519/__init__.py b/src/pycryptopp/publickey/ed25519/__init__.py
new file mode 100644
index 0000000..f399769
--- /dev/null
+++ b/src/pycryptopp/publickey/ed25519/__init__.py
@@ -0,0 +1,7 @@
+from keys import (BadSignatureError, SigningKey, VerifyingKey)
+
+(BadSignatureError, SigningKey, VerifyingKey) # hush pyflakes
+
+from _version import get_versions
+__version__ = get_versions()['version']
+del get_versions
diff --git a/src/pycryptopp/publickey/ed25519/_version.py b/src/pycryptopp/publickey/ed25519/_version.py
new file mode 100644
index 0000000..e1d12a1
--- /dev/null
+++ b/src/pycryptopp/publickey/ed25519/_version.py
@@ -0,0 +1,11 @@
+
+# This file was generated by 'versioneer.py' (0.7) from
+# revision-control system data, or from the parent directory name of an
+# unpacked source archive. Distribution tarballs contain a pre-generated copy
+# of this file.
+
+version_version = '1.0'
+version_full = '519b740ca2c67f0ba4c2758ed1c17f11df561ee7'
+def get_versions(default={}, verbose=False):
+ return {'version': version_version, 'full': version_full}
+
diff --git a/src/pycryptopp/publickey/ed25519/keys.py b/src/pycryptopp/publickey/ed25519/keys.py
new file mode 100644
index 0000000..5d7eafb
--- /dev/null
+++ b/src/pycryptopp/publickey/ed25519/keys.py
@@ -0,0 +1,70 @@
+import _ed25519
+BadSignatureError = _ed25519.BadSignatureError
+
+class SigningKey(object):
+ # this is how all keys are created
+ def __init__(self, sk_bytes):
+ if not isinstance(sk_bytes, type("")):
+ raise TypeError("must be bytes, not %s" % type(sk_bytes))
+ if len(sk_bytes) != 32:
+ raise ValueError("must be exactly 32 bytes")
+ vk_bytes, sk_and_vk = _ed25519.publickey(sk_bytes)
+ assert sk_and_vk[:32] == sk_bytes
+ assert vk_bytes == sk_and_vk[32:]
+ self.vk_bytes = vk_bytes
+ self.sk_and_vk = sk_and_vk
+
+ def __eq__(self, them):
+ if not isinstance(them, object): return False
+ return (them.__class__ == self.__class__
+ and them.sk_and_vk == self.sk_and_vk)
+
+ def get_verifying_key_bytes(self):
+ return self.vk_bytes
+
+ def sign(self, msg):
+ sig_and_msg = _ed25519.sign(msg, self.sk_and_vk)
+ # the response is R+S+msg
+ sig_R = sig_and_msg[0:32]
+ sig_S = sig_and_msg[32:64]
+ msg_out = sig_and_msg[64:]
+ sig_out = sig_R + sig_S
+ assert msg_out == msg
+ return sig_out
+
+class VerifyingKey(object):
+ def __init__(self, vk_bytes):
+ if not isinstance(vk_bytes, type("")):
+ raise TypeError("must be bytes, not %s" % type(vk_bytes))
+ if len(vk_bytes) != 32:
+ raise ValueError("must be exactly 32 bytes")
+ self.vk_bytes = vk_bytes
+
+ def __eq__(self, them):
+ if not isinstance(them, object): return False
+ return (them.__class__ == self.__class__
+ and them.vk_bytes == self.vk_bytes)
+
+ def verify(self, sig, msg):
+ assert isinstance(sig, type("")) # string, really bytes
+ assert len(sig) == 64
+ sig_R = sig[:32]
+ sig_S = sig[32:]
+ sig_and_msg = sig_R + sig_S + msg
+ # this might raise BadSignatureError
+ msg2 = _ed25519.open(sig_and_msg, self.vk_bytes)
+ assert msg2 == msg
+
+def selftest():
+ from binascii import unhexlify
+ message = "crypto libraries should always test themselves at powerup"
+ sk_bytes = unhexlify("548b1f9f938519ad3d527d8c47a1e6ec1439fbec61710b245363865c6f234899")
+ sk = SigningKey(sk_bytes)
+ vk_bytes = unhexlify("787162d9ad1ad571237681560c1ad653fb7df9e09e637e6a8072e4520fd288ca")
+ vk = VerifyingKey(vk_bytes)
+ assert sk.get_verifying_key_bytes() == vk_bytes
+ sig = sk.sign(message)
+ assert sig == "13f42bc2d485e76c7cfaad25e1a840ede25b44a73befb0a528d836d7b434cf87e260c09d980388fab4cb564885857ea4dc3fb04107ca74960cc5a4d415fbf50d".decode('hex'), sig
+ vk.verify(sig, message)
+
+selftest()