Skip to content

Commit 8f3903d

Browse files
authored
fix bech32 as it should use HASH160 not SHA256 (#171)
* fix bech32 as it should use HASH160 not SHA256 * rebuild and updated p2wpkh tests
1 parent a279db6 commit 8f3903d

File tree

5 files changed

+79
-25
lines changed

5 files changed

+79
-25
lines changed
Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,56 @@
1-
import { HASH160, Bech32 } from '../src'
1+
import { HASH160, Bech32, HRP } from '../src'
22

3-
const hrp = 'bcrt'
4-
const bech32 = 'bcrt1qykj5fsrne09yazx4n72ue4fwtpx8u65zac9zhn'
5-
const pubKey = '03987aec2e508e124468f0f07a836d185b329026e7aaf75be48cf12be8f18cbe81'
3+
const keypair = {
4+
hrp: 'bcrt' as HRP,
5+
bech32: 'bcrt1qykj5fsrne09yazx4n72ue4fwtpx8u65zac9zhn',
6+
pubKey: '03987aec2e508e124468f0f07a836d185b329026e7aaf75be48cf12be8f18cbe81'
7+
}
8+
9+
it('should convert bech32 to hash160', () => {
10+
const buffer: Buffer = Bech32.toHash160(keypair.bech32)
11+
12+
const pubKey = Buffer.from(keypair.pubKey, 'hex')
13+
const hash160 = HASH160(pubKey)
614

7-
it('should convert bech32 to pubkey', () => {
8-
const buffer: Buffer = Bech32.toPubKey(bech32)
9-
const hash160 = HASH160(Buffer.from(pubKey, 'hex'))
1015
expect(buffer.toString('hex')).toBe(hash160.toString('hex'))
1116
})
1217

13-
it('should convert bech32 to pubkey with hrp and version', () => {
14-
const buffer: Buffer = Bech32.toPubKey(bech32, 'bcrt', 0x00)
15-
const hash160 = HASH160(Buffer.from(pubKey, 'hex'))
18+
it('should convert bech32 to hash160 with hrp and version', () => {
19+
const buffer: Buffer = Bech32.toHash160(keypair.bech32, 'bcrt', 0x00)
20+
21+
const pubKey = Buffer.from(keypair.pubKey, 'hex')
22+
const hash160 = HASH160(pubKey)
23+
1624
expect(buffer.toString('hex')).toBe(hash160.toString('hex'))
1725
})
1826

1927
it('should fail convert bech32 to pubkey with invalid hrp', () => {
2028
expect(() => {
21-
Bech32.toPubKey(bech32, 'tf', 0x00)
29+
Bech32.toHash160(keypair.bech32, 'tf', 0x00)
2230
}).toThrow('Invalid HRP: human readable part')
2331
})
2432

2533
it('should fail convert bech32 to pubkey with invalid version', () => {
2634
expect(() => {
2735
// @ts-expect-error
28-
Bech32.toPubKey(bech32, 'bcrt', 0x01)
36+
Bech32.toHash160(keypair.bech32, 'bcrt', 0x01)
2937
}).toThrow('Invalid witness version')
3038
})
3139

3240
it('should convert pubkey to bech32', () => {
33-
const bech32 = Bech32.fromPubKey(Buffer.from(pubKey, 'hex'), hrp)
34-
expect(bech32).toBe(bech32)
41+
const pubKey = Buffer.from(keypair.pubKey, 'hex')
42+
const bech32 = Bech32.fromPubKey(pubKey, keypair.hrp)
43+
expect(bech32).toBe(keypair.bech32)
3544
})
3645

3746
it('should convert pubkey to bech32 with witness version', () => {
38-
const bech32 = Bech32.fromPubKey(Buffer.from(pubKey, 'hex'), hrp, 0x00)
39-
expect(bech32).toBe(bech32)
47+
const pubKey = Buffer.from(keypair.pubKey, 'hex')
48+
const bech32 = Bech32.fromPubKey(pubKey, keypair.hrp, 0x00)
49+
expect(bech32).toBe(keypair.bech32)
50+
})
51+
52+
it('should from bech32 to hash160 back to bech32', async () => {
53+
const hash160: Buffer = Bech32.toHash160(keypair.bech32)
54+
const bech32 = Bech32.fromHash160(hash160, keypair.hrp)
55+
expect(bech32).toBe(keypair.bech32)
4056
})
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Bech32, Elliptic, WIF } from '../src'
2+
3+
describe('keySet 1', () => {
4+
const keySet = {
5+
bech32: 'bcrt1qykj5fsrne09yazx4n72ue4fwtpx8u65zac9zhn',
6+
wif: 'cQSsfYvYkK5tx3u1ByK2ywTTc9xJrREc1dd67ZrJqJUEMwgktPWN'
7+
}
8+
9+
it('should convert from WIF to priv to pub to bech32', async () => {
10+
const wifDecoded = WIF.decode(keySet.wif)
11+
const privKey = wifDecoded.privateKey
12+
const pubKey = await Elliptic.fromPrivKey(privKey).publicKey()
13+
expect(Bech32.fromPubKey(pubKey, 'bcrt')).toBe(keySet.bech32)
14+
})
15+
})
16+
17+
describe('keySet 2', () => {
18+
const keySet = {
19+
bech32: 'bcrt1qf26rj8895uewxcfeuukhng5wqxmmpqp555z5a7',
20+
wif: 'cQbfHFbdJNhg3UGaBczir2m5D4hiFRVRKgoU8GJoxmu2gEhzqHtV'
21+
}
22+
23+
it('should convert from WIF to priv to pub to bech32', async () => {
24+
const wifDecoded = WIF.decode(keySet.wif)
25+
const privKey = wifDecoded.privateKey
26+
const pubKey = await Elliptic.fromPrivKey(privKey).publicKey()
27+
expect(Bech32.fromPubKey(pubKey, 'bcrt')).toBe(keySet.bech32)
28+
})
29+
})

packages/jellyfish-crypto/src/bech32.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { bech32 } from 'bech32'
2-
import { SHA256 } from './hash'
2+
import { HASH160 } from './hash'
33

44
/**
55
* Human Readable Part, prefixed to all bech32/segwit native address
@@ -11,15 +11,14 @@ import { SHA256 } from './hash'
1111
export type HRP = 'df' | 'tf' | 'bcrt'
1212

1313
/**
14-
* @param {Buffer} pubKey to format into bech32
14+
* @param {Buffer} hash160 to format into bech32
1515
* @param {'df'|'tf'|'bcrt'} hrp is the human readable part
1616
* @param {number} [version=0x00] witness version, OP_0
1717
* @return {string} bech32 encoded address
1818
* @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
1919
*/
20-
function toBech32 (pubKey: Buffer, hrp: HRP, version: 0x00 = 0x00): string {
21-
const hash = SHA256(pubKey)
22-
const words = bech32.toWords(hash)
20+
function toBech32 (hash160: Buffer, hrp: HRP, version: 0x00 = 0x00): string {
21+
const words = bech32.toWords(hash160)
2322
words.unshift(version)
2423
return bech32.encode(hrp, words)
2524
}
@@ -53,15 +52,25 @@ export const Bech32 = {
5352
* @return {string} bech32 encoded address
5453
*/
5554
fromPubKey (pubKey: Buffer, hrp: HRP, version: 0x00 = 0x00): string {
56-
return toBech32(pubKey, hrp, version)
55+
const hash = HASH160(pubKey)
56+
return toBech32(hash, hrp, version)
57+
},
58+
/**
59+
* @param {Buffer} hash160 to format into bech32
60+
* @param {'df'|'tf'|'bcrt'} hrp is the human readable part
61+
* @param {number} [version=0x00] witness version, OP_0
62+
* @return {string} bech32 encoded address
63+
*/
64+
fromHash160 (hash160: Buffer, hrp: HRP, version: 0x00 = 0x00) {
65+
return toBech32(hash160, hrp, version)
5766
},
5867
/**
5968
* @param {string} address to decode from bech32
6069
* @param {'df'|'tf'|'bcrt'} hrp is the human readable part
6170
* @param {number} [version] witness version, OP_0
6271
* @return {Buffer} hash160 of the pubkey
6372
*/
64-
toPubKey (address: string, hrp?: HRP, version?: 0x00): Buffer {
73+
toHash160 (address: string, hrp?: HRP, version?: 0x00): Buffer {
6574
return fromBech32(address, hrp, version)
6675
}
6776
}

packages/jellyfish-transaction/__tests__/tx/p2wpkh_1_to_1.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ it('sign transaction', async () => {
4242
script: {
4343
stack: [
4444
OP_CODES.OP_0,
45-
OP_CODES.OP_PUSHDATA(Bech32.toPubKey(input.bech32, 'bcrt', 0x00), 'little')
45+
OP_CODES.OP_PUSHDATA(Bech32.toHash160(input.bech32, 'bcrt', 0x00), 'little')
4646
]
4747
},
4848
value: new BigNumber('10'),

packages/jellyfish-transaction/__tests__/tx/p2wpkh_1_to_2.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ it('sign transaction', async () => {
4242
script: {
4343
stack: [
4444
OP_CODES.OP_0,
45-
OP_CODES.OP_PUSHDATA(Bech32.toPubKey(input.bech32, 'bcrt', 0x00), 'little')
45+
OP_CODES.OP_PUSHDATA(Bech32.toHash160(input.bech32, 'bcrt', 0x00), 'little')
4646
]
4747
},
4848
value: new BigNumber('10'),

0 commit comments

Comments
 (0)