UNPKG

1.83 kBPlain TextView Raw
1import { sha256 as sha256Hash } from '@noble/hashes/sha256'
2export { ripemd160 } from '@noble/hashes/ripemd160'
3import { keccak_256 } from '@noble/hashes/sha3'
4import { fromString, toString, concat } from 'uint8arrays'
5
6export function sha256(payload: string | Uint8Array): Uint8Array {
7 const data = typeof payload === 'string' ? fromString(payload) : payload
8 return sha256Hash(data)
9}
10
11export const keccak = keccak_256
12
13export function toEthereumAddress(hexPublicKey: string): string {
14 const hashInput = fromString(hexPublicKey.slice(2), 'base16')
15 return `0x${toString(keccak(hashInput).slice(-20), 'base16')}`
16}
17
18function writeUint32BE(value: number, array = new Uint8Array(4)): Uint8Array {
19 const encoded = fromString(value.toString(), 'base10')
20 array.set(encoded, 4 - encoded.length)
21 return array
22}
23
24const lengthAndInput = (input: Uint8Array): Uint8Array => concat([writeUint32BE(input.length), input])
25
26// This implementation of concatKDF was inspired by these two implementations:
27// https://github.com/digitalbazaar/minimal-cipher/blob/master/algorithms/ecdhkdf.js
28// https://github.com/panva/jose/blob/master/lib/jwa/ecdh/derive.js
29export function concatKDF(
30 secret: Uint8Array,
31 keyLen: number,
32 alg: string,
33 producerInfo?: Uint8Array,
34 consumerInfo?: Uint8Array
35): Uint8Array {
36 if (keyLen !== 256) throw new Error(`Unsupported key length: ${keyLen}`)
37 const value = concat([
38 lengthAndInput(fromString(alg)),
39 lengthAndInput(typeof producerInfo === 'undefined' ? new Uint8Array(0) : producerInfo), // apu
40 lengthAndInput(typeof consumerInfo === 'undefined' ? new Uint8Array(0) : consumerInfo), // apv
41 writeUint32BE(keyLen),
42 ])
43
44 // since our key lenght is 256 we only have to do one round
45 const roundNumber = 1
46 return sha256(concat([writeUint32BE(roundNumber), secret, value]))
47}