/
utils.ts
118 lines (106 loc) 路 3.18 KB
/
utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
* Copyright 漏 2021 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*/
import { bls } from '@liskhq/lisk-cryptography';
import { BlockHeader } from '@liskhq/lisk-chain';
import { codec } from '@liskhq/lisk-codec';
import { Certificate, UnsignedCertificate } from './types';
import { unsignedCertificateSchema } from './schema';
import { MESSAGE_TAG_CERTIFICATE } from './constants';
/**
* @see https://github.com/LiskHQ/lips/blob/main/proposals/lip-0061.md#creation
*/
export const computeUnsignedCertificateFromBlockHeader = (
blockHeader: BlockHeader,
): UnsignedCertificate => {
if (!blockHeader.stateRoot) {
throw new Error('stateRoot is not defined.');
}
if (!blockHeader.validatorsHash) {
throw new Error('validatorsHash is not defined.');
}
return {
blockID: blockHeader.id,
height: blockHeader.height,
stateRoot: blockHeader.stateRoot,
timestamp: blockHeader.timestamp,
validatorsHash: blockHeader.validatorsHash,
};
};
/**
* @see https://github.com/LiskHQ/lips/blob/main/proposals/lip-0061.md#signcertificate
*/
export const signCertificate = (
sk: Buffer,
chainID: Buffer,
unsignedCertificate: UnsignedCertificate,
): Buffer =>
bls.signData(
MESSAGE_TAG_CERTIFICATE,
chainID,
codec.encode(unsignedCertificateSchema, unsignedCertificate),
sk,
);
/**
* @see https://github.com/LiskHQ/lips/blob/main/proposals/lip-0061.md#verifysinglecertificatesignature
*/
export const verifySingleCertificateSignature = (
pk: Buffer,
signature: Buffer,
chainID: Buffer,
unsignedCertificate: UnsignedCertificate,
): boolean =>
bls.verifyData(
MESSAGE_TAG_CERTIFICATE,
chainID,
codec.encode(unsignedCertificateSchema, unsignedCertificate),
signature,
pk,
);
/**
* @see https://github.com/LiskHQ/lips/blob/main/proposals/lip-0061.md#verifyaggregatecertificatesignature
*/
export const verifyAggregateCertificateSignature = (
validators: { blsKey: Buffer; bftWeight: bigint }[],
threshold: bigint,
chainID: Buffer,
certificate: Certificate,
): boolean => {
if (!certificate.aggregationBits || !certificate.signature) {
return false;
}
const { weights, validatorKeys } = getSortedWeightsAndValidatorKeys(validators);
const { aggregationBits, signature, ...unsignedCertificate } = certificate;
return bls.verifyWeightedAggSig(
validatorKeys,
aggregationBits,
signature,
MESSAGE_TAG_CERTIFICATE,
chainID,
codec.encode(unsignedCertificateSchema, unsignedCertificate),
weights,
threshold,
);
};
export const getSortedWeightsAndValidatorKeys = (
validators: { blsKey: Buffer; bftWeight: bigint }[],
) => {
validators.sort((a, b) => a.blsKey.compare(b.blsKey));
const weights = [];
const validatorKeys = [];
for (const validator of validators) {
weights.push(validator.bftWeight);
validatorKeys.push(validator.blsKey);
}
return { weights, validatorKeys };
};