From 6537362e3d45eeeee1517f3fbfd0959fb55bec11 Mon Sep 17 00:00:00 2001 From: Kevin F Date: Wed, 19 Jan 2022 18:48:42 -0600 Subject: [PATCH] Adjusting block generation to use ttl instead of rounds in metadata --- CHANGELOG.md | 4 ++ onionrblocks/__init__.py | 8 +--- onionrblocks/block.py | 30 ++++++++++++++ onionrblocks/blockcreator/__init__.py | 16 ++++---- onionrblocks/generators/__init__.py | 3 +- onionrblocks/generators/anonvdf.py | 29 ++++++-------- onionrblocks/generators/signedby.py | 57 --------------------------- requirements.in | 3 +- setup.py | 2 +- tests/test_blockcreator.py | 47 ++++++++++++++++------ tests/test_signedby.py | 44 --------------------- 11 files changed, 96 insertions(+), 147 deletions(-) create mode 100644 onionrblocks/block.py delete mode 100644 onionrblocks/generators/signedby.py delete mode 100644 tests/test_signedby.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 42e63df..b9d81e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ This project uses Semantic Versioning +## 5.0.0 + +- Removed signedby + ## 4.0.0 * Make blocks less expensive diff --git a/onionrblocks/__init__.py b/onionrblocks/__init__.py index 3983bd5..241b4c3 100644 --- a/onionrblocks/__init__.py +++ b/onionrblocks/__init__.py @@ -1,7 +1,3 @@ -from typing import Union -from time import time -from binascii import hexlify +from .blockcreator import create_anonvdf_block -import kasten - -from . import generators +from .block import Block diff --git a/onionrblocks/block.py b/onionrblocks/block.py new file mode 100644 index 0000000..5ff0b93 --- /dev/null +++ b/onionrblocks/block.py @@ -0,0 +1,30 @@ +from enum import auto +from hashlib import new +from typing import Union, TYPE_CHECKING +from binascii import hexlify + +if TYPE_CHECKING: + from kasten.generator import KastenPacked +from kasten import Kasten +from . import generators + +class Block: + def __init__( + self, block_hash: str, + raw_block_data: 'KastenPacked', auto_verify=True): + generator = generators.AnonVDFGenerator + bl = Kasten( + block_hash, + raw_block_data, + generator, auto_check_generator=auto_verify) + self.timestamp = bl.get_timestamp() + self.metadata = bl.get_metadata() + self.id = block_hash + self.type = bl.get_data_type() + self.data = bl.data + self.raw = bl.get_packed() + + +def kasten_to_block(kasten: Kasten): + return Block(hexlify(kasten.id), kasten.get_packed(), auto_verify=False) + diff --git a/onionrblocks/blockcreator/__init__.py b/onionrblocks/blockcreator/__init__.py index bb160d8..2d1a3af 100644 --- a/onionrblocks/blockcreator/__init__.py +++ b/onionrblocks/blockcreator/__init__.py @@ -16,17 +16,19 @@ along with this program. If not, see . """ from time import time -from kasten import Kasten from kasten.generator.pack import pack from ..generators import anonvdf +from ..block import Block +from ..block import kasten_to_block + def create_anonvdf_block( block_data: bytes, block_type: bytes, ttl: int, - **block_metadata) -> Kasten: + **block_metadata) -> Block: try: block_data = block_data.encode('utf-8') except AttributeError: @@ -39,12 +41,12 @@ def create_anonvdf_block( packed = pack( block_data, block_type, app_metadata=block_metadata, timestamp=ts) + block_metadata['ttl'] = ttl rounds_needed = anonvdf.AnonVDFGenerator.get_rounds_for_ttl_seconds( - ttl, len(packed) + 10) - block_metadata['rds'] = rounds_needed + ttl, len(packed)) packed = pack( block_data, block_type, app_metadata=block_metadata, timestamp=ts) - return anonvdf.AnonVDFGenerator.generate( - packed, block_metadata['rds']) - + k = anonvdf.AnonVDFGenerator.generate( + packed, block_metadata['ttl']) + return kasten_to_block(k) \ No newline at end of file diff --git a/onionrblocks/generators/__init__.py b/onionrblocks/generators/__init__.py index 85d6445..3ecb6fa 100644 --- a/onionrblocks/generators/__init__.py +++ b/onionrblocks/generators/__init__.py @@ -1,2 +1 @@ -from .anonvdf import AnonVDFGenerator -from .signedby import Signed \ No newline at end of file +from .anonvdf import AnonVDFGenerator \ No newline at end of file diff --git a/onionrblocks/generators/anonvdf.py b/onionrblocks/generators/anonvdf.py index 4d2b247..0a24480 100644 --- a/onionrblocks/generators/anonvdf.py +++ b/onionrblocks/generators/anonvdf.py @@ -1,4 +1,5 @@ import time +from binascii import a2b_hex from kasten import Kasten, generator from kasten.types import KastenPacked, KastenChecksum @@ -34,16 +35,13 @@ class AnonVDFGenerator(generator.KastenBaseGenerator): @classmethod def generate( - cls, packed_bytes: KastenPacked, rounds: int = None) -> Kasten: - if not rounds: - try: - rounds = int(Kasten( + cls, packed_bytes: KastenPacked, ttl: int = None) -> Kasten: + + ttl = int(Kasten( None, packed_bytes, None, - auto_check_generator=False).get_metadata()['rds']) - except (KeyError, TypeError) as _: # noqa - raise ValueError( - "Rounds not specified either in block or as argument") + auto_check_generator=False).get_metadata()['ttl']) + rounds = AnonVDFGenerator.get_rounds_for_ttl_seconds(ttl, len(packed_bytes)) check_block_sanity(packed_bytes) return Kasten( vdf_create( @@ -55,19 +53,18 @@ class AnonVDFGenerator(generator.KastenBaseGenerator): @staticmethod def validate_id( hash: KastenChecksum, - packed_bytes: KastenPacked, rounds: int = None) -> None: + packed_bytes: KastenPacked) -> None: check_block_sanity(packed_bytes) - if not rounds: - try: - rounds = int(Kasten( + ttl = int(Kasten( None, packed_bytes, None, - auto_check_generator=False).get_metadata()['rds']) - except (KeyError, TypeError) as _: # noqa - raise ValueError( - "Rounds not specified either in block or as argument") + auto_check_generator=False).get_metadata()['ttl']) + rounds = AnonVDFGenerator.get_rounds_for_ttl_seconds(ttl, len(packed_bytes)) + + hash = hash.lstrip(b"0") + hash = int(hash, 16) try: hash = int.from_bytes(hash, byteorder="big") diff --git a/onionrblocks/generators/signedby.py b/onionrblocks/generators/signedby.py deleted file mode 100644 index ce83c00..0000000 --- a/onionrblocks/generators/signedby.py +++ /dev/null @@ -1,57 +0,0 @@ -from hashlib import sha3_256 -from typing import Union - -from nacl.signing import SigningKey, VerifyKey -from nacl.exceptions import BadSignatureError -from kasten import generator, Kasten -from kasten.exceptions import InvalidID -from kasten.types import KastenPacked, KastenChecksum - -from onionrblocks.customtypes import RawEd25519PrivateKey, RawEd25519PublicKey -from onionrblocks.universalrules import check_block_sanity - -class Signed(generator.KastenBaseGenerator): - - @classmethod - def generate( - cls, - packed_bytes: KastenPacked, - signingKey: Union[SigningKey, RawEd25519PrivateKey] - ) -> Kasten: - """Sign a digest of packed bytes, return a Kasten instance of it.""" - # Use libsodium/pynacl (ed25519) - hashed = sha3_256(packed_bytes).digest() - try: - signed = signingKey.sign(hashed) - except AttributeError: - signingKey = SigningKey(signingKey) - signed = signingKey.sign(hashed) - # The KastenChecksum will be 64 bytes message then 32 bytes of the hash - # This can be fed right back into VerifyKey without splitting up - return Kasten(signed, packed_bytes, None, - auto_check_generator=False) - - - @staticmethod - def validate_id( - hash: KastenChecksum, - packed_bytes: KastenPacked, - verify_key: Union[VerifyKey, RawEd25519PublicKey]) -> None: - check_block_sanity(packed_bytes) - # Hash is 64 bytes message then 32 bytes of the hash of the packed_bytes - if len(hash) != 86: - raise InvalidID("Block not have proper signature length") - actual_hash = sha3_256(packed_bytes).digest() - if not isinstance(verify_key, VerifyKey): - verify_key = VerifyKey(verify_key) - - # Ensure that the digest is correct - # Done in addition of the signature bc the sha3 can still ID blocks - # and to prevent swapping sigs - if actual_hash != hash[64:]: - raise InvalidID("Invalid sha3_256 digest") - # Ensure that the signature is correct - try: - verify_key.verify(hash) - except BadSignatureError as e: - raise InvalidID(repr(e)) diff --git a/requirements.in b/requirements.in index 1eb0894..99d5591 100644 --- a/requirements.in +++ b/requirements.in @@ -1,2 +1 @@ -kasten==3.0.0 -PyNaCl==1.4.0 \ No newline at end of file +kasten==3.0.0 \ No newline at end of file diff --git a/setup.py b/setup.py index 5cebe75..edd686a 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup, find_packages setup(name='onionrblocks', - version='4.0.0', + version='5.0.0', description='Onionr message format', author='Kevin Froman', author_email='beardog@mailbox.org', diff --git a/tests/test_blockcreator.py b/tests/test_blockcreator.py index 018a127..03fed8f 100644 --- a/tests/test_blockcreator.py +++ b/tests/test_blockcreator.py @@ -1,33 +1,56 @@ +from binascii import a2b_hex from onionrblocks.generators import anonvdf import unittest import kasten from onionrblocks.blockcreator import create_anonvdf_block +def get_rounds_for_ttl_seconds(seconds: int, size_bytes: int): + second_cost = 4 + byte_cost = 10 + return (seconds * second_cost) + (size_bytes * byte_cost) + class TestBlockCreator(unittest.TestCase): + """ def test_create_anonvdf(self): - bl = create_anonvdf_block(b"Test", "txt", 3600) + seconds = 3600 + bl = create_anonvdf_block(b"Test", "txt", seconds) + byte_cost = 10 + second_cost = 4 # (rounds - (size_bytes * cls.byte_cost)) // cls.second_cost - expected_rounds = (3600 * 4) + (len(bl.get_packed()) * 100) + 100 - self.assertEqual(expected_rounds, bl.get_metadata()['rds']) + expected_rounds = (seconds * second_cost) + (len(bl.get_packed()) * byte_cost) + self.assertTrue(abs(expected_rounds - bl.get_metadata()['rds']) < 91) def test_create_anonvdf_half_hour(self): bl = create_anonvdf_block(b"Test", "txt", 1800) - expected_rounds = (len(bl.get_packed()) * anonvdf.AnonVDFGenerator.byte_cost) + (1800 * anonvdf.AnonVDFGenerator.second_cost) + 100 - self.assertEqual(expected_rounds, bl.get_metadata()['rds']) + expected_rounds = (len(bl.get_packed()) * anonvdf.AnonVDFGenerator.byte_cost) + (1800 * anonvdf.AnonVDFGenerator.second_cost) + self.assertTrue(abs(expected_rounds - bl.get_metadata()['rds']) < 91) def test_create_anonvdf_odd(self): #(rounds - (size_bytes * cls.byte_cost)) // cls.second_cost bl = create_anonvdf_block(b"Test", "txt", 1303) - expected_rounds = (len(bl.get_packed()) * anonvdf.AnonVDFGenerator.byte_cost) + (1303 * anonvdf.AnonVDFGenerator.second_cost) + 100 - self.assertEqual(expected_rounds, bl.get_metadata()['rds']) + expected_rounds = (len(bl.get_packed()) * anonvdf.AnonVDFGenerator.byte_cost) + (1303 * anonvdf.AnonVDFGenerator.second_cost) + self.assertTrue(abs(expected_rounds - bl.get_metadata()['rds']) < 91) + """ def test_create_anonvdf_verify(self): bl = create_anonvdf_block(b"Test", "txt", 3600) - expected_rounds = (len(bl.get_packed()) * anonvdf.AnonVDFGenerator.byte_cost) + (3600 * anonvdf.AnonVDFGenerator.second_cost) + 100 - self.assertEqual(expected_rounds, bl.get_metadata()['rds']) - packed = bl.get_packed() - id = bl.id - kasten.Kasten(id, packed, anonvdf.AnonVDFGenerator, auto_check_generator=True) + packed = bl.raw + + kasten.Kasten(bl.id, packed, anonvdf.AnonVDFGenerator, auto_check_generator=True) + print(bl.id) + fake_id = b'01' + bl.id[2:] + + self.assertRaises(kasten.exceptions.InvalidID, kasten.Kasten, fake_id, packed, anonvdf.AnonVDFGenerator, auto_check_generator=True) + + fake_id = bytearray(bl.id) + fake_id[32] = 13 + fake_id[34] = 13 + fake_id[120] = 13 + fake_id = bytes(fake_id).replace(b'\r', b'') + print(fake_id.replace(b'\r', b'')) + + kasten.Kasten(fake_id, packed, anonvdf.AnonVDFGenerator, auto_check_generator=True) + unittest.main() \ No newline at end of file diff --git a/tests/test_signedby.py b/tests/test_signedby.py deleted file mode 100644 index 90cf3e0..0000000 --- a/tests/test_signedby.py +++ /dev/null @@ -1,44 +0,0 @@ -import unittest -from onionrblocks.generators import signedby -import kasten -import hashlib -from nacl.signing import SigningKey, VerifyKey - -from time import time -from math import floor - -def sha3_hash_bytes(data): - return hashlib.sha3_256(data).digest() - -class TestSignedByProof(unittest.TestCase): - def test_signed_by_create(self): - key = SigningKey.generate() - test_data = kasten.generator.pack.pack( - b"test", "tst") - gen = signedby.Signed.generate(test_data, key) - self.assertEqual( - gen.get_packed(), - test_data - ) - hashed = hashlib.sha3_256(test_data).digest() - signed = key.sign(hashed) - self.assertEqual(signed, gen.id) - key.verify_key.verify(signed) - self.assertEqual(hashlib.sha3_256(test_data).digest(), signed[64:]) - - def test_signed_by_create_raw_keys(self): - key = SigningKey.generate() - test_data = kasten.generator.pack.pack( - b"test", "tst") - gen = signedby.Signed.generate(test_data, key.encode()) - self.assertEqual( - gen.get_packed(), - test_data - ) - hashed = hashlib.sha3_256(test_data).digest() - signed = key.sign(hashed) - self.assertEqual(signed, gen.id) - key.verify_key.verify(signed) - self.assertEqual(hashlib.sha3_256(test_data).digest(), signed[64:]) - -unittest.main() \ No newline at end of file