added signedby proof
This commit is contained in:
parent
b0dc7d75e5
commit
cd53b4dde2
@ -8,3 +8,5 @@ AnonymousVDFBlockResult = namedtuple(
|
|||||||
HexChecksum = NewType("HexChecksum", str)
|
HexChecksum = NewType("HexChecksum", str)
|
||||||
DecChecksum = NewType("DecChecksum", int)
|
DecChecksum = NewType("DecChecksum", int)
|
||||||
DecChecksumStr = NewType("DecChecksumStr", str)
|
DecChecksumStr = NewType("DecChecksumStr", str)
|
||||||
|
RawEd25519PrivateKey = NewType("RawEd25519PrivateKey", bytes)
|
||||||
|
RawEd25519PublicKey = NewType("RawEd25519PublicKey", bytes)
|
||||||
|
@ -13,7 +13,8 @@ class AnonVDFGenerator(generator.KastenBaseGenerator):
|
|||||||
def get_ttl_seconds_per_rounds(cls, rounds: int):
|
def get_ttl_seconds_per_rounds(cls, rounds: int):
|
||||||
# 8000 rounds = 1 second (2.8ghz python) = 1 hour storage
|
# 8000 rounds = 1 second (2.8ghz python) = 1 hour storage
|
||||||
if rounds < 8000:
|
if rounds < 8000:
|
||||||
raise ValueError("Rounds must be at least 8000")
|
raise ValueError(
|
||||||
|
"Rounds must be at least 8000")
|
||||||
return (rounds / 8000) * 60
|
return (rounds / 8000) * 60
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
55
onionrblocks/generators/signedby.py
Normal file
55
onionrblocks/generators/signedby.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
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:
|
||||||
|
# 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))
|
44
tests/test_signedby.py
Normal file
44
tests/test_signedby.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
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