From 5fd90d84b40469e6b8cf511c54926cd435b4e384 Mon Sep 17 00:00:00 2001 From: inso <insomniak.fr@gmaiL.com> Date: Wed, 4 May 2016 07:12:48 +0200 Subject: [PATCH] Verifying Key --- docs/index.rst | 2 +- duniterpy/documents/document.py | 6 ++++++ duniterpy/key/__init__.py | 3 ++- duniterpy/key/base58.py | 10 ++++++++++ duniterpy/key/signing_key.py | 12 +---------- duniterpy/key/verifying_key.py | 35 +++++++++++++++++++++++++++++++++ setup.py | 4 ++-- tests/key/__init__.py | 0 tests/key/test_verifying_key.py | 25 +++++++++++++++++++++++ 9 files changed, 82 insertions(+), 15 deletions(-) create mode 100644 duniterpy/key/base58.py create mode 100644 duniterpy/key/verifying_key.py create mode 100644 tests/key/__init__.py create mode 100644 tests/key/test_verifying_key.py diff --git a/docs/index.rst b/docs/index.rst index f2bf96f1..524cf6e4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,7 +22,7 @@ Simply type:: Source code ----------- -Sources can be found at https://github.com/duniter-io/duniter-python-api +Sources can be found at https://github.com/duniter/duniter-python-api Contributions are welcome. diff --git a/duniterpy/documents/document.py b/duniterpy/documents/document.py index e809b948..bced25b4 100644 --- a/duniterpy/documents/document.py +++ b/duniterpy/documents/document.py @@ -59,6 +59,12 @@ class Document: logging.debug("Signature : \n{0}".format(signing.decode("ascii"))) self.signatures.append(signing.decode("ascii")) + def raw(self): + """ + Returns the raw document in string format + """ + raise NotImplementedError() + def signed_raw(self): """ If keys are None, returns the raw + current signatures diff --git a/duniterpy/key/__init__.py b/duniterpy/key/__init__.py index dc1b0fae..66d1aa86 100644 --- a/duniterpy/key/__init__.py +++ b/duniterpy/key/__init__.py @@ -1 +1,2 @@ -from .signing_key import SigningKey \ No newline at end of file +from .signing_key import SigningKey +from .verifying_key import VerifyingKey \ No newline at end of file diff --git a/duniterpy/key/base58.py b/duniterpy/key/base58.py new file mode 100644 index 00000000..5bcb8060 --- /dev/null +++ b/duniterpy/key/base58.py @@ -0,0 +1,10 @@ +import base58 + +class Base58Encoder(object): + @staticmethod + def encode(data): + return base58.b58encode(data) + + @staticmethod + def decode(data): + return base58.b58decode(data) \ No newline at end of file diff --git a/duniterpy/key/signing_key.py b/duniterpy/key/signing_key.py index 7cd1b6e1..4b646769 100644 --- a/duniterpy/key/signing_key.py +++ b/duniterpy/key/signing_key.py @@ -4,10 +4,9 @@ duniter public and private keys @author: inso """ -import base58 -import base64 import libnacl.sign from pylibscrypt import scrypt +from .base58 import Base58Encoder SEED_LENGTH = 32 # Length of the key @@ -35,12 +34,3 @@ class SigningKey(libnacl.sign.Signer): super().__init__(seed) self.pubkey = Base58Encoder.encode(self.vk) - -class Base58Encoder(object): - @staticmethod - def encode(data): - return base58.b58encode(data) - - @staticmethod - def decode(data): - return base58.b58decode(data) diff --git a/duniterpy/key/verifying_key.py b/duniterpy/key/verifying_key.py new file mode 100644 index 00000000..4af608d2 --- /dev/null +++ b/duniterpy/key/verifying_key.py @@ -0,0 +1,35 @@ +""" +duniter public and private keys + +@author: inso +""" + +import base58 +import base64 +import libnacl.sign +from pylibscrypt import scrypt +from .base58 import Base58Encoder + + +class VerifyingKey(libnacl.sign.Verifier): + """ + Class to verify documents + """ + def __init__(self, pubkey): + """ + Creates a Verify class from base58 pubkey + :param pubkey: + """ + key = libnacl.encode.hex_encode(Base58Encoder.decode(pubkey)) + super().__init__(key) + + def verify_document(self, document, **kwargs): + """ + Check specified document + :param duniterpy.documents.Document document: + :return: + """ + signature = base64.b64decode(document.signatures[0]) + prepended = signature + bytes(document.raw(**kwargs), 'ascii') + + return self.verify(prepended) diff --git a/setup.py b/setup.py index 4b7f4b67..0c72f9f4 100644 --- a/setup.py +++ b/setup.py @@ -49,13 +49,13 @@ setup( author_email="insomniak.fr@gmail.com", - description="A python implementation of [duniter](https://github.com/duniter-io/duniter) API", + description="A python implementation of [duniter](https://github.com/duniter/duniter) API", long_description=open('README.md').read(), # Active la prise en compte du fichier MANIFEST.in include_package_data=True, - url='https://github.com/duniter-io/duniter-python-api', + url='https://github.com/duniter/duniter-python-api', test_suite="tests", classifiers=[ diff --git a/tests/key/__init__.py b/tests/key/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/key/test_verifying_key.py b/tests/key/test_verifying_key.py new file mode 100644 index 00000000..4f282725 --- /dev/null +++ b/tests/key/test_verifying_key.py @@ -0,0 +1,25 @@ +from duniterpy.key import VerifyingKey, SigningKey +from duniterpy.documents import Peer +import unittest + + +class Test_VerifyingKey(unittest.TestCase): + def test_from_sign_to_verify(self): + sign_key = SigningKey("saltsalt", "passwordpassword") + verify_key = VerifyingKey(sign_key.pubkey) + self.assertEqual(verify_key.vk, sign_key.vk) + + def test_peer_signature(self): + signed_raw = """Version: 2 +Type: Peer +Currency: test_net +PublicKey: 8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU +Block: 2086-00005D6FC6E22FB308D8815A565A01C66FFB7DC761D616DE0698F6322565F1D6 +Endpoints: +BASIC_MERKLED_API testnet.duniter.inso.ovh 80 +4aQ/sfqFAFUeYkkLdC2OfgXqTBjCIcMptpR/GIlGqbe4aFVJcy9NEVAFx7sHiLuAb+VNnec3XHHC+xOk3MLzDA== +""""" + peer = Peer.from_signed_raw(signed_raw) + pubkey = "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU" + verifying_key = VerifyingKey(pubkey) + self.assertTrue(verifying_key.verify_document(peer)) -- GitLab