forked from status-im/status-web
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add public key deserialization (status-im#341)
* add `multiformats` dep * add `deserialize-public-key.ts` * compress by default * add tests * Update packages/status-js/src/utils/deserialize-public-key.ts Co-authored-by: Pavel <[email protected]> * rename vars --------- Co-authored-by: Pavel <[email protected]>
- Loading branch information
Showing
4 changed files
with
125 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
packages/status-js/src/utils/deserialize-public-key.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { expect, test } from 'vitest' | ||
|
||
import { deserializePublicKey } from './deserialize-public-key' | ||
|
||
test('should deserialize public key from compressed base58btc encoding', () => { | ||
expect( | ||
deserializePublicKey('zQ3shY7r4cAdg4eUF5dfcuCqCFzWmdjHW4SX5hspM9ucAarfU') | ||
).toEqual( | ||
'0x029f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133' | ||
) | ||
}) | ||
|
||
test('should deserialize public key from compressed hexadecimal encoding', () => { | ||
expect( | ||
deserializePublicKey( | ||
'0x029f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133' | ||
) | ||
).toEqual( | ||
'0x029f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133' | ||
) | ||
}) | ||
|
||
test('should deserialize public key from uncompressed hexadecimal encoding', () => { | ||
expect( | ||
deserializePublicKey( | ||
'0x049f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb454295513305b23fcf11d005ee622144fc402b713a8928f80d705781e2e78d701c6e01bfc4' | ||
) | ||
).toEqual( | ||
'0x029f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133' | ||
) | ||
}) | ||
|
||
test('should throw when deserializing unsupported multibase encoding', () => { | ||
expect(() => | ||
deserializePublicKey('ZQ3shY7r4cAdg4eUF5dfcuCqCFzWmdjHW4SX5hspM9ucAarfU') | ||
).toThrowError() | ||
}) | ||
|
||
test('should throw when deserializing invalid public key', () => { | ||
expect(() => | ||
deserializePublicKey( | ||
'0x019f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133' | ||
) | ||
).toThrowError() | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { Point } from 'ethereum-cryptography/secp256k1' | ||
import { | ||
toHex, | ||
// utf8ToBytes as toBytes, // see https://github.com/paulmillr/noble-hashes/blob/d76eb7c818931d290c4c27abb778e8e269895154/src/utils.ts#L91-L96 | ||
} from 'ethereum-cryptography/utils' | ||
import { varint } from 'multiformats' | ||
import { base58btc } from 'multiformats/bases/base58' | ||
|
||
/** | ||
* @see https://github.com/multiformats/multibase/blob/af2d36bdfaeaca453d20b18542ca57bd56b51f6c/README.md#multibase-table | ||
*/ | ||
const VALID_MULTIBASE_CODES = [ | ||
'f', // hexadecimal | ||
'z', // base58btc | ||
] as const | ||
|
||
type MultibaseCode = typeof VALID_MULTIBASE_CODES[number] | ||
|
||
/** | ||
* @see https://pkg.go.dev/github.com/multiformats/go-multicodec#pkg-types | ||
*/ | ||
const VALID_MULTICODEC_CODES = [ | ||
231, // secp256k1-pub (compressed) (0xe7) | ||
] as const | ||
|
||
type MulticodecCode = typeof VALID_MULTICODEC_CODES[number] | ||
|
||
/** | ||
* @see https://specs.status.im/spec/2#public-key-serialization for specification | ||
*/ | ||
export function deserializePublicKey( | ||
publicKey: string, // uncompressed, compressed, or compressed & encoded | ||
options = { compress: true } | ||
): string { | ||
const multibasePublicKey = publicKey.replace(/^0[xX]/, 'f') // ensure multibase code for hexadecimal encoding | ||
const multibaseCode = multibasePublicKey[0] as MultibaseCode | ||
|
||
if (!VALID_MULTIBASE_CODES.includes(multibaseCode)) { | ||
throw new Error('Invalid public key multibase code') | ||
} | ||
|
||
let hexadecimalPublicKey: string | ||
switch (multibaseCode) { | ||
case 'z': { | ||
const base58btcPublicKey = base58btc.decode(multibasePublicKey) | ||
const multicodec = varint.decode(base58btcPublicKey) | ||
const multicodecCode = multicodec[0] as MulticodecCode | ||
const multicodecCodeByteLength = multicodec[1] | ||
|
||
if (!VALID_MULTICODEC_CODES.includes(multicodecCode)) { | ||
throw new Error('Invalid public key multicodec code') | ||
} | ||
|
||
hexadecimalPublicKey = toHex( | ||
base58btcPublicKey.slice(multicodecCodeByteLength) | ||
) | ||
|
||
break | ||
} | ||
|
||
case 'f': { | ||
hexadecimalPublicKey = multibasePublicKey.slice(1) | ||
|
||
break | ||
} | ||
|
||
default: { | ||
throw new Error('Unsupported public key multicodec code') | ||
} | ||
} | ||
|
||
return `0x${Point.fromHex(hexadecimalPublicKey).toHex(options.compress)}` // validates and sets compression | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters