Speed up hashing of transactions and hashes

Calculate hashing without first concatenating bytes.
This commit is contained in:
Mark Spanbroek 2021-09-01 13:00:32 +02:00
parent 7e705dba3f
commit 652e34d6b2
5 changed files with 38 additions and 19 deletions

View File

@ -13,13 +13,15 @@ type
hash: Hash
signature: ?Signature
func toBytes*(ack: Ack): seq[byte] =
func calculateHash(ack: Ack) =
var hashing = Hashing.init(HashKind.Ack)
let previous = ack.previous |? Hash.default
result.add(previous.toBytes)
result.add(ack.transactions.len.uint8)
hashing.update(previous.toBytes)
hashing.update([ack.transactions.len.uint8])
for transaction in ack.transactions:
result.add(transaction.toBytes)
result.add(ack.validator.toBytes)
hashing.update(transaction.toBytes)
hashing.update(ack.validator.toBytes)
ack.hash = hashing.finish()
func new(_: type Ack,
previous: ?Hash,
@ -40,7 +42,7 @@ func new(_: type Ack,
transactions: @transactions,
validator: validator
)
ack.hash = hash(ack.toBytes, HashKind.Ack)
ack.calculateHash()
some ack
func new*(_: type Ack,

View File

@ -6,6 +6,9 @@ type
Hash* = object
kind*: HashKind
hash: MDigest[256]
Hashing* = object
kind: HashKind
context: sha256
func hash*(bytes: openArray[byte], kind: HashKind): Hash =
Hash(kind: kind, hash: sha256.digest(bytes))
@ -22,3 +25,15 @@ func `$`*(hash: Hash): string =
"Tx(" & $hash.hash & ")"
of Ack:
"Ack(" & $hash.hash & ")"
func init*(_: type Hashing, kind: HashKind): Hashing =
result.kind = kind
result.context.init()
func update*(hashing: var Hashing, bytes: openArray[byte]) =
hashing.context.update(bytes)
func finish*(hashing: var Hashing): Hash =
let hash = hashing.context.finish()
hashing.context.clear()
Hash(kind: hashing.kind, hash: hash)

View File

@ -25,16 +25,18 @@ type
owner: PublicKey
value: UInt256
func toBytes*(transaction: Transaction): seq[byte] =
result.add(transaction.inputs.len.uint8)
func calculateHash(transaction: Transaction) =
var hashing = Hashing.init(HashKind.Tx)
hashing.update([transaction.inputs.len.uint8])
for (txHash, owner) in transaction.inputs:
result.add(txHash.toBytes)
result.add(owner.toBytes)
result.add(transaction.outputs.len.uint8)
hashing.update(txHash.toBytes)
hashing.update(owner.toBytes)
hashing.update([transaction.outputs.len.uint8])
for (owner, value) in transaction.outputs:
result.add(owner.toBytes)
result.add(value.toBytes)
result.add(transaction.validator.toBytes)
hashing.update(owner.toBytes)
hashing.update(value.toBytes)
hashing.update(transaction.validator.toBytes)
transaction.hash = hashing.finish()
func new*(_: type Transaction,
inputs: openArray[TxInput],
@ -55,7 +57,7 @@ func new*(_: type Transaction,
outputs: @outputs,
validator: validator
)
transaction.hash = hash(transaction.toBytes, HashKind.Tx)
transaction.calculateHash()
some transaction
func new*(_: type Transaction,

View File

@ -28,7 +28,7 @@ suite "Acknowledgements":
check ack.?previous == previous.hash.some
check ack.?validator == victor.some
test "an acknowledgement can be converted to bytes":
test "an acknowledgement hash is derived from its fields":
let previous = Ack.example
let ack = !Ack.new(previous.hash, [tx1.hash, tx2.hash], victor)
var expected: seq[byte]
@ -37,7 +37,7 @@ suite "Acknowledgements":
expected.add(tx1.hash.toBytes)
expected.add(tx2.hash.toBytes)
expected.add(victor.toBytes)
check ack.toBytes == expected
check ack.hash == hash(expected, HashKind.Ack)
test "a signature can be added to an acknowledgment":
let key = PrivateKey.example

View File

@ -37,7 +37,7 @@ suite "Transactions":
check genesis.outputValue(bob) == 10.u256
check genesis.outputValue(victor) == 0.u256
test "a transaction can be converted to bytes":
test "a transaction hash is derived from its fields":
let genesis = !Transaction.new({alice: 32.u256, bob: 10.u256}, victor)
let transaction = !Transaction.new(
{genesis.hash: alice},
@ -54,7 +54,7 @@ suite "Transactions":
expected.add(bob.toBytes)
expected.add(30.u256.toBytes)
expected.add(victor.toBytes)
check transaction.toBytes == expected
check transaction.hash == hash(expected, HashKind.Tx)
test "signatures can be added to a transaction":
let key1, key2 = PrivateKey.example