Adjusting block generation to use ttl instead of rounds in metadata
This commit is contained in:
parent
7d8781c57d
commit
6537362e3d
@ -2,6 +2,10 @@
|
||||
|
||||
This project uses Semantic Versioning
|
||||
|
||||
## 5.0.0
|
||||
|
||||
- Removed signedby
|
||||
|
||||
## 4.0.0
|
||||
|
||||
* Make blocks less expensive
|
||||
|
@ -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
|
||||
|
30
onionrblocks/block.py
Normal file
30
onionrblocks/block.py
Normal file
@ -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)
|
||||
|
@ -16,17 +16,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
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)
|
@ -1,2 +1 @@
|
||||
from .anonvdf import AnonVDFGenerator
|
||||
from .signedby import Signed
|
@ -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")
|
||||
|
@ -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))
|
@ -1,2 +1 @@
|
||||
kasten==3.0.0
|
||||
PyNaCl==1.4.0
|
2
setup.py
2
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',
|
||||
|
@ -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()
|
@ -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()
|
Loading…
Reference in New Issue
Block a user