1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | 'use strict'
|
13 |
|
14 | import { Address } from './address'
|
15 | import { Bw } from './bw'
|
16 | import { cmp } from './cmp'
|
17 | import { Ecdsa } from './ecdsa'
|
18 | import { Hash } from './hash'
|
19 | import { KeyPair } from './key-pair'
|
20 | import { Sig } from './sig'
|
21 | import { Struct } from './struct'
|
22 | import { Workers } from './workers'
|
23 |
|
24 | class Bsm extends Struct {
|
25 | constructor (messageBuf, keyPair, sig, address, verified) {
|
26 | super({ messageBuf, keyPair, sig, address, verified })
|
27 | }
|
28 |
|
29 | static magicHash (messageBuf) {
|
30 | if (!Buffer.isBuffer(messageBuf)) {
|
31 | throw new Error('messageBuf must be a buffer')
|
32 | }
|
33 | const bw = new Bw()
|
34 | bw.writeVarIntNum(Bsm.magicBytes.length)
|
35 | bw.write(Bsm.magicBytes)
|
36 | bw.writeVarIntNum(messageBuf.length)
|
37 | bw.write(messageBuf)
|
38 | const buf = bw.toBuffer()
|
39 |
|
40 | const hashBuf = Hash.sha256Sha256(buf)
|
41 |
|
42 | return hashBuf
|
43 | }
|
44 |
|
45 | static async asyncMagicHash (messageBuf) {
|
46 | const args = [messageBuf]
|
47 | const workersResult = await Workers.asyncClassMethod(Bsm, 'magicHash', args)
|
48 | return workersResult.resbuf
|
49 | }
|
50 |
|
51 | static sign (messageBuf, keyPair) {
|
52 | const m = new Bsm(messageBuf, keyPair)
|
53 | m.sign()
|
54 | const sigbuf = m.sig.toCompact()
|
55 | const sigstr = sigbuf.toString('base64')
|
56 | return sigstr
|
57 | }
|
58 |
|
59 | static async asyncSign (messageBuf, keyPair) {
|
60 | const args = [messageBuf, keyPair]
|
61 | const workersResult = await Workers.asyncClassMethod(Bsm, 'sign', args)
|
62 | const sigstr = JSON.parse(workersResult.resbuf.toString())
|
63 | return sigstr
|
64 | }
|
65 |
|
66 | static verify (messageBuf, sigstr, address) {
|
67 | const sigbuf = Buffer.from(sigstr, 'base64')
|
68 | const message = new Bsm()
|
69 | message.messageBuf = messageBuf
|
70 | message.sig = new Sig().fromCompact(sigbuf)
|
71 | message.address = address
|
72 |
|
73 | return message.verify().verified
|
74 | }
|
75 |
|
76 | static async asyncVerify (messageBuf, sigstr, address) {
|
77 | const args = [messageBuf, sigstr, address]
|
78 | const workersResult = await Workers.asyncClassMethod(Bsm, 'verify', args)
|
79 | const res = JSON.parse(workersResult.resbuf.toString())
|
80 | return res
|
81 | }
|
82 |
|
83 | sign () {
|
84 | const hashBuf = Bsm.magicHash(this.messageBuf)
|
85 | const ecdsa = new Ecdsa().fromObject({
|
86 | hashBuf: hashBuf,
|
87 | keyPair: this.keyPair
|
88 | })
|
89 | ecdsa.sign()
|
90 | ecdsa.calcrecovery()
|
91 | this.sig = ecdsa.sig
|
92 | return this
|
93 | }
|
94 |
|
95 | verify () {
|
96 | const hashBuf = Bsm.magicHash(this.messageBuf)
|
97 |
|
98 | const ecdsa = new Ecdsa()
|
99 | ecdsa.hashBuf = hashBuf
|
100 | ecdsa.sig = this.sig
|
101 | ecdsa.keyPair = new KeyPair()
|
102 | ecdsa.keyPair.pubKey = ecdsa.sig2PubKey()
|
103 |
|
104 | if (!ecdsa.verify()) {
|
105 | this.verified = false
|
106 | return this
|
107 | }
|
108 |
|
109 | const address = new Address().fromPubKey(
|
110 | ecdsa.keyPair.pubKey,
|
111 | undefined,
|
112 | this.sig.compressed
|
113 | )
|
114 |
|
115 | if (cmp(address.hashBuf, this.address.hashBuf)) {
|
116 | this.verified = true
|
117 | } else {
|
118 | this.verified = false
|
119 | }
|
120 |
|
121 | return this
|
122 | }
|
123 | }
|
124 |
|
125 | Bsm.magicBytes = Buffer.from('Bitcoin Signed Message:\n')
|
126 |
|
127 | export { Bsm }
|