@btc-vision/transaction 1.8.7 → 1.8.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/browser/btc-vision-bitcoin.js +495 -491
- package/browser/index.js +58 -50
- package/browser/noble-curves.js +4 -4
- package/browser/noble-hashes.js +88 -88
- package/browser/rolldown-runtime.js +26 -19
- package/browser/src/epoch/validator/EpochValidator.d.ts +28 -6
- package/browser/vendors.js +3065 -3027
- package/build/epoch/validator/EpochValidator.d.ts +28 -6
- package/build/epoch/validator/EpochValidator.js +44 -10
- package/package.json +1 -1
- package/src/epoch/validator/EpochValidator.ts +67 -6
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -6,9 +6,31 @@ export declare class EpochValidator {
|
|
|
6
6
|
*/
|
|
7
7
|
static sha1(data: Uint8Array): Uint8Array;
|
|
8
8
|
/**
|
|
9
|
-
* Calculate mining preimage
|
|
9
|
+
* Calculate mining preimage.
|
|
10
|
+
*
|
|
11
|
+
* When useConcatenatedPreimage is false the legacy XOR construction is used
|
|
12
|
+
* (checksumRoot ^ publicKey ^ salt). That construction is malleable: a
|
|
13
|
+
* miner can set salt == publicKey to force preimage == checksumRoot (max
|
|
14
|
+
* difficulty for free), or transform any solution to another key via
|
|
15
|
+
* salt' = publicKey' ^ publicKey ^ salt. When useConcatenatedPreimage is true
|
|
16
|
+
* the preimage is the 96-byte concatenation checksumRoot || publicKey || salt,
|
|
17
|
+
* which removes both (the SHA-1 proof-of-work over it is unchanged).
|
|
18
|
+
*
|
|
19
|
+
* The switch is a consensus rule: callers pass useConcatenatedPreimage =
|
|
20
|
+
* (epochBlockHeight >= activationHeight) using the activation height for the
|
|
21
|
+
* network they are on (opnet-node exposes it as
|
|
22
|
+
* consensusEpochPatches.PREIMAGE_CONCAT_PATCH_BLOCK_HEIGHT). The value MUST be
|
|
23
|
+
* identical across opnet-node, this library and the mining pool.
|
|
10
24
|
*/
|
|
11
|
-
static calculatePreimage(checksumRoot: Uint8Array, publicKey: Uint8Array, salt: Uint8Array): Uint8Array;
|
|
25
|
+
static calculatePreimage(checksumRoot: Uint8Array, publicKey: Uint8Array, salt: Uint8Array, useConcatenatedPreimage?: boolean): Uint8Array;
|
|
26
|
+
/**
|
|
27
|
+
* Non-malleable mining preimage: the 96-byte concatenation
|
|
28
|
+
* checksumRoot || publicKey || salt. The public key sits in its own segment,
|
|
29
|
+
* so a miner-chosen salt can neither cancel it nor be transformed to
|
|
30
|
+
* re-attribute another miner's solution. The SHA-1 proof-of-work over it is
|
|
31
|
+
* unchanged.
|
|
32
|
+
*/
|
|
33
|
+
static concatenatePreimage(checksumRoot: Uint8Array, publicKey: Uint8Array, salt: Uint8Array): Uint8Array;
|
|
12
34
|
/**
|
|
13
35
|
* Count matching bits between two hashes
|
|
14
36
|
*/
|
|
@@ -16,7 +38,7 @@ export declare class EpochValidator {
|
|
|
16
38
|
/**
|
|
17
39
|
* Verify an epoch solution using IPreimage
|
|
18
40
|
*/
|
|
19
|
-
static verifySolution(challenge: IChallengeSolution, log?: boolean): boolean;
|
|
41
|
+
static verifySolution(challenge: IChallengeSolution, log?: boolean, useHashedPreimage?: boolean): boolean;
|
|
20
42
|
/**
|
|
21
43
|
* Get the mining target block for an epoch
|
|
22
44
|
*/
|
|
@@ -24,11 +46,11 @@ export declare class EpochValidator {
|
|
|
24
46
|
/**
|
|
25
47
|
* Validate epoch winner from raw data
|
|
26
48
|
*/
|
|
27
|
-
static validateEpochWinner(epochData: RawChallenge): boolean;
|
|
49
|
+
static validateEpochWinner(epochData: RawChallenge, useHashedPreimage?: boolean): boolean;
|
|
28
50
|
/**
|
|
29
51
|
* Validate epoch winner from Preimage instance
|
|
30
52
|
*/
|
|
31
|
-
static validateChallengeSolution(challenge: IChallengeSolution): boolean;
|
|
53
|
+
static validateChallengeSolution(challenge: IChallengeSolution, useHashedPreimage?: boolean): boolean;
|
|
32
54
|
/**
|
|
33
55
|
* Calculate solution hash from preimage components
|
|
34
56
|
* @param targetChecksum The target checksum (32 bytes)
|
|
@@ -36,7 +58,7 @@ export declare class EpochValidator {
|
|
|
36
58
|
* @param salt The salt buffer (32 bytes)
|
|
37
59
|
* @returns The SHA-1 hash of the preimage
|
|
38
60
|
*/
|
|
39
|
-
static calculateSolution(targetChecksum: Uint8Array, publicKey: Uint8Array, salt: Uint8Array): Uint8Array;
|
|
61
|
+
static calculateSolution(targetChecksum: Uint8Array, publicKey: Uint8Array, salt: Uint8Array, useHashedPreimage?: boolean): Uint8Array;
|
|
40
62
|
/**
|
|
41
63
|
* Check if a solution meets the minimum difficulty requirement
|
|
42
64
|
*/
|
|
@@ -10,13 +10,30 @@ export class EpochValidator {
|
|
|
10
10
|
return crypto.sha1(data);
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* Calculate mining preimage
|
|
13
|
+
* Calculate mining preimage.
|
|
14
|
+
*
|
|
15
|
+
* When useConcatenatedPreimage is false the legacy XOR construction is used
|
|
16
|
+
* (checksumRoot ^ publicKey ^ salt). That construction is malleable: a
|
|
17
|
+
* miner can set salt == publicKey to force preimage == checksumRoot (max
|
|
18
|
+
* difficulty for free), or transform any solution to another key via
|
|
19
|
+
* salt' = publicKey' ^ publicKey ^ salt. When useConcatenatedPreimage is true
|
|
20
|
+
* the preimage is the 96-byte concatenation checksumRoot || publicKey || salt,
|
|
21
|
+
* which removes both (the SHA-1 proof-of-work over it is unchanged).
|
|
22
|
+
*
|
|
23
|
+
* The switch is a consensus rule: callers pass useConcatenatedPreimage =
|
|
24
|
+
* (epochBlockHeight >= activationHeight) using the activation height for the
|
|
25
|
+
* network they are on (opnet-node exposes it as
|
|
26
|
+
* consensusEpochPatches.PREIMAGE_CONCAT_PATCH_BLOCK_HEIGHT). The value MUST be
|
|
27
|
+
* identical across opnet-node, this library and the mining pool.
|
|
14
28
|
*/
|
|
15
|
-
static calculatePreimage(checksumRoot, publicKey, salt) {
|
|
29
|
+
static calculatePreimage(checksumRoot, publicKey, salt, useConcatenatedPreimage = false) {
|
|
16
30
|
// Ensure all are 32 bytes
|
|
17
31
|
if (checksumRoot.length !== 32 || publicKey.length !== 32 || salt.length !== 32) {
|
|
18
32
|
throw new Error('All inputs must be 32 bytes');
|
|
19
33
|
}
|
|
34
|
+
if (useConcatenatedPreimage) {
|
|
35
|
+
return this.concatenatePreimage(checksumRoot, publicKey, salt);
|
|
36
|
+
}
|
|
20
37
|
const preimage = new Uint8Array(32);
|
|
21
38
|
for (let i = 0; i < 32; i++) {
|
|
22
39
|
preimage[i] =
|
|
@@ -24,6 +41,23 @@ export class EpochValidator {
|
|
|
24
41
|
}
|
|
25
42
|
return preimage;
|
|
26
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Non-malleable mining preimage: the 96-byte concatenation
|
|
46
|
+
* checksumRoot || publicKey || salt. The public key sits in its own segment,
|
|
47
|
+
* so a miner-chosen salt can neither cancel it nor be transformed to
|
|
48
|
+
* re-attribute another miner's solution. The SHA-1 proof-of-work over it is
|
|
49
|
+
* unchanged.
|
|
50
|
+
*/
|
|
51
|
+
static concatenatePreimage(checksumRoot, publicKey, salt) {
|
|
52
|
+
if (checksumRoot.length !== 32 || publicKey.length !== 32 || salt.length !== 32) {
|
|
53
|
+
throw new Error('All inputs must be 32 bytes');
|
|
54
|
+
}
|
|
55
|
+
const message = new Uint8Array(96);
|
|
56
|
+
message.set(checksumRoot, 0);
|
|
57
|
+
message.set(publicKey, 32);
|
|
58
|
+
message.set(salt, 64);
|
|
59
|
+
return message;
|
|
60
|
+
}
|
|
27
61
|
/**
|
|
28
62
|
* Count matching bits between two hashes
|
|
29
63
|
*/
|
|
@@ -56,10 +90,10 @@ export class EpochValidator {
|
|
|
56
90
|
/**
|
|
57
91
|
* Verify an epoch solution using IPreimage
|
|
58
92
|
*/
|
|
59
|
-
static verifySolution(challenge, log = false) {
|
|
93
|
+
static verifySolution(challenge, log = false, useHashedPreimage = false) {
|
|
60
94
|
try {
|
|
61
95
|
const verification = challenge.verification;
|
|
62
|
-
const calculatedPreimage = this.calculatePreimage(verification.targetChecksum, challenge.publicKey.toBuffer(), challenge.salt);
|
|
96
|
+
const calculatedPreimage = this.calculatePreimage(verification.targetChecksum, challenge.publicKey.toBuffer(), challenge.salt, useHashedPreimage);
|
|
63
97
|
const computedSolution = this.sha1(calculatedPreimage);
|
|
64
98
|
if (!equals(computedSolution, challenge.solution)) {
|
|
65
99
|
return false;
|
|
@@ -92,7 +126,7 @@ export class EpochValidator {
|
|
|
92
126
|
/**
|
|
93
127
|
* Validate epoch winner from raw data
|
|
94
128
|
*/
|
|
95
|
-
static validateEpochWinner(epochData) {
|
|
129
|
+
static validateEpochWinner(epochData, useHashedPreimage = false) {
|
|
96
130
|
try {
|
|
97
131
|
const epochNumber = BigInt(epochData.epochNumber);
|
|
98
132
|
const publicKey = Address.fromString(epochData.mldsaPublicKey, epochData.legacyPublicKey);
|
|
@@ -108,7 +142,7 @@ export class EpochValidator {
|
|
|
108
142
|
endBlock: BigInt(epochData.verification.endBlock),
|
|
109
143
|
proofs: Object.freeze(epochData.verification.proofs.map((p) => stringToBuffer(p))),
|
|
110
144
|
};
|
|
111
|
-
const calculatedPreimage = this.calculatePreimage(verification.targetChecksum, publicKey.toBuffer(), salt);
|
|
145
|
+
const calculatedPreimage = this.calculatePreimage(verification.targetChecksum, publicKey.toBuffer(), salt, useHashedPreimage);
|
|
112
146
|
const computedSolution = this.sha1(calculatedPreimage);
|
|
113
147
|
if (!equals(computedSolution, solution)) {
|
|
114
148
|
return false;
|
|
@@ -129,8 +163,8 @@ export class EpochValidator {
|
|
|
129
163
|
/**
|
|
130
164
|
* Validate epoch winner from Preimage instance
|
|
131
165
|
*/
|
|
132
|
-
static validateChallengeSolution(challenge) {
|
|
133
|
-
return this.verifySolution(challenge);
|
|
166
|
+
static validateChallengeSolution(challenge, useHashedPreimage = false) {
|
|
167
|
+
return this.verifySolution(challenge, false, useHashedPreimage);
|
|
134
168
|
}
|
|
135
169
|
/**
|
|
136
170
|
* Calculate solution hash from preimage components
|
|
@@ -139,8 +173,8 @@ export class EpochValidator {
|
|
|
139
173
|
* @param salt The salt buffer (32 bytes)
|
|
140
174
|
* @returns The SHA-1 hash of the preimage
|
|
141
175
|
*/
|
|
142
|
-
static calculateSolution(targetChecksum, publicKey, salt) {
|
|
143
|
-
const preimage = this.calculatePreimage(targetChecksum, publicKey, salt);
|
|
176
|
+
static calculateSolution(targetChecksum, publicKey, salt, useHashedPreimage = false) {
|
|
177
|
+
const preimage = this.calculatePreimage(targetChecksum, publicKey, salt, useHashedPreimage);
|
|
144
178
|
return this.sha1(preimage);
|
|
145
179
|
}
|
|
146
180
|
/**
|
package/package.json
CHANGED
|
@@ -14,18 +14,37 @@ export class EpochValidator {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Calculate mining preimage
|
|
17
|
+
* Calculate mining preimage.
|
|
18
|
+
*
|
|
19
|
+
* When useConcatenatedPreimage is false the legacy XOR construction is used
|
|
20
|
+
* (checksumRoot ^ publicKey ^ salt). That construction is malleable: a
|
|
21
|
+
* miner can set salt == publicKey to force preimage == checksumRoot (max
|
|
22
|
+
* difficulty for free), or transform any solution to another key via
|
|
23
|
+
* salt' = publicKey' ^ publicKey ^ salt. When useConcatenatedPreimage is true
|
|
24
|
+
* the preimage is the 96-byte concatenation checksumRoot || publicKey || salt,
|
|
25
|
+
* which removes both (the SHA-1 proof-of-work over it is unchanged).
|
|
26
|
+
*
|
|
27
|
+
* The switch is a consensus rule: callers pass useConcatenatedPreimage =
|
|
28
|
+
* (epochBlockHeight >= activationHeight) using the activation height for the
|
|
29
|
+
* network they are on (opnet-node exposes it as
|
|
30
|
+
* consensusEpochPatches.PREIMAGE_CONCAT_PATCH_BLOCK_HEIGHT). The value MUST be
|
|
31
|
+
* identical across opnet-node, this library and the mining pool.
|
|
18
32
|
*/
|
|
19
33
|
public static calculatePreimage(
|
|
20
34
|
checksumRoot: Uint8Array,
|
|
21
35
|
publicKey: Uint8Array,
|
|
22
36
|
salt: Uint8Array,
|
|
37
|
+
useConcatenatedPreimage: boolean = false,
|
|
23
38
|
): Uint8Array {
|
|
24
39
|
// Ensure all are 32 bytes
|
|
25
40
|
if (checksumRoot.length !== 32 || publicKey.length !== 32 || salt.length !== 32) {
|
|
26
41
|
throw new Error('All inputs must be 32 bytes');
|
|
27
42
|
}
|
|
28
43
|
|
|
44
|
+
if (useConcatenatedPreimage) {
|
|
45
|
+
return this.concatenatePreimage(checksumRoot, publicKey, salt);
|
|
46
|
+
}
|
|
47
|
+
|
|
29
48
|
const preimage = new Uint8Array(32);
|
|
30
49
|
for (let i = 0; i < 32; i++) {
|
|
31
50
|
preimage[i] =
|
|
@@ -35,6 +54,30 @@ export class EpochValidator {
|
|
|
35
54
|
return preimage;
|
|
36
55
|
}
|
|
37
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Non-malleable mining preimage: the 96-byte concatenation
|
|
59
|
+
* checksumRoot || publicKey || salt. The public key sits in its own segment,
|
|
60
|
+
* so a miner-chosen salt can neither cancel it nor be transformed to
|
|
61
|
+
* re-attribute another miner's solution. The SHA-1 proof-of-work over it is
|
|
62
|
+
* unchanged.
|
|
63
|
+
*/
|
|
64
|
+
public static concatenatePreimage(
|
|
65
|
+
checksumRoot: Uint8Array,
|
|
66
|
+
publicKey: Uint8Array,
|
|
67
|
+
salt: Uint8Array,
|
|
68
|
+
): Uint8Array {
|
|
69
|
+
if (checksumRoot.length !== 32 || publicKey.length !== 32 || salt.length !== 32) {
|
|
70
|
+
throw new Error('All inputs must be 32 bytes');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const message = new Uint8Array(96);
|
|
74
|
+
message.set(checksumRoot, 0);
|
|
75
|
+
message.set(publicKey, 32);
|
|
76
|
+
message.set(salt, 64);
|
|
77
|
+
|
|
78
|
+
return message;
|
|
79
|
+
}
|
|
80
|
+
|
|
38
81
|
/**
|
|
39
82
|
* Count matching bits between two hashes
|
|
40
83
|
*/
|
|
@@ -69,13 +112,18 @@ export class EpochValidator {
|
|
|
69
112
|
/**
|
|
70
113
|
* Verify an epoch solution using IPreimage
|
|
71
114
|
*/
|
|
72
|
-
public static verifySolution(
|
|
115
|
+
public static verifySolution(
|
|
116
|
+
challenge: IChallengeSolution,
|
|
117
|
+
log: boolean = false,
|
|
118
|
+
useHashedPreimage: boolean = false,
|
|
119
|
+
): boolean {
|
|
73
120
|
try {
|
|
74
121
|
const verification = challenge.verification;
|
|
75
122
|
const calculatedPreimage = this.calculatePreimage(
|
|
76
123
|
verification.targetChecksum,
|
|
77
124
|
challenge.publicKey.toBuffer(),
|
|
78
125
|
challenge.salt,
|
|
126
|
+
useHashedPreimage,
|
|
79
127
|
);
|
|
80
128
|
|
|
81
129
|
const computedSolution = this.sha1(calculatedPreimage);
|
|
@@ -118,7 +166,10 @@ export class EpochValidator {
|
|
|
118
166
|
/**
|
|
119
167
|
* Validate epoch winner from raw data
|
|
120
168
|
*/
|
|
121
|
-
public static validateEpochWinner(
|
|
169
|
+
public static validateEpochWinner(
|
|
170
|
+
epochData: RawChallenge,
|
|
171
|
+
useHashedPreimage: boolean = false,
|
|
172
|
+
): boolean {
|
|
122
173
|
try {
|
|
123
174
|
const epochNumber = BigInt(epochData.epochNumber);
|
|
124
175
|
const publicKey = Address.fromString(
|
|
@@ -143,6 +194,7 @@ export class EpochValidator {
|
|
|
143
194
|
verification.targetChecksum,
|
|
144
195
|
publicKey.toBuffer(),
|
|
145
196
|
salt,
|
|
197
|
+
useHashedPreimage,
|
|
146
198
|
);
|
|
147
199
|
|
|
148
200
|
const computedSolution = this.sha1(calculatedPreimage);
|
|
@@ -172,8 +224,11 @@ export class EpochValidator {
|
|
|
172
224
|
/**
|
|
173
225
|
* Validate epoch winner from Preimage instance
|
|
174
226
|
*/
|
|
175
|
-
public static validateChallengeSolution(
|
|
176
|
-
|
|
227
|
+
public static validateChallengeSolution(
|
|
228
|
+
challenge: IChallengeSolution,
|
|
229
|
+
useHashedPreimage: boolean = false,
|
|
230
|
+
): boolean {
|
|
231
|
+
return this.verifySolution(challenge, false, useHashedPreimage);
|
|
177
232
|
}
|
|
178
233
|
|
|
179
234
|
/**
|
|
@@ -187,8 +242,14 @@ export class EpochValidator {
|
|
|
187
242
|
targetChecksum: Uint8Array,
|
|
188
243
|
publicKey: Uint8Array,
|
|
189
244
|
salt: Uint8Array,
|
|
245
|
+
useHashedPreimage: boolean = false,
|
|
190
246
|
): Uint8Array {
|
|
191
|
-
const preimage = this.calculatePreimage(
|
|
247
|
+
const preimage = this.calculatePreimage(
|
|
248
|
+
targetChecksum,
|
|
249
|
+
publicKey,
|
|
250
|
+
salt,
|
|
251
|
+
useHashedPreimage,
|
|
252
|
+
);
|
|
192
253
|
return this.sha1(preimage);
|
|
193
254
|
}
|
|
194
255
|
|