Skip to content

Commit 38f0a20

Browse files
author
Greg S
committed
#356: use keccak for merkle hash in aggregate transactions (may be reverted)
1 parent 15c276e commit 38f0a20

File tree

3 files changed

+65
-34
lines changed

3 files changed

+65
-34
lines changed

src/core/crypto/MerkleHashBuilder.ts

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,46 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
16+
import { SHA3Hasher } from './SHA3Hasher';
1717
import { SignSchema } from './SignSchema';
1818

1919
export class MerkleHashBuilder {
2020

21-
hashes: Uint8Array[] = new Array<Uint8Array>();
22-
hasherFactory: any;
23-
signSchema: SignSchema;
24-
length: number;
21+
/**
22+
* The list of hashes used to calculate root hash.
23+
*
24+
* @var {Uint8Array}
25+
*/
26+
protected hashes: Uint8Array[] = new Array<Uint8Array>();
2527

2628
/**
2729
* Constructor
28-
* @param hasherFactory Hasher (SHA3_256)
2930
* @param signSchema Sign schema
3031
* @param length Hash size
3132
*/
32-
constructor(hasherFactory: any, signSchema: SignSchema = SignSchema.SHA3, length: number = 32) {
33-
this.hasherFactory = hasherFactory;
34-
this.signSchema = signSchema;
35-
this.length = length;
33+
constructor(/**
34+
* Length of produced merkle hash in bytes.
35+
*
36+
* @var {number}
37+
*/
38+
public readonly length: 32 | 64,
39+
/**
40+
* Signature schema used (hash algorithm diff)
41+
*
42+
* @var {SignSchema}
43+
*/
44+
public readonly signSchema: SignSchema) {
3645
}
3746

38-
/** @internal
47+
/**
3948
* Hash inner transactions
49+
*
50+
* @internal
4051
* @param hashes Inner transaction hashes
52+
* @return {Uint8Array}
4153
*/
4254
protected hash(hashes: Uint8Array[]): Uint8Array {
43-
const hasher = this.hasherFactory(this.length, this.signSchema);
55+
const hasher = SHA3Hasher.createHasher(this.length, this.signSchema);
4456
hasher.reset();
4557

4658
hashes.forEach((hashVal: Uint8Array) => {
@@ -52,9 +64,12 @@ export class MerkleHashBuilder {
5264
return hash;
5365
}
5466

55-
/** @internal
56-
* Get root hash of Merkle Trees
57-
* @param hashes Inner transaction hashes
67+
/**
68+
* Get root hash of Merkle Tree
69+
*
70+
* @internal
71+
* @param {Uint8Array[]} hashes Inner transaction hashes
72+
* @return {Uint8Array}
5873
*/
5974
protected calculateRootHash(hashes: Uint8Array[]): Uint8Array {
6075

@@ -80,18 +95,22 @@ export class MerkleHashBuilder {
8095
}
8196

8297
/**
83-
* Return root hash from Merkle tree
98+
* Get root hash of Merkle tree
99+
*
100+
* @return {Uint8Array}
84101
*/
85102
public getRootHash(): Uint8Array {
86103
return this.calculateRootHash(this.hashes);
87104
}
88105

89106
/**
90-
* Update hashes array
107+
* Update hashes array (add hash)
108+
*
91109
* @param hash Inner transaction hash buffer
110+
* @return {MerkleHashBuilder}
92111
*/
93-
public update(hash: Uint8Array): void {
112+
public update(hash: Uint8Array): MerkleHashBuilder {
94113
this.hashes.push(hash);
114+
return this;
95115
}
96-
97116
}

src/model/transaction/AggregateTransaction.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ export class AggregateTransaction extends Transaction {
340340
this.type.valueOf(),
341341
new AmountDto(this.maxFee.toDTO()),
342342
new TimestampDto(this.deadline.toDTO()),
343-
new Hash256Dto(this.calculateInnerTransactionHash()),
343+
new Hash256Dto(this.calculateInnerTransactionHash(this.networkType)),
344344
transactions,
345345
cosignatures,
346346
) :
@@ -352,7 +352,7 @@ export class AggregateTransaction extends Transaction {
352352
this.type.valueOf(),
353353
new AmountDto(this.maxFee.toDTO()),
354354
new TimestampDto(this.deadline.toDTO()),
355-
new Hash256Dto(this.calculateInnerTransactionHash()),
355+
new Hash256Dto(this.calculateInnerTransactionHash(this.networkType)),
356356
transactions,
357357
cosignatures,
358358
);
@@ -372,11 +372,23 @@ export class AggregateTransaction extends Transaction {
372372
* Generate inner transaction root hash (merkle tree)
373373
* @returns {Uint8Array}
374374
*/
375-
private calculateInnerTransactionHash(): Uint8Array {
376-
const builder = new MerkleHashBuilder(SHA3Hasher.createHasher);
375+
private calculateInnerTransactionHash(networkType: NetworkType): Uint8Array {
376+
const signSchema = SHA3Hasher.resolveSignSchema(networkType);
377+
const hasher = SHA3Hasher.createHasher(32, signSchema);
378+
const builder = new MerkleHashBuilder(32, signSchema);
377379
this.innerTransactions.forEach((transaction) => {
378-
builder.update(RawArray.uint8View(sha3_256.arrayBuffer(transaction.toAggregateTransactionBytes())));
380+
const entityHash: Uint8Array = new Uint8Array(32);
381+
382+
// for each embedded transaction hash their body
383+
hasher.reset();
384+
hasher.update(transaction.toAggregateTransactionBytes());
385+
hasher.finalize(entityHash);
386+
387+
// update merkle tree (add transaction hash)
388+
builder.update(entityHash);
379389
});
390+
391+
// calculate root hash with all transactions
380392
return builder.getRootHash();
381393
}
382394

test/core/crypto/MerkleHashBuilder.spec.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,23 @@
1515
*/
1616

1717
import { expect } from 'chai';
18-
import { MerkleHashBuilder, SHA3Hasher } from '../../../src/core/crypto';
18+
import { MerkleHashBuilder, SHA3Hasher, SignSchema } from '../../../src/core/crypto';
1919
import { Convert } from '../../../src/core/format';
2020

21-
describe('MerkleHashBuilder tests', () => {
22-
it('Zero Value', () => {
21+
describe('MerkleHashBuilder should', () => {
22+
it('fill 0s for empty merkle tree', () => {
2323
// Arrange:
24-
const builder = new MerkleHashBuilder(SHA3Hasher.createHasher);
24+
const builder = new MerkleHashBuilder(32, SignSchema.SHA3);
2525

2626
const rootHash = builder.getRootHash();
2727

2828
expect(Convert.uint8ToHex(rootHash)).equal('0000000000000000000000000000000000000000000000000000000000000000');
2929

3030
});
3131

32-
it('One Value', () => {
32+
it('return first hash given single child', () => {
3333
// Arrange:
34-
const builder = new MerkleHashBuilder(SHA3Hasher.createHasher);
34+
const builder = new MerkleHashBuilder(32, SignSchema.SHA3);
3535

3636
builder.update(Convert.hexToUint8('215B158F0BD416B596271BCE527CD9DC8E4A639CC271D896F9156AF6F441EEB9'));
3737

@@ -41,9 +41,9 @@ describe('MerkleHashBuilder tests', () => {
4141

4242
});
4343

44-
it('Two Values', () => {
44+
it('create correct merkle hash given two children', () => {
4545
// Arrange:
46-
const builder = new MerkleHashBuilder(SHA3Hasher.createHasher);
46+
const builder = new MerkleHashBuilder(32, SignSchema.SHA3);
4747

4848
builder.update(Convert.hexToUint8('215b158f0bd416b596271bce527cd9dc8e4a639cc271d896f9156af6f441eeb9'));
4949
builder.update(Convert.hexToUint8('976c5ce6bf3f797113e5a3a094c7801c885daf783c50563ffd3ca6a5ef580e25'));
@@ -54,9 +54,9 @@ describe('MerkleHashBuilder tests', () => {
5454

5555
});
5656

57-
it('Three Values', () => {
57+
it('create correct merkle hash given three children', () => {
5858
// Arrange:
59-
const builder = new MerkleHashBuilder(SHA3Hasher.createHasher);
59+
const builder = new MerkleHashBuilder(32, SignSchema.SHA3);
6060

6161
builder.update(Convert.hexToUint8('215b158f0bd416b596271bce527cd9dc8e4a639cc271d896f9156af6f441eeb9'));
6262
builder.update(Convert.hexToUint8('976c5ce6bf3f797113e5a3a094c7801c885daf783c50563ffd3ca6a5ef580e25'));

0 commit comments

Comments
 (0)