mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
sha256 fulfillment
tests
This commit is contained in:
parent
821ca9f8e6
commit
9bd1e9ff8b
@ -51,8 +51,10 @@ class BitmaskRegistry:
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
from bigchaindb.crypto.fulfillments.sha256 import Sha256Fulfillment
|
||||||
from bigchaindb.crypto.fulfillments.threshold_sha256 import ThresholdSha256Fulfillment
|
from bigchaindb.crypto.fulfillments.threshold_sha256 import ThresholdSha256Fulfillment
|
||||||
from bigchaindb.crypto.fulfillments.ed25519_sha256 import Ed25519Sha256Fulfillment
|
from bigchaindb.crypto.fulfillments.ed25519_sha256 import Ed25519Sha256Fulfillment
|
||||||
|
|
||||||
|
BitmaskRegistry.register_type(Sha256Fulfillment)
|
||||||
BitmaskRegistry.register_type(ThresholdSha256Fulfillment)
|
BitmaskRegistry.register_type(ThresholdSha256Fulfillment)
|
||||||
BitmaskRegistry.register_type(Ed25519Sha256Fulfillment)
|
BitmaskRegistry.register_type(Ed25519Sha256Fulfillment)
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from abc import ABCMeta, abstractmethod
|
|||||||
from six import string_types
|
from six import string_types
|
||||||
|
|
||||||
from bigchaindb.crypto.condition import Condition
|
from bigchaindb.crypto.condition import Condition
|
||||||
from bigchaindb.crypto.iostream import Writer, base64_remove_padding, Reader, base64_add_padding
|
from bigchaindb.crypto.iostream import Writer, base64_remove_padding, Reader, base64_add_padding, Predictor
|
||||||
|
|
||||||
FULFILLMENT_REGEX = r'^cf:1:[1-9a-f][0-9a-f]{0,2}:[a-zA-Z0-9_-]+$'
|
FULFILLMENT_REGEX = r'^cf:1:[1-9a-f][0-9a-f]{0,2}:[a-zA-Z0-9_-]+$'
|
||||||
|
|
||||||
@ -179,9 +179,7 @@ class Fulfillment(metaclass=ABCMeta):
|
|||||||
Return:
|
Return:
|
||||||
{Number} Maximum fulfillment length
|
{Number} Maximum fulfillment length
|
||||||
"""
|
"""
|
||||||
# TODO: Predictor
|
predictor = Predictor()
|
||||||
# predictor = Predictor()
|
|
||||||
predictor = None
|
|
||||||
self.write_payload(predictor)
|
self.write_payload(predictor)
|
||||||
return predictor.size
|
return predictor.size
|
||||||
|
|
||||||
|
|||||||
@ -164,6 +164,17 @@ class Ed25519Sha256Fulfillment(BaseSha256Fulfillment):
|
|||||||
|
|
||||||
This writes the fulfillment payload to a Writer.
|
This writes the fulfillment payload to a Writer.
|
||||||
|
|
||||||
|
COMMON_HEADER =
|
||||||
|
VARBYTES PUBLIC_KEY
|
||||||
|
VARBYTES MESSAGE_ID
|
||||||
|
VARBYTES FIXED_PREFIX
|
||||||
|
VARUINT DYNAMIC_MESSAGE_LENGTH
|
||||||
|
|
||||||
|
FULFILLMENT_PAYLOAD =
|
||||||
|
COMMON_HEADER
|
||||||
|
VARBYTES DYNAMIC_MESSAGE
|
||||||
|
VARBYTES SIGNATURE
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
writer (Writer): Subject for writing the fulfillment payload.
|
writer (Writer): Subject for writing the fulfillment payload.
|
||||||
"""
|
"""
|
||||||
@ -178,6 +189,16 @@ class Ed25519Sha256Fulfillment(BaseSha256Fulfillment):
|
|||||||
|
|
||||||
Writes the contents of the condition hash to a Hasher. Used internally by `condition`.
|
Writes the contents of the condition hash to a Hasher. Used internally by `condition`.
|
||||||
|
|
||||||
|
COMMON_HEADER =
|
||||||
|
VARBYTES PUBLIC_KEY
|
||||||
|
VARBYTES MESSAGE_ID
|
||||||
|
VARBYTES FIXED_PREFIX
|
||||||
|
VARUINT DYNAMIC_MESSAGE_LENGTH
|
||||||
|
|
||||||
|
HASH = SHA256(
|
||||||
|
COMMON_HEADER
|
||||||
|
)
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
hasher (Hasher): Destination where the hash payload will be written.
|
hasher (Hasher): Destination where the hash payload will be written.
|
||||||
"""
|
"""
|
||||||
|
|||||||
94
bigchaindb/crypto/fulfillments/sha256.py
Normal file
94
bigchaindb/crypto/fulfillments/sha256.py
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
from bigchaindb.crypto.fulfillments.base_sha256 import BaseSha256Fulfillment
|
||||||
|
from bigchaindb.crypto.iostream import Hasher, Reader, Writer, Predictor
|
||||||
|
|
||||||
|
|
||||||
|
class Sha256Fulfillment(BaseSha256Fulfillment):
|
||||||
|
|
||||||
|
_bitmask = 0x01
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._preimage = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def preimage(self):
|
||||||
|
return self._preimage
|
||||||
|
|
||||||
|
@preimage.setter
|
||||||
|
def preimage(self, value):
|
||||||
|
"""
|
||||||
|
Provide a preimage.
|
||||||
|
|
||||||
|
The preimage is the only input to a SHA256 hashlock condition.
|
||||||
|
|
||||||
|
Note that the preimage should contain enough (pseudo-random) data in order
|
||||||
|
to be difficult to guess. A sufficiently large secret seed and a
|
||||||
|
cryptographically secure pseudo-random number generator (CSPRNG) can be
|
||||||
|
used to avoid having to store each individual preimage.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: Secret data that will be hashed to form the condition.
|
||||||
|
"""
|
||||||
|
# TODO: Verify preimage
|
||||||
|
self._preimage = value
|
||||||
|
|
||||||
|
def write_hash_payload(self, hasher):
|
||||||
|
"""
|
||||||
|
Generate the contents of the condition hash.
|
||||||
|
|
||||||
|
Writes the contents of the condition hash to a Hasher. Used internally by `getCondition`.
|
||||||
|
|
||||||
|
HASH = SHA256(PREIMAGE)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
hasher (Hasher): Destination where the hash payload will be written.
|
||||||
|
"""
|
||||||
|
if not isinstance(hasher, Hasher):
|
||||||
|
raise TypeError('hasher must be a Hasher instance')
|
||||||
|
if self.preimage is None:
|
||||||
|
raise ValueError('Could not calculate hash, no preimage provided')
|
||||||
|
hasher.write(self.preimage)
|
||||||
|
|
||||||
|
def parse_payload(self, reader):
|
||||||
|
"""
|
||||||
|
Parse the payload of a SHA256 hashlock fulfillment.
|
||||||
|
|
||||||
|
Read a fulfillment payload from a Reader and populate this object with that fulfillment.
|
||||||
|
|
||||||
|
FULFILLMENT_PAYLOAD =
|
||||||
|
VARBYTES PREIMAGE
|
||||||
|
|
||||||
|
Args:
|
||||||
|
reader (Reader): Source to read the fulfillment payload from.
|
||||||
|
"""
|
||||||
|
if not isinstance(reader, Reader):
|
||||||
|
raise TypeError('reader must be a Reader instance')
|
||||||
|
self.preimage = reader.read_var_bytes()
|
||||||
|
|
||||||
|
def write_payload(self, writer):
|
||||||
|
"""
|
||||||
|
Generate the fulfillment payload.
|
||||||
|
|
||||||
|
This writes the fulfillment payload to a Writer.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
writer (Writer): Subject for writing the fulfillment payload.
|
||||||
|
"""
|
||||||
|
if not isinstance(writer, (Writer, Predictor)):
|
||||||
|
raise TypeError('writer must be a Writer instance')
|
||||||
|
if self.preimage is None:
|
||||||
|
raise ValueError('Preimage must be specified')
|
||||||
|
|
||||||
|
writer.write_var_bytes(self.preimage)
|
||||||
|
return writer
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
"""
|
||||||
|
Validate this fulfillment.
|
||||||
|
|
||||||
|
For a SHA256 hashlock fulfillment, successful parsing implies that the
|
||||||
|
fulfillment is valid, so this method is a no-op.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
boolean: Validation result
|
||||||
|
"""
|
||||||
|
return True
|
||||||
@ -102,6 +102,14 @@ class ThresholdSha256Fulfillment(BaseSha256Fulfillment):
|
|||||||
|
|
||||||
This function is called internally by the `getCondition` method.
|
This function is called internally by the `getCondition` method.
|
||||||
|
|
||||||
|
HASH = SHA256(
|
||||||
|
VARUINT TYPE_BIT
|
||||||
|
VARUINT THRESHOLD
|
||||||
|
VARARRAY
|
||||||
|
VARUINT WEIGHT
|
||||||
|
CONDITION
|
||||||
|
)
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
hasher (Hasher): Hash generator
|
hasher (Hasher): Hash generator
|
||||||
"""
|
"""
|
||||||
@ -182,6 +190,15 @@ class ThresholdSha256Fulfillment(BaseSha256Fulfillment):
|
|||||||
|
|
||||||
This writes the fulfillment payload to a Writer.
|
This writes the fulfillment payload to a Writer.
|
||||||
|
|
||||||
|
FULFILLMENT_PAYLOAD =
|
||||||
|
VARUINT THRESHOLD
|
||||||
|
VARARRAY
|
||||||
|
VARUINT WEIGHT
|
||||||
|
FULFILLMENT
|
||||||
|
VARARRAY
|
||||||
|
VARUINT WEIGHT
|
||||||
|
CONDITION
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
writer (Writer): Subject for writing the fulfillment payload.
|
writer (Writer): Subject for writing the fulfillment payload.
|
||||||
"""
|
"""
|
||||||
@ -195,6 +212,7 @@ class ThresholdSha256Fulfillment(BaseSha256Fulfillment):
|
|||||||
# Prefer shorter fulfillments
|
# Prefer shorter fulfillments
|
||||||
fulfillments.sort(key=lambda f: len(f['binary']))
|
fulfillments.sort(key=lambda f: len(f['binary']))
|
||||||
|
|
||||||
|
# Cut off unnecessary fulfillments
|
||||||
if len(fulfillments) < self.threshold:
|
if len(fulfillments) < self.threshold:
|
||||||
raise ValueError('Not enough subfulfillments')
|
raise ValueError('Not enough subfulfillments')
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ from bigchaindb.crypto.condition import Condition
|
|||||||
from bigchaindb.crypto.ed25519 import ED25519PrivateKey, ED25519PublicKey
|
from bigchaindb.crypto.ed25519 import ED25519PrivateKey, ED25519PublicKey
|
||||||
from bigchaindb.crypto.fulfillment import Fulfillment
|
from bigchaindb.crypto.fulfillment import Fulfillment
|
||||||
from bigchaindb.crypto.fulfillments.ed25519_sha256 import Ed25519Sha256Fulfillment
|
from bigchaindb.crypto.fulfillments.ed25519_sha256 import Ed25519Sha256Fulfillment
|
||||||
|
from bigchaindb.crypto.fulfillments.sha256 import Sha256Fulfillment
|
||||||
from bigchaindb.crypto.fulfillments.threshold_sha256 import ThresholdSha256Fulfillment
|
from bigchaindb.crypto.fulfillments.threshold_sha256 import ThresholdSha256Fulfillment
|
||||||
|
|
||||||
|
|
||||||
@ -20,6 +21,38 @@ class TestBigchainILPSha256Condition:
|
|||||||
assert condition.serialize_uri() == self.CONDITION_SHA256_ILP
|
assert condition.serialize_uri() == self.CONDITION_SHA256_ILP
|
||||||
|
|
||||||
|
|
||||||
|
class TestBigchainILPSha256Fulfillment:
|
||||||
|
CONDITION_SHA256_ILP = 'cc:1:1:47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU:1'
|
||||||
|
FULFILLMENT_SHA256_ILP = 'cf:1:1:AA'
|
||||||
|
|
||||||
|
def test_deserialize_and_validate_fulfillment(self):
|
||||||
|
fulfillment = Fulfillment.from_uri(self.FULFILLMENT_SHA256_ILP)
|
||||||
|
assert fulfillment.serialize_uri() == self.FULFILLMENT_SHA256_ILP
|
||||||
|
assert fulfillment.condition.serialize_uri() == self.CONDITION_SHA256_ILP
|
||||||
|
assert fulfillment.validate()
|
||||||
|
|
||||||
|
def test_deserialize_condition_and_validate_fulfillment(self):
|
||||||
|
condition = Condition.from_uri(self.CONDITION_SHA256_ILP)
|
||||||
|
fulfillment = Sha256Fulfillment()
|
||||||
|
fulfillment.preimage = ''
|
||||||
|
assert fulfillment.serialize_uri() == self.FULFILLMENT_SHA256_ILP
|
||||||
|
assert fulfillment.condition.serialize_uri() == condition.serialize_uri()
|
||||||
|
assert fulfillment.validate()
|
||||||
|
|
||||||
|
def test_condition_from_fulfillment(self):
|
||||||
|
fulfillment = Sha256Fulfillment()
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
fulfillment.condition
|
||||||
|
|
||||||
|
fulfillment.preimage = 'Hello World!'
|
||||||
|
condition = fulfillment.condition
|
||||||
|
|
||||||
|
verify_fulfillment = Sha256Fulfillment()
|
||||||
|
verify_fulfillment.preimage = 'Hello World!'
|
||||||
|
assert verify_fulfillment.condition.serialize_uri() == condition.serialize_uri()
|
||||||
|
assert verify_fulfillment.validate()
|
||||||
|
|
||||||
|
|
||||||
class TestBigchainILPEd25519Sha256Fulfillment:
|
class TestBigchainILPEd25519Sha256Fulfillment:
|
||||||
PUBLIC_HEX_ILP = b'ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf'
|
PUBLIC_HEX_ILP = b'ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf'
|
||||||
PUBLIC_B64_ILP = b'7Bcrk61eVjv0kyxw4SRQNMNUZ+8u/U1k6/gZaDRn4r8'
|
PUBLIC_B64_ILP = b'7Bcrk61eVjv0kyxw4SRQNMNUZ+8u/U1k6/gZaDRn4r8'
|
||||||
@ -133,12 +166,14 @@ class TestBigchainILPThresholdSha256Fulfillment:
|
|||||||
'mUhQNmD2Cvk7e3EFOo-arA2TKYTP-474Z4okhbYmKij6XxObIbRsDScjXILAJ6mV5hP7Xyqkg5fcSsZbfRYypzlsAM'
|
'mUhQNmD2Cvk7e3EFOo-arA2TKYTP-474Z4okhbYmKij6XxObIbRsDScjXILAJ6mV5hP7Xyqkg5fcSsZbfRYypzlsAM'
|
||||||
HASH_ED25519_HEX_ILP = b'a9020d5b6ba6e7d0b80c1f494955c7d6282a026698186aabca59475200a97cf5'
|
HASH_ED25519_HEX_ILP = b'a9020d5b6ba6e7d0b80c1f494955c7d6282a026698186aabca59475200a97cf5'
|
||||||
|
|
||||||
CONDITION_THRESHOLD_ED25519_ILP_2 = 'cc:1:c:IZgoTeE1Weg6tfGMLWGe2JmS-waBN-CUrlbhtI9GBcQ:230'
|
CONDITION_SHA256_ILP = 'cc:1:1:47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU:1'
|
||||||
|
FULFILLMENT_SHA256_ILP = 'cf:1:1:AA'
|
||||||
|
|
||||||
|
CONDITION_THRESHOLD_ED25519_ILP_2 = 'cc:1:d:fDM51fekeLlbeF9yj9W1KT76jtqa7u0vMlJAbM4EyiE:230'
|
||||||
FULFILLMENT_THRESHOLD_ED25519_ILP_2 = \
|
FULFILLMENT_THRESHOLD_ED25519_ILP_2 = \
|
||||||
'cf:1:4:AgIBCCDsFyuTrV5WO_STLHDhJFA0w1Rn7y79TWTr-BloNGfivwxIZWxsbyB3b3JsZCEgFSBDb25kaXRpb25zIGFyZSBoZXJlIUBDW' \
|
'cf:1:4:AgIBAQABCCDsFyuTrV5WO_STLHDhJFA0w1Rn7y79TWTr-BloNGfivwxIZWxsbyB3b3JsZCEgFSBDb25kaXRpb25zIGFyZSBoZXJlI' \
|
||||||
'6ped9T2wiZUVLyoz-epNFyiTDqyBqNheurnrk7UZ2KyQdrdmbbXX1zOIMw__O3h9Z2U6buK05AMfNYUnacCAQgg7Bcrk61eVjv0kyxw4SRQN' \
|
'UBDW6ped9T2wiZUVLyoz-epNFyiTDqyBqNheurnrk7UZ2KyQdrdmbbXX1zOIMw__O3h9Z2U6buK05AMfNYUnacCAQEIIP1s06x7xZ7-CPh9H' \
|
||||||
'MNUZ-8u_U1k6_gZaDRn4r8MSGVsbG8gd29ybGQhIBUgQ29uZGl0aW9ucyBhcmUgaGVyZSFAQ1uqXnfU9sImVFS8qM_nqTRcokw6sgajYXrq5' \
|
'AClmekN4N2NA7t2ltNZyLGgLIqPdA'
|
||||||
'65O1GdiskHa3Zm2119cziDMP_zt4fWdlOm7itOQDHzWFJ2nAgEBCCD9bNOse8We_gj4fRwApZnpDeDdjQO7dpbTWcixoCyKj3Q'
|
|
||||||
|
|
||||||
def create_fulfillment_ed25519sha256(self):
|
def create_fulfillment_ed25519sha256(self):
|
||||||
sk = ED25519PrivateKey(self.PRIVATE_B58_ILP)
|
sk = ED25519PrivateKey(self.PRIVATE_B58_ILP)
|
||||||
@ -153,8 +188,9 @@ class TestBigchainILPThresholdSha256Fulfillment:
|
|||||||
return fulfillment
|
return fulfillment
|
||||||
|
|
||||||
def test_serialize_condition_and_validate_fulfillment(self):
|
def test_serialize_condition_and_validate_fulfillment(self):
|
||||||
ilp_fulfillment = Fulfillment.from_uri(self.FULFILLMENT_ED25519_ILP)
|
ilp_fulfillment = Fulfillment.from_uri(self.FULFILLMENT_ED25519_ILP_2)
|
||||||
ilp_fulfillment_2 = Fulfillment.from_uri(self.FULFILLMENT_ED25519_ILP_2)
|
ilp_fulfillment_2 = Fulfillment.from_uri(self.FULFILLMENT_ED25519_ILP)
|
||||||
|
ilp_fulfillment_3 = Fulfillment.from_uri(self.FULFILLMENT_SHA256_ILP)
|
||||||
|
|
||||||
assert ilp_fulfillment.validate() == True
|
assert ilp_fulfillment.validate() == True
|
||||||
assert ilp_fulfillment_2.validate() == True
|
assert ilp_fulfillment_2.validate() == True
|
||||||
@ -163,9 +199,9 @@ class TestBigchainILPThresholdSha256Fulfillment:
|
|||||||
|
|
||||||
# Create a threshold condition
|
# Create a threshold condition
|
||||||
fulfillment = ThresholdSha256Fulfillment()
|
fulfillment = ThresholdSha256Fulfillment()
|
||||||
|
fulfillment.add_subfulfillment(ilp_fulfillment)
|
||||||
fulfillment.add_subfulfillment(ilp_fulfillment_2)
|
fulfillment.add_subfulfillment(ilp_fulfillment_2)
|
||||||
fulfillment.add_subfulfillment(ilp_fulfillment)
|
fulfillment.add_subfulfillment(ilp_fulfillment_3)
|
||||||
fulfillment.add_subfulfillment(ilp_fulfillment)
|
|
||||||
fulfillment.threshold = THRESHOLD # defaults to subconditions.length
|
fulfillment.threshold = THRESHOLD # defaults to subconditions.length
|
||||||
|
|
||||||
assert fulfillment.condition.serialize_uri() == self.CONDITION_THRESHOLD_ED25519_ILP_2
|
assert fulfillment.condition.serialize_uri() == self.CONDITION_THRESHOLD_ED25519_ILP_2
|
||||||
@ -185,6 +221,10 @@ class TestBigchainILPThresholdSha256Fulfillment:
|
|||||||
assert len(fulfillment.get_all_subconditions()) == NUM_FULFILLMENTS
|
assert len(fulfillment.get_all_subconditions()) == NUM_FULFILLMENTS
|
||||||
assert fulfillment.serialize_uri() == self.FULFILLMENT_THRESHOLD_ED25519_ILP_2
|
assert fulfillment.serialize_uri() == self.FULFILLMENT_THRESHOLD_ED25519_ILP_2
|
||||||
assert fulfillment.validate()
|
assert fulfillment.validate()
|
||||||
|
assert isinstance(fulfillment.subfulfillments[0], Sha256Fulfillment)
|
||||||
|
assert isinstance(fulfillment.subfulfillments[1], Ed25519Sha256Fulfillment)
|
||||||
|
assert fulfillment.subfulfillments[0].condition.serialize_uri() == self.CONDITION_SHA256_ILP
|
||||||
|
assert fulfillment.subfulfillments[1].condition.serialize_uri() == self.CONDITION_ED25519_ILP
|
||||||
|
|
||||||
def test_serialize_deserialize_fulfillment(self):
|
def test_serialize_deserialize_fulfillment(self):
|
||||||
ilp_fulfillment = Fulfillment.from_uri(self.FULFILLMENT_ED25519_ILP)
|
ilp_fulfillment = Fulfillment.from_uri(self.FULFILLMENT_ED25519_ILP)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user