From 4138842eed1e822d645cecdb6518043da49f17e1 Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 23 Mar 2016 19:14:59 +0100 Subject: [PATCH 1/5] import keys from cryptoconditions set ed25519 as default --- bigchaindb/__init__.py | 5 +- bigchaindb/consensus.py | 2 +- bigchaindb/core.py | 4 +- bigchaindb/crypto.py | 150 +++------------------------------- bigchaindb/util.py | 16 ++-- setup.py | 2 +- tests/conftest.py | 26 ++++-- tests/db/test_bigchain_api.py | 63 +++----------- tests/db/test_voter.py | 22 ++--- 9 files changed, 67 insertions(+), 223 deletions(-) diff --git a/bigchaindb/__init__.py b/bigchaindb/__init__.py index 9283913f..08cabf73 100644 --- a/bigchaindb/__init__.py +++ b/bigchaindb/__init__.py @@ -2,9 +2,8 @@ import os import copy - def e(key, default=None, conv=None): - '''Get the environment variable `key`, fallback to `default` + """Get the environment variable `key`, fallback to `default` if nothing is found. Keyword arguments: @@ -12,7 +11,7 @@ def e(key, default=None, conv=None): default -- the default value if nothing is found (default: None) conv -- a callable used to convert the value (default: use the type of the default value) - ''' + """ val = os.environ.get(key, default) diff --git a/bigchaindb/consensus.py b/bigchaindb/consensus.py index b65ab9ad..f039597d 100644 --- a/bigchaindb/consensus.py +++ b/bigchaindb/consensus.py @@ -2,7 +2,7 @@ from abc import ABCMeta, abstractmethod import bigchaindb.exceptions as exceptions from bigchaindb import util -from bigchaindb.crypto import hash_data, PublicKey +from bigchaindb.crypto import hash_data class AbstractConsensusRules(metaclass=ABCMeta): diff --git a/bigchaindb/core.py b/bigchaindb/core.py index f76dd2d6..36e23bf4 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -298,7 +298,7 @@ class Bigchain(object): # Calculate the hash of the new block block_data = util.serialize(block) block_hash = crypto.hash_data(block_data) - block_signature = crypto.PrivateKey(self.me_private).sign(block_data) + block_signature = crypto.SigningKey(self.me_private).sign(block_data).decode() block = { 'id': block_hash, @@ -419,7 +419,7 @@ class Bigchain(object): } vote_data = util.serialize(vote) - signature = crypto.PrivateKey(self.me_private).sign(vote_data) + signature = crypto.SigningKey(self.me_private).sign(vote_data).decode() vote_signed = { 'node_pubkey': self.me, diff --git a/bigchaindb/crypto.py b/bigchaindb/crypto.py index bcbe0863..5bdc81c4 100644 --- a/bigchaindb/crypto.py +++ b/bigchaindb/crypto.py @@ -1,150 +1,20 @@ # Separate all crypto code so that we can easily test several implementations -import binascii -import base58 - import sha3 -import bitcoin - -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.asymmetric import ec -from cryptography.hazmat.primitives import hashes -from cryptography.exceptions import InvalidSignature +from cryptoconditions import ecdsa, ed25519 -class PrivateKey(object): - """ - PrivateKey instance - """ +signing_algorithm = 'ed25519' - def __init__(self, key): - """ - Instantiate the private key with the private_value encoded in base58 - """ - private_value = self.decode(key) - private_numbers = self._private_value_to_cryptography_private_numbers(private_value) - self.private_key = self._cryptography_private_key_from_private_numbers(private_numbers) +if signing_algorithm == 'ecdsa': + SigningKey = ecdsa.EcdsaSigningKey + VerifyingKey = ecdsa.EcdsaVerifyingKey + generate_key_pair = ecdsa.ecdsa_generate_key_pair - def sign(self, data): - """ - Sign data with private key - """ - signer = self.private_key.signer(ec.ECDSA(hashes.SHA256())) - signer.update(data.encode('utf-8')) - signature = signer.finalize() - return binascii.hexlify(signature).decode('utf-8') - - - @staticmethod - def encode(private_value): - """ - Encode the decimal number private_value to base58 - """ - private_value_hex = bitcoin.encode_privkey(private_value, 'hex') - private_value_base58 = base58.b58encode(bytes.fromhex(private_value_hex)) - return private_value_base58 - - @staticmethod - def decode(key): - """ - Decode the base58 private_value to decimale - """ - private_value_hex = binascii.hexlify(base58.b58decode(key)) - private_value = bitcoin.decode_privkey(private_value_hex) - return private_value - - def _private_value_to_public_values(self, private_value): - """ - Return the public values from the private value - """ - public_value_x, public_value_y = bitcoin.privkey_to_pubkey(private_value) - return (public_value_x, public_value_y) - - def _private_value_to_cryptography_private_numbers(self, private_value): - """ - Return an instance of cryptography PrivateNumbers from the decimal private_value - """ - public_value_x, public_value_y = self._private_value_to_public_values(private_value) - public_numbers = PublicKey._public_values_to_cryptography_public_numbers(public_value_x, public_value_y) - private_numbers = ec.EllipticCurvePrivateNumbers(private_value, public_numbers) - return private_numbers - - @staticmethod - def _cryptography_private_key_from_private_numbers(private_numbers): - """ - Return an instace of cryptography PrivateKey from a cryptography instance of PrivateNumbers - """ - return private_numbers.private_key(default_backend()) - - -class PublicKey(object): - - def __init__(self, key): - """ - Instantiate the public key with the compressed public value encoded in base58 - """ - public_value_x, public_value_y = self.decode(key) - public_numbers = self._public_values_to_cryptography_public_numbers(public_value_x, public_value_y) - self.public_key = self._criptography_public_key_from_public_numbers(public_numbers) - - def verify(self, data, signature): - verifier = self.public_key.verifier(binascii.unhexlify(signature), ec.ECDSA(hashes.SHA256())) - verifier.update(data.encode('utf-8')) - try: - verifier.verify() - except InvalidSignature: - return False - - return True - - @staticmethod - def encode(public_value_x, public_value_y): - """ - Encode the public key represented by the decimal values x and y to base58 - """ - public_value_compressed_hex = bitcoin.encode_pubkey([public_value_x, public_value_y], 'hex_compressed') - public_value_compressed_base58 = base58.b58encode(bytes.fromhex(public_value_compressed_hex)) - return public_value_compressed_base58 - - @staticmethod - def decode(public_value_compressed_base58): - """ - Decode the base58 public_value to the decimal x and y values - """ - public_value_compressed_hex = binascii.hexlify(base58.b58decode(public_value_compressed_base58)) - public_value_x, public_value_y = bitcoin.decode_pubkey(public_value_compressed_hex.decode()) - return (public_value_x, public_value_y) - - @staticmethod - def _public_values_to_cryptography_public_numbers(public_value_x, public_value_y): - """ - Return an instance of cryptography PublicNumbers from the decimal x and y values - """ - public_numbers = ec.EllipticCurvePublicNumbers(public_value_x, public_value_y, ec.SECP256K1()) - return public_numbers - - def _criptography_public_key_from_public_numbers(self, public_numbers): - """ - Return an instance of cryptography PublicKey from a cryptography instance of PublicNumbers - """ - return public_numbers.public_key(default_backend()) - - -def generate_key_pair(): - """ - Generate a new key pair and return the pair encoded in base58 - """ - # Private key - private_key = ec.generate_private_key(ec.SECP256K1, default_backend()) - private_value = private_key.private_numbers().private_value - private_value_base58 = PrivateKey.encode(private_value) - - # Public key - public_key = private_key.public_key() - public_value_x, public_value_y = public_key.public_numbers().x, public_key.public_numbers().y - public_value_compressed_base58 = PublicKey.encode(public_value_x, public_value_y) - - return (private_value_base58, public_value_compressed_base58) +elif signing_algorithm == 'ed25519': + SigningKey = ed25519.Ed25519SigningKey + VerifyingKey = ed25519.Ed25519VerifyingKey + generate_key_pair = ed25519.ed25519_generate_key_pair def hash_data(data): diff --git a/bigchaindb/util.py b/bigchaindb/util.py index d8ddc9ce..ac3bd12a 100644 --- a/bigchaindb/util.py +++ b/bigchaindb/util.py @@ -6,7 +6,7 @@ from datetime import datetime import bigchaindb from bigchaindb import exceptions -from bigchaindb.crypto import PrivateKey, PublicKey, hash_data +from bigchaindb import crypto class ProcessGroup(object): @@ -109,7 +109,7 @@ def create_tx(current_owner, new_owner, tx_input, operation, payload=None): data = None if payload is not None: if isinstance(payload, dict): - hash_payload = hash_data(serialize(payload)) + hash_payload = crypto.hash_data(serialize(payload)) data = { 'hash': hash_payload, 'payload': payload @@ -117,7 +117,7 @@ def create_tx(current_owner, new_owner, tx_input, operation, payload=None): else: raise TypeError('`payload` must be an dict instance') - hash_payload = hash_data(serialize(payload)) + hash_payload = crypto.hash_data(serialize(payload)) data = { 'hash': hash_payload, 'payload': payload @@ -134,7 +134,7 @@ def create_tx(current_owner, new_owner, tx_input, operation, payload=None): # serialize and convert to bytes tx_serialized = serialize(tx) - tx_hash = hash_data(tx_serialized) + tx_hash = crypto.hash_data(tx_serialized) # create the transaction transaction = { @@ -158,10 +158,10 @@ def sign_tx(transaction, private_key): dict: transaction with the `signature` field included. """ - private_key = PrivateKey(private_key) + private_key = crypto.SigningKey(private_key) signature = private_key.sign(serialize(transaction)) signed_transaction = transaction.copy() - signed_transaction.update({'signature': signature}) + signed_transaction.update({'signature': signature.decode()}) return signed_transaction @@ -172,7 +172,7 @@ def create_and_sign_tx(private_key, current_owner, new_owner, tx_input, operatio def check_hash_and_signature(transaction): # Check hash of the transaction - calculated_hash = hash_data(serialize(transaction['transaction'])) + calculated_hash = crypto.hash_data(serialize(transaction['transaction'])) if calculated_hash != transaction['id']: raise exceptions.InvalidHash() @@ -201,7 +201,7 @@ def verify_signature(signed_transaction): signature = data.pop('signature') public_key_base58 = signed_transaction['transaction']['current_owner'] - public_key = PublicKey(public_key_base58) + public_key = crypto.VerifyingKey(public_key_base58) return public_key.verify(serialize(data), signature) diff --git a/setup.py b/setup.py index 6156b417..e26dd1fd 100644 --- a/setup.py +++ b/setup.py @@ -71,7 +71,7 @@ setup( 'rethinkdb==2.2.0.post4', 'pysha3==0.3', 'pytz==2015.7', - 'cryptography==1.2.1', + 'cryptoconditions==0.1.0', 'statsd==3.2.1', 'python-rapidjson==0.0.6', 'logstats==0.2.1', diff --git a/tests/conftest.py b/tests/conftest.py index 3781b2b6..3debae03 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,7 +14,7 @@ import pytest DB_NAME = 'bigchain_test_{}'.format(os.getpid()) -CONFIG = { +CONFIG_ECDSA = { 'database': { 'name': DB_NAME }, @@ -25,8 +25,22 @@ CONFIG = { } # Test user. inputs will be created for this user. Cryptography Keys -USER_PRIVATE_KEY = 'GmRZxQdQv7tooMijXytQkexKuFN6mJocciJarAmMwTX2' -USER_PUBLIC_KEY = 'r3cEu8GNoz8rYpNJ61k7GqfR8VEvdUbtyHce8u1kaYwh' +USER_PRIVATE_KEY_ECDSA = 'GmRZxQdQv7tooMijXytQkexKuFN6mJocciJarAmMwTX2' +USER_PUBLIC_KEY_ECDSA = 'r3cEu8GNoz8rYpNJ61k7GqfR8VEvdUbtyHce8u1kaYwh' + +CONFIG_ED25519 = { + 'database': { + 'name': DB_NAME + }, + 'keypair': { + 'private': '3wssdnSNsZYLvvQwuag5QNQnSfc5N38KV1ZeAoeHQQVe59N7vReJwXWANf5nncGxW63UzR4qHHv6DJhyLs9arJng', + 'public': '4spEuJCR6UNkS9Qyz6QwseU3ENRaypkcVgGKDeqfg8Ha' + } +} + +# Test user. inputs will be created for this user. Cryptography Keys +USER_PRIVATE_KEY_ED25519 = '3RZ3Kn8JbzyNwqzDwhU4dkZFFcwVkfgjhKiiqybfabxFAaANZqPemEudxTYMKfkbrHADTGCkvR7uQHSjihsXLbcM' +USER_PUBLIC_KEY_ED25519 = '2XJT5M6D3fYhvDbgcHmGMUcrGeZ9MtCWGqQZZVXghjv9' @pytest.fixture @@ -37,17 +51,17 @@ def restore_config(request, node_config): @pytest.fixture(scope='module') def node_config(): - return copy.deepcopy(CONFIG) + return copy.deepcopy(CONFIG_ED25519) @pytest.fixture def user_private_key(): - return USER_PRIVATE_KEY + return USER_PRIVATE_KEY_ED25519 @pytest.fixture def user_public_key(): - return USER_PUBLIC_KEY + return USER_PUBLIC_KEY_ED25519 @pytest.fixture diff --git a/tests/db/test_bigchain_api.py b/tests/db/test_bigchain_api.py index 1fed8800..23e73580 100644 --- a/tests/db/test_bigchain_api.py +++ b/tests/db/test_bigchain_api.py @@ -8,7 +8,7 @@ import rethinkdb as r import bigchaindb from bigchaindb import util from bigchaindb import exceptions -from bigchaindb.crypto import PrivateKey, PublicKey, generate_key_pair, hash_data +from bigchaindb import crypto from bigchaindb.voter import Voter from bigchaindb.block import Block @@ -44,7 +44,7 @@ class TestBigchainApi(object): 'operation': 'd', 'timestamp': tx['transaction']['timestamp'], 'data': { - 'hash': hash_data(util.serialize(payload)), + 'hash': crypto.hash_data(util.serialize(payload)), 'payload': payload } } @@ -52,7 +52,7 @@ class TestBigchainApi(object): # assert tx_hash == tx_calculated_hash def test_transaction_signature(self, b): - sk, vk = generate_key_pair() + sk, vk = crypto.generate_key_pair() tx = b.create_transaction(vk, 'b', 'c', 'd') tx_signed = b.sign_transaction(tx, sk) @@ -108,7 +108,7 @@ class TestBigchainApi(object): def test_assign_transaction_multiple_nodes(self, b, user_public_key, user_private_key): # create 5 federation nodes for _ in range(5): - b.federation_nodes.append(generate_key_pair()[1]) + b.federation_nodes.append(crypto.generate_key_pair()[1]) # test assignee for several transactions for _ in range(20): @@ -185,11 +185,11 @@ class TestBigchainApi(object): def test_create_new_block(self, b): new_block = b.create_block([]) - block_hash = hash_data(util.serialize(new_block['block'])) + block_hash = crypto.hash_data(util.serialize(new_block['block'])) assert new_block['block']['voters'] == [b.me] assert new_block['block']['node_pubkey'] == b.me - assert PublicKey(b.me).verify(util.serialize(new_block['block']), new_block['signature']) is True + assert crypto.VerifyingKey(b.me).verify(util.serialize(new_block['block']), new_block['signature']) is True assert new_block['id'] == block_hash assert new_block['votes'] == [] @@ -371,8 +371,8 @@ class TestBlockValidation(object): } block_data = util.serialize(block) - block_hash = hash_data(block_data) - block_signature = PrivateKey(b.me_private).sign(block_data) + block_hash = crypto.hash_data(block_data) + block_signature = crypto.SigningKey(b.me_private).sign(block_data) block = { 'id': block_hash, @@ -408,45 +408,6 @@ class TestBlockValidation(object): assert b.is_valid_block(block) -class TestBigchainCrypto(object): - PRIVATE_VALUE = 64328150571824492670917070117568709277186368319388887463636481841106388379832 - PUBLIC_VALUE_X = 48388170575736684074633245566225141536152842355597159440179742847497614196929 - PUBLIC_VALUE_Y = 65233479152484407841598798165960909560839872511163322973341535484598825150846 - - PRIVATE_VALUE_B58 = 'AaAp4xBavbe6VGeQF2mWdSKNM1r6HfR2Z1tAY6aUkwdq' - PUBLIC_VALUE_COMPRESSED_B58 = 'ifEi3UuTDT4CqUUKiS5omgeDodhu2aRFHVp6LoahbEVe' - - def test_private_key_encode(self): - private_value_base58 = PrivateKey.encode(self.PRIVATE_VALUE) - assert private_value_base58 == self.PRIVATE_VALUE_B58 - - def test_private_key_decode(self): - private_value = PrivateKey.decode(self.PRIVATE_VALUE_B58) - assert private_value == self.PRIVATE_VALUE - - def test_public_key_encode(self): - public_value_compressed_base58 = PublicKey.encode(self.PUBLIC_VALUE_X, self.PUBLIC_VALUE_Y) - assert public_value_compressed_base58 == self.PUBLIC_VALUE_COMPRESSED_B58 - - def test_public_key_decode(self): - public_value_x, public_value_y = PublicKey.decode(self.PUBLIC_VALUE_COMPRESSED_B58) - assert public_value_x == self.PUBLIC_VALUE_X - assert public_value_y == self.PUBLIC_VALUE_Y - - def test_sign_verify(self): - message = 'Hello World!' - public_key = PublicKey(self.PUBLIC_VALUE_COMPRESSED_B58) - private_key = PrivateKey(self.PRIVATE_VALUE_B58) - assert public_key.verify(message, private_key.sign(message)) is True - - def test_generate_key_pair(self): - private_value_base58, public_value_compressed_base58 = generate_key_pair() - assert PrivateKey.encode( - PrivateKey.decode(private_value_base58)) == private_value_base58 - assert PublicKey.encode( - *PublicKey.decode(public_value_compressed_base58)) == public_value_compressed_base58 - - class TestBigchainVoter(object): def test_valid_block_voting(self, b): @@ -483,7 +444,7 @@ class TestBigchainVoter(object): assert vote['vote']['is_block_valid'] is True assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me - assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True + assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True def test_invalid_block_voting(self, b, user_public_key): # create queue and voter @@ -524,7 +485,7 @@ class TestBigchainVoter(object): assert vote['vote']['is_block_valid'] is False assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me - assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True + assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True def test_vote_creation_valid(self, b): # create valid block @@ -538,7 +499,7 @@ class TestBigchainVoter(object): assert vote['vote']['is_block_valid'] is True assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me - assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True + assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True def test_vote_creation_invalid(self, b): # create valid block @@ -552,7 +513,7 @@ class TestBigchainVoter(object): assert vote['vote']['is_block_valid'] is False assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me - assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True + assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True class TestBigchainBlock(object): diff --git a/tests/db/test_voter.py b/tests/db/test_voter.py index d8146829..28f7fa59 100644 --- a/tests/db/test_voter.py +++ b/tests/db/test_voter.py @@ -6,7 +6,7 @@ import multiprocessing as mp from bigchaindb import util from bigchaindb.voter import Voter, BlockStream -from bigchaindb.crypto import PublicKey, generate_key_pair +from bigchaindb import crypto class TestBigchainVoter(object): @@ -45,7 +45,7 @@ class TestBigchainVoter(object): assert vote['vote']['is_block_valid'] is True assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me - assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True + assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True def test_valid_block_voting_with_create_transaction(self, b): q_new_block = mp.Queue() @@ -53,7 +53,7 @@ class TestBigchainVoter(object): genesis = b.create_genesis_block() # create a `CREATE` transaction - test_user_priv, test_user_pub = generate_key_pair() + test_user_priv, test_user_pub = crypto.generate_key_pair() tx = b.create_transaction(b.me, test_user_pub, None, 'CREATE') tx_signed = b.sign_transaction(tx, b.me_private) assert b.is_valid_transaction(tx_signed) @@ -87,7 +87,7 @@ class TestBigchainVoter(object): assert vote['vote']['is_block_valid'] is True assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me - assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True + assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True def test_valid_block_voting_with_transfer_transactions(self, b): q_new_block = mp.Queue() @@ -95,7 +95,7 @@ class TestBigchainVoter(object): b.create_genesis_block() # create a `CREATE` transaction - test_user_priv, test_user_pub = generate_key_pair() + test_user_priv, test_user_pub = crypto.generate_key_pair() tx = b.create_transaction(b.me, test_user_pub, None, 'CREATE') tx_signed = b.sign_transaction(tx, b.me_private) assert b.is_valid_transaction(tx_signed) @@ -124,7 +124,7 @@ class TestBigchainVoter(object): assert len(blocks[1]['votes']) == 1 # create a `TRANSFER` transaction - test_user2_priv, test_user2_pub = generate_key_pair() + test_user2_priv, test_user2_pub = crypto.generate_key_pair() tx2 = b.create_transaction(test_user_pub, test_user2_pub, tx['id'], 'TRANSFER') tx2_signed = b.sign_transaction(tx2, test_user_priv) assert b.is_valid_transaction(tx2_signed) @@ -158,7 +158,7 @@ class TestBigchainVoter(object): assert vote['vote']['is_block_valid'] is True assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me - assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True + assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True def test_invalid_block_voting(self, b, user_public_key): # create queue and voter @@ -197,7 +197,7 @@ class TestBigchainVoter(object): assert vote['vote']['is_block_valid'] is False assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me - assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True + assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True def test_vote_creation_valid(self, b): # create valid block @@ -211,7 +211,7 @@ class TestBigchainVoter(object): assert vote['vote']['is_block_valid'] is True assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me - assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True + assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True def test_vote_creation_invalid(self, b): # create valid block @@ -225,7 +225,7 @@ class TestBigchainVoter(object): assert vote['vote']['is_block_valid'] is False assert vote['vote']['invalid_reason'] is None assert vote['node_pubkey'] == b.me - assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True + assert crypto.VerifyingKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True def test_voter_considers_unvoted_blocks_when_single_node(self, b): # simulate a voter going donw in a single node environment @@ -301,7 +301,7 @@ class TestBlockStream(object): def test_if_federation_size_is_greater_than_one_ignore_past_blocks(self, b): for _ in range(5): - b.federation_nodes.append(generate_key_pair()[1]) + b.federation_nodes.append(crypto.generate_key_pair()[1]) new_blocks = mp.Queue() bs = BlockStream(new_blocks) block_1 = b.create_block([]) From ce1302dd904206d3dde9d72136c116d024111c53 Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 31 Mar 2016 15:10:43 +0200 Subject: [PATCH 2/5] imports from crypto --- bigchaindb/consensus.py | 6 +++--- bigchaindb/crypto.py | 22 +++++++--------------- setup.py | 2 +- tests/conftest.py | 8 ++++---- 4 files changed, 15 insertions(+), 23 deletions(-) diff --git a/bigchaindb/consensus.py b/bigchaindb/consensus.py index f039597d..277dad3e 100644 --- a/bigchaindb/consensus.py +++ b/bigchaindb/consensus.py @@ -2,7 +2,7 @@ from abc import ABCMeta, abstractmethod import bigchaindb.exceptions as exceptions from bigchaindb import util -from bigchaindb.crypto import hash_data +from bigchaindb import crypto class AbstractConsensusRules(metaclass=ABCMeta): @@ -156,7 +156,7 @@ class BaseConsensusRules(AbstractConsensusRules): transaction['transaction']['input'])) # Check hash of the transaction - calculated_hash = hash_data(util.serialize( + calculated_hash = crypto.hash_data(util.serialize( transaction['transaction'])) if calculated_hash != transaction['id']: raise exceptions.InvalidHash() @@ -185,7 +185,7 @@ class BaseConsensusRules(AbstractConsensusRules): """ # Check if current hash is correct - calculated_hash = hash_data(util.serialize(block['block'])) + calculated_hash = crypto.hash_data(util.serialize(block['block'])) if calculated_hash != block['id']: raise exceptions.InvalidHash() diff --git a/bigchaindb/crypto.py b/bigchaindb/crypto.py index 5bdc81c4..506cb00e 100644 --- a/bigchaindb/crypto.py +++ b/bigchaindb/crypto.py @@ -1,25 +1,17 @@ # Separate all crypto code so that we can easily test several implementations import sha3 -from cryptoconditions import ecdsa, ed25519 - - -signing_algorithm = 'ed25519' - -if signing_algorithm == 'ecdsa': - SigningKey = ecdsa.EcdsaSigningKey - VerifyingKey = ecdsa.EcdsaVerifyingKey - generate_key_pair = ecdsa.ecdsa_generate_key_pair - -elif signing_algorithm == 'ed25519': - SigningKey = ed25519.Ed25519SigningKey - VerifyingKey = ed25519.Ed25519VerifyingKey - generate_key_pair = ed25519.ed25519_generate_key_pair +from cryptoconditions import ed25519 def hash_data(data): """Hash the provided data using SHA3-256""" - return sha3.sha3_256(data.encode()).hexdigest() +def generate_key_pair(): + sk, pk = ed25519.ed25519_generate_key_pair() + return sk.decode(), pk.decode() + +SigningKey = ed25519.Ed25519SigningKey +VerifyingKey = ed25519.Ed25519VerifyingKey diff --git a/setup.py b/setup.py index e26dd1fd..8c170823 100644 --- a/setup.py +++ b/setup.py @@ -71,7 +71,7 @@ setup( 'rethinkdb==2.2.0.post4', 'pysha3==0.3', 'pytz==2015.7', - 'cryptoconditions==0.1.0', + 'cryptoconditions==0.1.1', 'statsd==3.2.1', 'python-rapidjson==0.0.6', 'logstats==0.2.1', diff --git a/tests/conftest.py b/tests/conftest.py index 3debae03..c5018b7e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -33,14 +33,14 @@ CONFIG_ED25519 = { 'name': DB_NAME }, 'keypair': { - 'private': '3wssdnSNsZYLvvQwuag5QNQnSfc5N38KV1ZeAoeHQQVe59N7vReJwXWANf5nncGxW63UzR4qHHv6DJhyLs9arJng', - 'public': '4spEuJCR6UNkS9Qyz6QwseU3ENRaypkcVgGKDeqfg8Ha' + 'private': '31Lb1ZGKTyHnmVK3LUMrAUrPNfd4sE2YyBt3UA4A25aA', + 'public': '4XYfCbabAWVUCbjTmRTFEu2sc3dFEdkse4r6X498B1s8' } } # Test user. inputs will be created for this user. Cryptography Keys -USER_PRIVATE_KEY_ED25519 = '3RZ3Kn8JbzyNwqzDwhU4dkZFFcwVkfgjhKiiqybfabxFAaANZqPemEudxTYMKfkbrHADTGCkvR7uQHSjihsXLbcM' -USER_PUBLIC_KEY_ED25519 = '2XJT5M6D3fYhvDbgcHmGMUcrGeZ9MtCWGqQZZVXghjv9' +USER_PRIVATE_KEY_ED25519 = '8eJ8q9ZQpReWyQT5aFCiwtZ5wDZC4eDnCen88p3tQ6ie' +USER_PUBLIC_KEY_ED25519 = 'JEAkEJqLbbgDRAtMm8YAjGp759Aq2qTn9eaEHUj2XePE' @pytest.fixture From 9067582bdd2290533a1b24c06569b851764c499c Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 31 Mar 2016 18:05:52 +0200 Subject: [PATCH 3/5] updated docs --- bigchaindb/client.py | 4 ++-- bigchaindb/core.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bigchaindb/client.py b/bigchaindb/client.py index f7b37ad4..67ce51a9 100644 --- a/bigchaindb/client.py +++ b/bigchaindb/client.py @@ -27,8 +27,8 @@ class Client: 3. Reading them from the `config.json` file. Args: - public_key (str): the base58 encoded public key for the ECDSA secp256k1 curve. - private_key (str): the base58 encoded private key for the ECDSA secp256k1 curve. + public_key (str): the base58 encoded public key for the ED25519 curve. + private_key (str): the base58 encoded private key for the ED25519 curve. api_endpoint (str): a URL where rethinkdb is running. format: scheme://hostname:port consensus_plugin (str): the registered name of your installed diff --git a/bigchaindb/core.py b/bigchaindb/core.py index 36e23bf4..76252a89 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -41,8 +41,8 @@ class Bigchain(object): host (str): hostname where the rethinkdb is running. port (int): port in which rethinkb is running (usually 28015). dbname (str): the name of the database to connect to (usually bigchain). - public_key (str): the base58 encoded public key for the ECDSA secp256k1 curve. - private_key (str): the base58 encoded private key for the ECDSA secp256k1 curve. + public_key (str): the base58 encoded public key for the ED25519 curve. + private_key (str): the base58 encoded private key for the ED25519 curve. keyring (list[str]): list of base58 encoded public keys of the federation nodes. """ From e1191a8c38094398d6a9f141463eaae5a6780a7d Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 7 Apr 2016 09:54:25 +0200 Subject: [PATCH 4/5] updated documentation --- docs/source/cryptography.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/cryptography.md b/docs/source/cryptography.md index aaa9f7ef..03fe22c3 100644 --- a/docs/source/cryptography.md +++ b/docs/source/cryptography.md @@ -19,8 +19,8 @@ tx_hash = hashlib.sha3_256(data).hexdigest() ## Signature algorithm and keys -The signature algorithm used by BigchainDB is ECDSA with the secp256k1 curve -using the python [cryptography](https://cryptography.io/en/latest/) module. +The signature algorithm used by BigchainDB is [ED25519](https://tools.ietf.org/html/draft-irtf-cfrg-eddsa-04) +using the python [ed25519](https://github.com/warner/python-ed25519) module, overloaded by the [cryptoconditions library](https://github.com/bigchaindb/cryptoconditions). The private key is the base58 encoded hexadecimal representation of private number. The public key is the base58 encoded hexadecimal representation of the From 12ce46040068b0be8d04ef8933f1d9609495bf37 Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 7 Apr 2016 17:05:57 +0200 Subject: [PATCH 5/5] removed ECDSA support in tests config --- tests/conftest.py | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index c5018b7e..1116b52f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,21 +14,7 @@ import pytest DB_NAME = 'bigchain_test_{}'.format(os.getpid()) -CONFIG_ECDSA = { - 'database': { - 'name': DB_NAME - }, - 'keypair': { - 'private': '3i2FDXp87N9ExXSvWxqBAw9EgzoxxGTQNKbtxmWBpTyL', - 'public': '29Tw3ozmSRtN8XNofvsu5RdoQRk9gAonfpkFvRZDmhTPo' - } -} - -# Test user. inputs will be created for this user. Cryptography Keys -USER_PRIVATE_KEY_ECDSA = 'GmRZxQdQv7tooMijXytQkexKuFN6mJocciJarAmMwTX2' -USER_PUBLIC_KEY_ECDSA = 'r3cEu8GNoz8rYpNJ61k7GqfR8VEvdUbtyHce8u1kaYwh' - -CONFIG_ED25519 = { +CONFIG = { 'database': { 'name': DB_NAME }, @@ -39,8 +25,8 @@ CONFIG_ED25519 = { } # Test user. inputs will be created for this user. Cryptography Keys -USER_PRIVATE_KEY_ED25519 = '8eJ8q9ZQpReWyQT5aFCiwtZ5wDZC4eDnCen88p3tQ6ie' -USER_PUBLIC_KEY_ED25519 = 'JEAkEJqLbbgDRAtMm8YAjGp759Aq2qTn9eaEHUj2XePE' +USER_PRIVATE_KEY = '8eJ8q9ZQpReWyQT5aFCiwtZ5wDZC4eDnCen88p3tQ6ie' +USER_PUBLIC_KEY = 'JEAkEJqLbbgDRAtMm8YAjGp759Aq2qTn9eaEHUj2XePE' @pytest.fixture @@ -51,17 +37,17 @@ def restore_config(request, node_config): @pytest.fixture(scope='module') def node_config(): - return copy.deepcopy(CONFIG_ED25519) + return copy.deepcopy(CONFIG) @pytest.fixture def user_private_key(): - return USER_PRIVATE_KEY_ED25519 + return USER_PRIVATE_KEY @pytest.fixture def user_public_key(): - return USER_PUBLIC_KEY_ED25519 + return USER_PUBLIC_KEY @pytest.fixture