@alephium/web3 0.5.0-rc.0 → 0.5.0-rc.10
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/dist/alephium-web3.min.js +1 -1
- package/dist/alephium-web3.min.js.LICENSE.txt +2 -0
- package/dist/alephium-web3.min.js.map +1 -1
- package/dist/src/api/api-alephium.d.ts +57 -20
- package/dist/src/api/api-alephium.js +57 -15
- package/dist/src/api/index.d.ts +1 -0
- package/dist/src/api/index.js +1 -0
- package/dist/src/api/types.d.ts +1 -1
- package/dist/src/api/types.js +6 -2
- package/dist/src/constants.d.ts +1 -0
- package/dist/src/constants.js +2 -1
- package/dist/src/contract/contract.d.ts +37 -17
- package/dist/src/contract/contract.js +167 -19
- package/dist/src/signer/signer.d.ts +29 -30
- package/dist/src/signer/signer.js +34 -25
- package/dist/src/signer/tx-builder.d.ts +2 -7
- package/dist/src/signer/tx-builder.js +10 -7
- package/dist/src/signer/types.d.ts +8 -0
- package/dist/src/transaction/sign-verify.d.ts +3 -2
- package/dist/src/transaction/sign-verify.js +4 -14
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/index.js +1 -0
- package/dist/src/utils/sign.d.ts +3 -0
- package/dist/src/utils/sign.js +89 -0
- package/dist/src/utils/utils.d.ts +5 -3
- package/dist/src/utils/utils.js +25 -10
- package/package.json +3 -2
- package/src/api/api-alephium.ts +88 -32
- package/src/api/index.ts +2 -0
- package/src/api/types.ts +12 -2
- package/src/constants.ts +1 -0
- package/src/contract/contract.ts +288 -38
- package/src/signer/signer.ts +69 -55
- package/src/signer/tx-builder.ts +13 -7
- package/src/signer/types.ts +10 -2
- package/src/transaction/sign-verify.ts +10 -15
- package/src/utils/index.ts +1 -0
- package/src/utils/sign.ts +66 -0
- package/src/utils/utils.ts +27 -10
package/src/signer/signer.ts
CHANGED
|
@@ -16,7 +16,6 @@ You should have received a copy of the GNU Lesser General Public License
|
|
|
16
16
|
along with the library. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import { ec as EC } from 'elliptic'
|
|
20
19
|
import { ExplorerProvider, fromApiNumber256, fromApiTokens, NodeProvider, toApiNumber256, toApiTokens } from '../api'
|
|
21
20
|
import { node } from '../api'
|
|
22
21
|
import * as utils from '../utils'
|
|
@@ -43,53 +42,70 @@ import {
|
|
|
43
42
|
ExtSignDeployContractTxParams,
|
|
44
43
|
ExtSignExecuteScriptTxParams,
|
|
45
44
|
ExtSignUnsignedTxParams,
|
|
46
|
-
ExtSignMessageParams
|
|
45
|
+
ExtSignMessageParams,
|
|
46
|
+
KeyType
|
|
47
47
|
} from './types'
|
|
48
48
|
import { TransactionBuilder } from './tx-builder'
|
|
49
|
+
import { addressFromPublicKey, groupOfAddress } from '../utils'
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
export abstract class SignerProvider {
|
|
52
|
+
abstract get nodeProvider(): NodeProvider | undefined
|
|
53
|
+
abstract get explorerProvider(): ExplorerProvider | undefined
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
protected abstract unsafeGetSelectedAccount(): Promise<Account>
|
|
56
|
+
async getSelectedAccount(): Promise<Account> {
|
|
57
|
+
const account = await this.unsafeGetSelectedAccount()
|
|
58
|
+
SignerProvider.validateAccount(account)
|
|
59
|
+
return account
|
|
60
|
+
}
|
|
55
61
|
|
|
56
|
-
|
|
62
|
+
static validateAccount(account: Account): void {
|
|
63
|
+
const derivedAddress = addressFromPublicKey(account.publicKey, account.keyType)
|
|
64
|
+
const derivedGroup = groupOfAddress(derivedAddress)
|
|
65
|
+
if (derivedAddress !== account.address || derivedGroup !== account.group) {
|
|
66
|
+
throw Error(`Invalid accounot data: ${JSON.stringify(account)}`)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
57
69
|
|
|
58
|
-
signAndSubmitTransferTx(params: SignTransferTxParams): Promise<SignTransferTxResult>
|
|
59
|
-
signAndSubmitDeployContractTx(params: SignDeployContractTxParams): Promise<SignDeployContractTxResult>
|
|
60
|
-
signAndSubmitExecuteScriptTx(params: SignExecuteScriptTxParams): Promise<SignExecuteScriptTxResult>
|
|
61
|
-
signAndSubmitUnsignedTx(params: SignUnsignedTxParams): Promise<SignUnsignedTxResult>
|
|
70
|
+
abstract signAndSubmitTransferTx(params: SignTransferTxParams): Promise<SignTransferTxResult>
|
|
71
|
+
abstract signAndSubmitDeployContractTx(params: SignDeployContractTxParams): Promise<SignDeployContractTxResult>
|
|
72
|
+
abstract signAndSubmitExecuteScriptTx(params: SignExecuteScriptTxParams): Promise<SignExecuteScriptTxResult>
|
|
73
|
+
abstract signAndSubmitUnsignedTx(params: SignUnsignedTxParams): Promise<SignUnsignedTxResult>
|
|
62
74
|
|
|
63
|
-
signUnsignedTx(params: SignUnsignedTxParams): Promise<SignUnsignedTxResult>
|
|
75
|
+
abstract signUnsignedTx(params: SignUnsignedTxParams): Promise<SignUnsignedTxResult>
|
|
64
76
|
// The message will be prefixed with 'Alephium Signed Message: ' before signing
|
|
65
77
|
// so that the resulted signature cannot be reused for building transactions.
|
|
66
|
-
signMessage(params: SignMessageParams): Promise<SignMessageResult>
|
|
78
|
+
abstract signMessage(params: SignMessageParams): Promise<SignMessageResult>
|
|
67
79
|
}
|
|
68
80
|
|
|
69
81
|
// Abstraction for interactive signer (e.g. WalletConnect instance, Extension wallet object)
|
|
70
|
-
export
|
|
71
|
-
extends
|
|
72
|
-
|
|
73
|
-
|
|
82
|
+
export abstract class InteractiveSignerProvider<
|
|
83
|
+
EnableOptions extends EnableOptionsBase = EnableOptionsBase
|
|
84
|
+
> extends SignerProvider {
|
|
85
|
+
protected abstract unsafeEnable(opt?: EnableOptions): Promise<Account>
|
|
86
|
+
async enable(opt?: EnableOptions): Promise<Account> {
|
|
87
|
+
const account = await this.unsafeEnable(opt)
|
|
88
|
+
SignerProvider.validateAccount(account)
|
|
89
|
+
return account
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
abstract disconnect(): Promise<void>
|
|
74
93
|
|
|
75
94
|
// Methods inherited from SignerProvider, but require networkId in the params
|
|
76
|
-
signAndSubmitTransferTx(params: ExtSignTransferTxParams): Promise<SignTransferTxResult>
|
|
77
|
-
signAndSubmitDeployContractTx(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
95
|
+
abstract override signAndSubmitTransferTx(params: ExtSignTransferTxParams): Promise<SignTransferTxResult>
|
|
96
|
+
abstract override signAndSubmitDeployContractTx(
|
|
97
|
+
params: ExtSignDeployContractTxParams
|
|
98
|
+
): Promise<SignDeployContractTxResult>
|
|
99
|
+
abstract override signAndSubmitExecuteScriptTx(
|
|
100
|
+
params: ExtSignExecuteScriptTxParams
|
|
101
|
+
): Promise<SignExecuteScriptTxResult>
|
|
102
|
+
abstract override signAndSubmitUnsignedTx(params: ExtSignUnsignedTxParams): Promise<SignUnsignedTxResult>
|
|
103
|
+
abstract override signUnsignedTx(params: ExtSignUnsignedTxParams): Promise<SignUnsignedTxResult>
|
|
104
|
+
abstract override signMessage(params: ExtSignMessageParams): Promise<SignMessageResult>
|
|
82
105
|
}
|
|
83
106
|
|
|
84
|
-
export abstract class SignerProviderSimple extends
|
|
85
|
-
abstract get
|
|
86
|
-
|
|
87
|
-
abstract getSelectedAccount(): Promise<Account>
|
|
88
|
-
|
|
89
|
-
async getSelectedAddress(): Promise<Address> {
|
|
90
|
-
const account = await this.getSelectedAccount()
|
|
91
|
-
return account.address
|
|
92
|
-
}
|
|
107
|
+
export abstract class SignerProviderSimple extends SignerProvider {
|
|
108
|
+
abstract override get nodeProvider(): NodeProvider
|
|
93
109
|
|
|
94
110
|
async submitTransaction(params: SubmitTransactionParams): Promise<SubmissionResult> {
|
|
95
111
|
const data: node.SubmitTransaction = { unsignedTx: params.unsignedTx, signature: params.signature }
|
|
@@ -133,8 +149,11 @@ export abstract class SignerProviderSimple extends TransactionBuilder implements
|
|
|
133
149
|
return { signature, ...response }
|
|
134
150
|
}
|
|
135
151
|
|
|
136
|
-
|
|
137
|
-
return
|
|
152
|
+
async buildTransferTx(params: SignTransferTxParams): Promise<Omit<SignTransferTxResult, 'signature'>> {
|
|
153
|
+
return TransactionBuilder.from(this.nodeProvider).buildTransferTx(
|
|
154
|
+
params,
|
|
155
|
+
await this.getPublicKey(params.signerAddress)
|
|
156
|
+
)
|
|
138
157
|
}
|
|
139
158
|
|
|
140
159
|
async signDeployContractTx(params: SignDeployContractTxParams): Promise<SignDeployContractTxResult> {
|
|
@@ -143,10 +162,13 @@ export abstract class SignerProviderSimple extends TransactionBuilder implements
|
|
|
143
162
|
return { signature, ...response }
|
|
144
163
|
}
|
|
145
164
|
|
|
146
|
-
|
|
165
|
+
async buildDeployContractTx(
|
|
147
166
|
params: SignDeployContractTxParams
|
|
148
167
|
): Promise<Omit<SignDeployContractTxResult, 'signature'>> {
|
|
149
|
-
return
|
|
168
|
+
return TransactionBuilder.from(this.nodeProvider).buildDeployContractTx(
|
|
169
|
+
params,
|
|
170
|
+
await this.getPublicKey(params.signerAddress)
|
|
171
|
+
)
|
|
150
172
|
}
|
|
151
173
|
|
|
152
174
|
async signExecuteScriptTx(params: SignExecuteScriptTxParams): Promise<SignExecuteScriptTxResult> {
|
|
@@ -155,16 +177,17 @@ export abstract class SignerProviderSimple extends TransactionBuilder implements
|
|
|
155
177
|
return { signature, ...response }
|
|
156
178
|
}
|
|
157
179
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
180
|
+
async buildExecuteScriptTx(params: SignExecuteScriptTxParams): Promise<Omit<SignExecuteScriptTxResult, 'signature'>> {
|
|
181
|
+
return TransactionBuilder.from(this.nodeProvider).buildExecuteScriptTx(
|
|
182
|
+
params,
|
|
183
|
+
await this.getPublicKey(params.signerAddress)
|
|
184
|
+
)
|
|
162
185
|
}
|
|
163
186
|
|
|
164
187
|
// in general, wallet should show the decoded information to user for confirmation
|
|
165
188
|
// please overwrite this function for real wallet
|
|
166
189
|
async signUnsignedTx(params: SignUnsignedTxParams): Promise<SignUnsignedTxResult> {
|
|
167
|
-
const response = await this.buildUnsignedTx(params)
|
|
190
|
+
const response = await TransactionBuilder.from(this.nodeProvider).buildUnsignedTx(params)
|
|
168
191
|
const signature = await this.signRaw(params.signerAddress, response.txId)
|
|
169
192
|
return { signature, ...response }
|
|
170
193
|
}
|
|
@@ -180,7 +203,7 @@ export abstract class SignerProviderSimple extends TransactionBuilder implements
|
|
|
180
203
|
}
|
|
181
204
|
|
|
182
205
|
export abstract class SignerProviderWithMultipleAccounts extends SignerProviderSimple {
|
|
183
|
-
abstract
|
|
206
|
+
abstract setSelectedAccount(address: string): Promise<void>
|
|
184
207
|
|
|
185
208
|
abstract getAccounts(): Promise<Account[]>
|
|
186
209
|
|
|
@@ -204,7 +227,7 @@ export abstract class SignerProviderWithCachedAccounts<T extends Account> extend
|
|
|
204
227
|
private _selectedAccount: T | undefined = undefined
|
|
205
228
|
protected readonly _accounts = new Map<Address, T>()
|
|
206
229
|
|
|
207
|
-
|
|
230
|
+
protected unsafeGetSelectedAccount(): Promise<T> {
|
|
208
231
|
if (this._selectedAccount === undefined) {
|
|
209
232
|
throw Error('No account is selected yet')
|
|
210
233
|
} else {
|
|
@@ -212,7 +235,7 @@ export abstract class SignerProviderWithCachedAccounts<T extends Account> extend
|
|
|
212
235
|
}
|
|
213
236
|
}
|
|
214
237
|
|
|
215
|
-
|
|
238
|
+
setSelectedAccount(address: string): Promise<void> {
|
|
216
239
|
const accountOpt = this._accounts.get(address)
|
|
217
240
|
if (accountOpt === undefined) {
|
|
218
241
|
throw Error('The address is not in the accounts')
|
|
@@ -236,23 +259,14 @@ export abstract class SignerProviderWithCachedAccounts<T extends Account> extend
|
|
|
236
259
|
}
|
|
237
260
|
}
|
|
238
261
|
|
|
239
|
-
export function verifyHexString(hexString: string, publicKey: string, signature: string): boolean {
|
|
240
|
-
try {
|
|
241
|
-
const key = ec.keyFromPublic(publicKey, 'hex')
|
|
242
|
-
return key.verify(hexString, utils.signatureDecode(ec, signature))
|
|
243
|
-
} catch (error) {
|
|
244
|
-
return false
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
262
|
function extendMessage(message: string): string {
|
|
249
263
|
return 'Alephium Signed Message: ' + message
|
|
250
264
|
}
|
|
251
265
|
|
|
252
|
-
export function verifySignedMessage(message: string, publicKey: string, signature: string): boolean {
|
|
266
|
+
export function verifySignedMessage(message: string, publicKey: string, signature: string, keyType: KeyType): boolean {
|
|
253
267
|
const extendedMessage = extendMessage(message)
|
|
254
268
|
const messageHash = blake.blake2b(extendedMessage, undefined, 32)
|
|
255
|
-
return
|
|
269
|
+
return utils.verifySignature(utils.binToHex(messageHash), publicKey, signature, keyType)
|
|
256
270
|
}
|
|
257
271
|
|
|
258
272
|
export function toApiDestination(data: Destination): node.Destination {
|
package/src/signer/tx-builder.ts
CHANGED
|
@@ -21,6 +21,7 @@ import { fromApiNumber256, node, NodeProvider, toApiNumber256Optional, toApiToke
|
|
|
21
21
|
import { addressFromPublicKey } from '../utils'
|
|
22
22
|
import { toApiDestinations } from './signer'
|
|
23
23
|
import {
|
|
24
|
+
KeyType,
|
|
24
25
|
SignDeployContractTxParams,
|
|
25
26
|
SignDeployContractTxResult,
|
|
26
27
|
SignerAddress,
|
|
@@ -35,8 +36,10 @@ import {
|
|
|
35
36
|
export abstract class TransactionBuilder {
|
|
36
37
|
abstract get nodeProvider(): NodeProvider
|
|
37
38
|
|
|
38
|
-
static
|
|
39
|
-
|
|
39
|
+
static from(nodeProvider: NodeProvider): TransactionBuilder
|
|
40
|
+
static from(baseUrl: string, apiKey?: string): TransactionBuilder
|
|
41
|
+
static from(param0: string | NodeProvider, param1?: string): TransactionBuilder {
|
|
42
|
+
const nodeProvider = typeof param0 === 'string' ? new NodeProvider(param0, param1) : (param0 as NodeProvider)
|
|
40
43
|
return new (class extends TransactionBuilder {
|
|
41
44
|
get nodeProvider(): NodeProvider {
|
|
42
45
|
return nodeProvider
|
|
@@ -44,8 +47,8 @@ export abstract class TransactionBuilder {
|
|
|
44
47
|
})()
|
|
45
48
|
}
|
|
46
49
|
|
|
47
|
-
private static validatePublicKey(params: SignerAddress, publicKey: string) {
|
|
48
|
-
const address = addressFromPublicKey(publicKey)
|
|
50
|
+
private static validatePublicKey(params: SignerAddress, publicKey: string, keyType: KeyType) {
|
|
51
|
+
const address = addressFromPublicKey(publicKey, keyType)
|
|
49
52
|
if (address !== params.signerAddress) {
|
|
50
53
|
throw new Error('Unmatched public key')
|
|
51
54
|
}
|
|
@@ -55,11 +58,12 @@ export abstract class TransactionBuilder {
|
|
|
55
58
|
params: SignTransferTxParams,
|
|
56
59
|
publicKey: string
|
|
57
60
|
): Promise<Omit<SignTransferTxResult, 'signature'>> {
|
|
58
|
-
TransactionBuilder.validatePublicKey(params, publicKey)
|
|
61
|
+
TransactionBuilder.validatePublicKey(params, publicKey, params.signerKeyType ?? 'default')
|
|
59
62
|
|
|
60
63
|
const { destinations, gasPrice, ...rest } = params
|
|
61
64
|
const data: node.BuildTransaction = {
|
|
62
65
|
fromPublicKey: publicKey,
|
|
66
|
+
fromPublicKeyType: params.signerKeyType,
|
|
63
67
|
destinations: toApiDestinations(destinations),
|
|
64
68
|
gasPrice: toApiNumber256Optional(gasPrice),
|
|
65
69
|
...rest
|
|
@@ -72,11 +76,12 @@ export abstract class TransactionBuilder {
|
|
|
72
76
|
params: SignDeployContractTxParams,
|
|
73
77
|
publicKey: string
|
|
74
78
|
): Promise<Omit<SignDeployContractTxResult, 'signature'>> {
|
|
75
|
-
TransactionBuilder.validatePublicKey(params, publicKey)
|
|
79
|
+
TransactionBuilder.validatePublicKey(params, publicKey, params.signerKeyType ?? 'default')
|
|
76
80
|
|
|
77
81
|
const { initialAttoAlphAmount, initialTokenAmounts, issueTokenAmount, gasPrice, ...rest } = params
|
|
78
82
|
const data: node.BuildDeployContractTx = {
|
|
79
83
|
fromPublicKey: publicKey,
|
|
84
|
+
fromPublicKeyType: params.signerKeyType,
|
|
80
85
|
initialAttoAlphAmount: toApiNumber256Optional(initialAttoAlphAmount),
|
|
81
86
|
initialTokenAmounts: toApiTokens(initialTokenAmounts),
|
|
82
87
|
issueTokenAmount: toApiNumber256Optional(issueTokenAmount),
|
|
@@ -92,11 +97,12 @@ export abstract class TransactionBuilder {
|
|
|
92
97
|
params: SignExecuteScriptTxParams,
|
|
93
98
|
publicKey: string
|
|
94
99
|
): Promise<Omit<SignExecuteScriptTxResult, 'signature'>> {
|
|
95
|
-
TransactionBuilder.validatePublicKey(params, publicKey)
|
|
100
|
+
TransactionBuilder.validatePublicKey(params, publicKey, params.signerKeyType ?? 'default')
|
|
96
101
|
|
|
97
102
|
const { attoAlphAmount, tokens, gasPrice, ...rest } = params
|
|
98
103
|
const data: node.BuildExecuteScriptTx = {
|
|
99
104
|
fromPublicKey: publicKey,
|
|
105
|
+
fromPublicKeyType: params.signerKeyType,
|
|
100
106
|
attoAlphAmount: toApiNumber256Optional(attoAlphAmount),
|
|
101
107
|
tokens: toApiTokens(tokens),
|
|
102
108
|
gasPrice: toApiNumber256Optional(gasPrice),
|
package/src/signer/types.ts
CHANGED
|
@@ -33,18 +33,22 @@ export interface Destination {
|
|
|
33
33
|
}
|
|
34
34
|
assertType<Eq<keyof Destination, keyof node.Destination>>
|
|
35
35
|
|
|
36
|
+
export type KeyType = 'default' | 'bip340-schnorr'
|
|
37
|
+
|
|
36
38
|
export interface Account {
|
|
39
|
+
keyType: KeyType
|
|
37
40
|
address: string
|
|
38
41
|
group: number
|
|
39
42
|
publicKey: string
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
export type SignerAddress = { signerAddress: string }
|
|
43
|
-
type TxBuildParams<T> = Omit<T, 'fromPublicKey' | 'targetBlockHash'> & SignerAddress
|
|
45
|
+
export type SignerAddress = { signerAddress: string; signerKeyType?: KeyType }
|
|
46
|
+
type TxBuildParams<T> = Omit<T, 'fromPublicKey' | 'fromPublicKeyType' | 'targetBlockHash'> & SignerAddress
|
|
44
47
|
type SignResult<T> = Omit<T, 'gasPrice'> & { signature: string; gasPrice: Number256 }
|
|
45
48
|
|
|
46
49
|
export interface SignTransferTxParams {
|
|
47
50
|
signerAddress: string
|
|
51
|
+
signerKeyType?: KeyType
|
|
48
52
|
destinations: Destination[]
|
|
49
53
|
utxos?: OutputRef[]
|
|
50
54
|
gasAmount?: number
|
|
@@ -64,6 +68,7 @@ assertType<Eq<SignTransferTxResult, SignResult<node.BuildTransactionResult>>>()
|
|
|
64
68
|
|
|
65
69
|
export interface SignDeployContractTxParams {
|
|
66
70
|
signerAddress: string
|
|
71
|
+
signerKeyType?: KeyType
|
|
67
72
|
bytecode: string
|
|
68
73
|
initialAttoAlphAmount?: Number256
|
|
69
74
|
initialTokenAmounts?: Token[]
|
|
@@ -91,6 +96,7 @@ assertType<
|
|
|
91
96
|
|
|
92
97
|
export interface SignExecuteScriptTxParams {
|
|
93
98
|
signerAddress: string
|
|
99
|
+
signerKeyType?: KeyType
|
|
94
100
|
bytecode: string
|
|
95
101
|
attoAlphAmount?: Number256
|
|
96
102
|
tokens?: Token[]
|
|
@@ -115,6 +121,7 @@ assertType<
|
|
|
115
121
|
|
|
116
122
|
export interface SignUnsignedTxParams {
|
|
117
123
|
signerAddress: string
|
|
124
|
+
signerKeyType?: KeyType
|
|
118
125
|
unsignedTx: string
|
|
119
126
|
}
|
|
120
127
|
assertType<Eq<SignUnsignedTxParams, { unsignedTx: string } & SignerAddress>>()
|
|
@@ -131,6 +138,7 @@ assertType<Eq<SignUnsignedTxResult, SignTransferTxResult>>
|
|
|
131
138
|
|
|
132
139
|
export interface SignMessageParams {
|
|
133
140
|
signerAddress: string
|
|
141
|
+
signerKeyType?: KeyType
|
|
134
142
|
message: string
|
|
135
143
|
}
|
|
136
144
|
assertType<Eq<SignMessageParams, { message: string } & SignerAddress>>()
|
|
@@ -17,22 +17,17 @@ along with the library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import * as utils from '../utils'
|
|
20
|
-
import {
|
|
20
|
+
import { KeyType } from '../signer'
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export function transactionSign(txHash: string, privateKey: string): string {
|
|
25
|
-
const keyPair = ec.keyFromPrivate(privateKey)
|
|
26
|
-
const signature = keyPair.sign(txHash)
|
|
27
|
-
|
|
28
|
-
return utils.encodeSignature(signature)
|
|
22
|
+
export function transactionSign(txId: string, privateKey: string, keyType: KeyType): string {
|
|
23
|
+
return utils.sign(txId, privateKey, keyType)
|
|
29
24
|
}
|
|
30
25
|
|
|
31
|
-
export function transactionVerifySignature(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
export function transactionVerifySignature(
|
|
27
|
+
txId: string,
|
|
28
|
+
publicKey: string,
|
|
29
|
+
signature: string,
|
|
30
|
+
keyType: KeyType
|
|
31
|
+
): boolean {
|
|
32
|
+
return utils.verifySignature(txId, publicKey, signature, keyType)
|
|
38
33
|
}
|
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2018 - 2022 The Alephium Authors
|
|
3
|
+
This file is part of the alephium project.
|
|
4
|
+
|
|
5
|
+
The library is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU Lesser General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
The library is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU Lesser General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
along with the library. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { ec as EC } from 'elliptic'
|
|
20
|
+
import { binToHex, encodeSignature, hexToBinUnsafe, signatureDecode } from '..'
|
|
21
|
+
import { KeyType } from '../signer'
|
|
22
|
+
import * as necc from '@noble/secp256k1'
|
|
23
|
+
import { createHash, createHmac } from 'crypto'
|
|
24
|
+
|
|
25
|
+
const ec = new EC('secp256k1')
|
|
26
|
+
|
|
27
|
+
necc.utils.sha256Sync = (...messages: Uint8Array[]): Uint8Array => {
|
|
28
|
+
const sha256 = createHash('sha256')
|
|
29
|
+
for (const message of messages) sha256.update(message)
|
|
30
|
+
return sha256.digest()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
necc.utils.hmacSha256Sync = (key: Uint8Array, ...messages: Uint8Array[]): Uint8Array => {
|
|
34
|
+
const hash = createHmac('sha256', Buffer.from(key))
|
|
35
|
+
messages.forEach((m) => hash.update(m))
|
|
36
|
+
return Uint8Array.from(hash.digest())
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// hash has to be 32 bytes
|
|
40
|
+
export function sign(hash: string, privateKey: string, _keyType: KeyType): string {
|
|
41
|
+
const keyType = _keyType ?? 'default'
|
|
42
|
+
|
|
43
|
+
if (keyType === 'default') {
|
|
44
|
+
const key = ec.keyFromPrivate(privateKey)
|
|
45
|
+
const signature = key.sign(hash)
|
|
46
|
+
return encodeSignature(signature)
|
|
47
|
+
} else {
|
|
48
|
+
const signature = necc.schnorr.signSync(hexToBinUnsafe(hash), hexToBinUnsafe(privateKey))
|
|
49
|
+
return binToHex(signature)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function verifySignature(hash: string, publicKey: string, signature: string, _keyType: KeyType): boolean {
|
|
54
|
+
const keyType = _keyType ?? 'default'
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
if (keyType === 'default') {
|
|
58
|
+
const key = ec.keyFromPublic(publicKey, 'hex')
|
|
59
|
+
return key.verify(hash, signatureDecode(ec, signature))
|
|
60
|
+
} else {
|
|
61
|
+
return necc.schnorr.verifySync(hexToBinUnsafe(signature), hexToBinUnsafe(hash), hexToBinUnsafe(publicKey))
|
|
62
|
+
}
|
|
63
|
+
} catch (error) {
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
}
|
package/src/utils/utils.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { Buffer } from 'buffer/'
|
|
|
24
24
|
|
|
25
25
|
import { TOTAL_NUMBER_OF_GROUPS } from '../constants'
|
|
26
26
|
import djb2 from './djb2'
|
|
27
|
+
import { KeyType } from '../signer'
|
|
27
28
|
|
|
28
29
|
const ec = new EC('secp256k1')
|
|
29
30
|
|
|
@@ -157,20 +158,35 @@ export function binToHex(bin: Uint8Array): string {
|
|
|
157
158
|
return Buffer.from(bin).toString('hex')
|
|
158
159
|
}
|
|
159
160
|
|
|
160
|
-
export function groupOfPrivateKey(privateKey: string): number {
|
|
161
|
-
return groupOfAddress(addressFromPublicKey(publicKeyFromPrivateKey(privateKey)))
|
|
161
|
+
export function groupOfPrivateKey(privateKey: string, keyType: KeyType): number {
|
|
162
|
+
return groupOfAddress(addressFromPublicKey(publicKeyFromPrivateKey(privateKey, keyType), keyType))
|
|
162
163
|
}
|
|
163
164
|
|
|
164
|
-
export function publicKeyFromPrivateKey(privateKey: string): string {
|
|
165
|
-
const
|
|
166
|
-
|
|
165
|
+
export function publicKeyFromPrivateKey(privateKey: string, _keyType: KeyType): string {
|
|
166
|
+
const keyType = _keyType ?? 'default'
|
|
167
|
+
|
|
168
|
+
if (keyType === 'default') {
|
|
169
|
+
const key = ec.keyFromPrivate(privateKey)
|
|
170
|
+
return key.getPublic(true, 'hex')
|
|
171
|
+
} else {
|
|
172
|
+
return ec.g.mul(new BN(privateKey, 16)).encode('hex', true).slice(2)
|
|
173
|
+
}
|
|
167
174
|
}
|
|
168
175
|
|
|
169
|
-
export function addressFromPublicKey(publicKey: string): string {
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
176
|
+
export function addressFromPublicKey(publicKey: string, _keyType: KeyType): string {
|
|
177
|
+
const keyType = _keyType ?? 'default'
|
|
178
|
+
|
|
179
|
+
if (keyType === 'default') {
|
|
180
|
+
const addressType = Buffer.from([AddressType.P2PKH])
|
|
181
|
+
const hash = Buffer.from(blake.blake2b(Buffer.from(publicKey, 'hex'), undefined, 32))
|
|
182
|
+
const bytes = Buffer.concat([addressType, hash])
|
|
183
|
+
return bs58.encode(bytes)
|
|
184
|
+
} else {
|
|
185
|
+
const lockupScript = Buffer.from(`0101000000000458144020${publicKey}8685`, 'hex')
|
|
186
|
+
const lockupScriptHash = blake.blake2b(lockupScript, undefined, 32)
|
|
187
|
+
const addressType = Buffer.from([AddressType.P2SH])
|
|
188
|
+
return bs58.encode(Buffer.concat([addressType, lockupScriptHash]))
|
|
189
|
+
}
|
|
174
190
|
}
|
|
175
191
|
|
|
176
192
|
export function addressFromContractId(contractId: string): string {
|
|
@@ -219,3 +235,4 @@ type _Eq<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1
|
|
|
219
235
|
export type Eq<X, Y> = _Eq<{ [P in keyof X]: X[P] }, { [P in keyof Y]: Y[P] }>
|
|
220
236
|
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
|
|
221
237
|
export function assertType<T extends true>(): void {}
|
|
238
|
+
export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>
|