Skip to content

Commit 6c886dd

Browse files
committed
refactor: store pre-computed prefixes
1 parent d495765 commit 6c886dd

12 files changed

+144
-46
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"gitdiff:ci": "npm run build && git diff --exit-code",
3030
"integration": "npm run build && npm run nobuild:integration",
3131
"lint": "eslint ts_src/** src/**/*.js",
32+
"lint:fix": "eslint --fix ts_src/** src/**/*.js",
3233
"lint:tests": "eslint test/**/*.spec.ts",
3334
"mocha:ts": "mocha --recursive --require test/ts-node-register",
3435
"nobuild:coverage-report": "nyc report --reporter=lcov",
@@ -39,7 +40,8 @@
3940
"prettier": "prettier \"ts_src/**/*.ts\" \"test/**/*.ts\" --ignore-path ./.prettierignore",
4041
"prettierjs": "prettier \"src/**/*.js\" --ignore-path ./.prettierignore",
4142
"test": "npm run build && npm run format:ci && npm run lint && npm run nobuild:coverage",
42-
"unit": "npm run build && npm run nobuild:unit"
43+
"unit": "npm run build && npm run nobuild:unit",
44+
"generate:prefixes": "node scripts/generate-tagged-hash-prefixes.js && yarn prettierjs && yarn lint:fix"
4345
},
4446
"repository": {
4547
"type": "git",
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const { sha256 } = require('../src/crypto');
2+
const { TAGS } = require('../src/tags');
3+
const fs = require('fs');
4+
const path = require('path');
5+
6+
const taggedHashPrefixes = Object.fromEntries(
7+
TAGS.map(tag => {
8+
const tagHash = sha256(Buffer.from(tag));
9+
return [tag, Buffer.concat([tagHash, tagHash]).toString('hex')];
10+
}),
11+
);
12+
13+
let content = `
14+
interface StringMap {
15+
[key: string]: string;
16+
}
17+
export const TAGGED_HASH_PREFIXES_HEX: StringMap = ${JSON.stringify(
18+
taggedHashPrefixes,
19+
)}
20+
`;
21+
22+
fs.writeFileSync(
23+
path.resolve(__dirname, '../ts_src', 'tagged-hash-prefixes.ts'),
24+
content,
25+
{ encoding: 'utf8', flag: 'w' },
26+
);

src/crypto.d.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
/// <reference types="node" />
2+
import { TAGS } from './tags';
23
export declare function ripemd160(buffer: Buffer): Buffer;
34
export declare function sha1(buffer: Buffer): Buffer;
45
export declare function sha256(buffer: Buffer): Buffer;
56
export declare function hash160(buffer: Buffer): Buffer;
67
export declare function hash256(buffer: Buffer): Buffer;
7-
declare const TAGS: readonly ["BIP0340/challenge", "BIP0340/aux", "BIP0340/nonce", "TapLeaf", "TapBranch", "TapSighash", "TapTweak", "KeyAgg list", "KeyAgg coefficient"];
88
export type TaggedHashPrefix = typeof TAGS[number];
99
export declare function taggedHash(prefix: TaggedHashPrefix, data: Buffer): Buffer;
10-
export {};

src/crypto.js

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ exports.taggedHash =
99
void 0;
1010
const createHash = require('create-hash');
1111
const RipeMd160 = require('ripemd160');
12+
const tagged_hash_prefixes_1 = require('./tagged-hash-prefixes');
1213
function ripemd160(buffer) {
1314
try {
1415
return createHash('rmd160').update(buffer).digest();
@@ -37,28 +38,14 @@ function hash256(buffer) {
3738
return sha256(sha256(buffer));
3839
}
3940
exports.hash256 = hash256;
40-
const TAGS = [
41-
'BIP0340/challenge',
42-
'BIP0340/aux',
43-
'BIP0340/nonce',
44-
'TapLeaf',
45-
'TapBranch',
46-
'TapSighash',
47-
'TapTweak',
48-
'KeyAgg list',
49-
'KeyAgg coefficient',
50-
];
5141
/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
52-
let TAGGED_HASH_PREFIXES = undefined;
42+
const TAGGED_HASH_PREFIXES = Object.fromEntries(
43+
Object.keys(tagged_hash_prefixes_1.TAGGED_HASH_PREFIXES_HEX).map(tag => [
44+
tag,
45+
Buffer.from(tagged_hash_prefixes_1.TAGGED_HASH_PREFIXES_HEX[tag], 'hex'),
46+
]),
47+
);
5348
function taggedHash(prefix, data) {
54-
if (!TAGGED_HASH_PREFIXES) {
55-
TAGGED_HASH_PREFIXES = Object.fromEntries(
56-
TAGS.map(tag => {
57-
const tagHash = sha256(Buffer.from(tag));
58-
return [tag, Buffer.concat([tagHash, tagHash])];
59-
}),
60-
);
61-
}
6249
return sha256(Buffer.concat([TAGGED_HASH_PREFIXES[prefix], data]));
6350
}
6451
exports.taggedHash = taggedHash;

src/tagged-hash-prefixes.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
interface StringMap {
2+
[key: string]: string;
3+
}
4+
export declare const TAGGED_HASH_PREFIXES_HEX: StringMap;
5+
export {};

src/tagged-hash-prefixes.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
Object.defineProperty(exports, '__esModule', { value: true });
3+
exports.TAGGED_HASH_PREFIXES_HEX = void 0;
4+
exports.TAGGED_HASH_PREFIXES_HEX = {
5+
'BIP0340/challenge':
6+
'7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c',
7+
'BIP0340/aux':
8+
'f1ef4e5ec063cada6d94cafa9d987ea069265839ecc11f972d77a52ed8c1cc90f1ef4e5ec063cada6d94cafa9d987ea069265839ecc11f972d77a52ed8c1cc90',
9+
'BIP0340/nonce':
10+
'07497734a79bcb355b9b8c7d034f121cf434d73ef72dda19870061fb52bfeb2f07497734a79bcb355b9b8c7d034f121cf434d73ef72dda19870061fb52bfeb2f',
11+
TapLeaf:
12+
'aeea8fdc4208983105734b58081d1e2638d35f1cb54008d4d357ca03be78e9eeaeea8fdc4208983105734b58081d1e2638d35f1cb54008d4d357ca03be78e9ee',
13+
TapBranch:
14+
'1941a1f2e56eb95fa2a9f194be5c01f7216f33ed82b091463490d05bf516a0151941a1f2e56eb95fa2a9f194be5c01f7216f33ed82b091463490d05bf516a015',
15+
TapSighash:
16+
'f40a48df4b2a70c8b4924bf2654661ed3d95fd66a313eb87237597c628e4a031f40a48df4b2a70c8b4924bf2654661ed3d95fd66a313eb87237597c628e4a031',
17+
TapTweak:
18+
'e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9',
19+
'KeyAgg list':
20+
'481c971c3c0b46d7f0b275ae598d4e2c7ed7319c594a5c6ec79ea0d4990294f0481c971c3c0b46d7f0b275ae598d4e2c7ed7319c594a5c6ec79ea0d4990294f0',
21+
'KeyAgg coefficient':
22+
'bfc904034d1c88e8c80e22e53d24566d64824ed6427281c09100f94dcd52c981bfc904034d1c88e8c80e22e53d24566d64824ed6427281c09100f94dcd52c981',
23+
};

src/tags.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export declare const TAGS: readonly ["BIP0340/challenge", "BIP0340/aux", "BIP0340/nonce", "TapLeaf", "TapBranch", "TapSighash", "TapTweak", "KeyAgg list", "KeyAgg coefficient"];

src/tags.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
'use strict';
2+
Object.defineProperty(exports, '__esModule', { value: true });
3+
exports.TAGS = void 0;
4+
exports.TAGS = [
5+
'BIP0340/challenge',
6+
'BIP0340/aux',
7+
'BIP0340/nonce',
8+
'TapLeaf',
9+
'TapBranch',
10+
'TapSighash',
11+
'TapTweak',
12+
'KeyAgg list',
13+
'KeyAgg coefficient',
14+
];

test/crypto.spec.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import * as assert from 'assert';
22
import { describe, it } from 'mocha';
33
import { crypto as bcrypto, TaggedHashPrefix } from '..';
44
import * as fixtures from './fixtures/crypto.json';
5+
import { sha256 } from '../src/crypto';
6+
import { TAGS } from '../src/tags';
7+
import { TAGGED_HASH_PREFIXES_HEX } from '../src/tagged-hash-prefixes';
58

69
describe('crypto', () => {
710
['hash160', 'hash256', 'ripemd160', 'sha1', 'sha256'].forEach(algorithm => {
@@ -30,4 +33,21 @@ describe('crypto', () => {
3033
});
3134
});
3235
});
36+
37+
describe('TAGGED_HASH_PREFIXES', () => {
38+
const taggedHashPrefixes = Object.fromEntries(
39+
TAGS.map(tag => {
40+
const tagHash = sha256(Buffer.from(tag));
41+
return [tag, Buffer.concat([tagHash, tagHash])];
42+
}),
43+
);
44+
it('stored the result of operation', () => {
45+
Object.keys(taggedHashPrefixes).forEach(tag => {
46+
assert.strictEqual(
47+
TAGGED_HASH_PREFIXES_HEX[tag],
48+
taggedHashPrefixes[tag].toString('hex'),
49+
);
50+
});
51+
});
52+
});
3353
});

ts_src/crypto.ts

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as createHash from 'create-hash';
22
import * as RipeMd160 from 'ripemd160';
3-
3+
import { TAGGED_HASH_PREFIXES_HEX } from './tagged-hash-prefixes';
4+
import { TAGS } from './tags';
45
export function ripemd160(buffer: Buffer): Buffer {
56
try {
67
return createHash('rmd160').update(buffer).digest();
@@ -29,31 +30,17 @@ export function hash256(buffer: Buffer): Buffer {
2930
return sha256(sha256(buffer));
3031
}
3132

32-
const TAGS = [
33-
'BIP0340/challenge',
34-
'BIP0340/aux',
35-
'BIP0340/nonce',
36-
'TapLeaf',
37-
'TapBranch',
38-
'TapSighash',
39-
'TapTweak',
40-
'KeyAgg list',
41-
'KeyAgg coefficient',
42-
] as const;
4333
export type TaggedHashPrefix = typeof TAGS[number];
34+
4435
/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
45-
let TAGGED_HASH_PREFIXES = undefined as
46-
| { [k in TaggedHashPrefix]: Buffer }
47-
| undefined;
36+
37+
const TAGGED_HASH_PREFIXES = Object.fromEntries(
38+
Object.keys(TAGGED_HASH_PREFIXES_HEX).map((tag: string) => [
39+
tag,
40+
Buffer.from(TAGGED_HASH_PREFIXES_HEX[tag], 'hex'),
41+
]),
42+
) as { [k in TaggedHashPrefix]: Buffer };
4843

4944
export function taggedHash(prefix: TaggedHashPrefix, data: Buffer): Buffer {
50-
if (!TAGGED_HASH_PREFIXES) {
51-
TAGGED_HASH_PREFIXES = Object.fromEntries(
52-
TAGS.map(tag => {
53-
const tagHash = sha256(Buffer.from(tag));
54-
return [tag, Buffer.concat([tagHash, tagHash])];
55-
}),
56-
) as { [k in TaggedHashPrefix]: Buffer };
57-
}
5845
return sha256(Buffer.concat([TAGGED_HASH_PREFIXES[prefix], data]));
5946
}

ts_src/tagged-hash-prefixes.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
interface StringMap {
2+
[key: string]: string;
3+
}
4+
export const TAGGED_HASH_PREFIXES_HEX: StringMap = {
5+
'BIP0340/challenge':
6+
'7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c',
7+
'BIP0340/aux':
8+
'f1ef4e5ec063cada6d94cafa9d987ea069265839ecc11f972d77a52ed8c1cc90f1ef4e5ec063cada6d94cafa9d987ea069265839ecc11f972d77a52ed8c1cc90',
9+
'BIP0340/nonce':
10+
'07497734a79bcb355b9b8c7d034f121cf434d73ef72dda19870061fb52bfeb2f07497734a79bcb355b9b8c7d034f121cf434d73ef72dda19870061fb52bfeb2f',
11+
TapLeaf:
12+
'aeea8fdc4208983105734b58081d1e2638d35f1cb54008d4d357ca03be78e9eeaeea8fdc4208983105734b58081d1e2638d35f1cb54008d4d357ca03be78e9ee',
13+
TapBranch:
14+
'1941a1f2e56eb95fa2a9f194be5c01f7216f33ed82b091463490d05bf516a0151941a1f2e56eb95fa2a9f194be5c01f7216f33ed82b091463490d05bf516a015',
15+
TapSighash:
16+
'f40a48df4b2a70c8b4924bf2654661ed3d95fd66a313eb87237597c628e4a031f40a48df4b2a70c8b4924bf2654661ed3d95fd66a313eb87237597c628e4a031',
17+
TapTweak:
18+
'e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9',
19+
'KeyAgg list':
20+
'481c971c3c0b46d7f0b275ae598d4e2c7ed7319c594a5c6ec79ea0d4990294f0481c971c3c0b46d7f0b275ae598d4e2c7ed7319c594a5c6ec79ea0d4990294f0',
21+
'KeyAgg coefficient':
22+
'bfc904034d1c88e8c80e22e53d24566d64824ed6427281c09100f94dcd52c981bfc904034d1c88e8c80e22e53d24566d64824ed6427281c09100f94dcd52c981',
23+
};

ts_src/tags.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export const TAGS = [
2+
'BIP0340/challenge',
3+
'BIP0340/aux',
4+
'BIP0340/nonce',
5+
'TapLeaf',
6+
'TapBranch',
7+
'TapSighash',
8+
'TapTweak',
9+
'KeyAgg list',
10+
'KeyAgg coefficient',
11+
] as const;

0 commit comments

Comments
 (0)