Use chat keys in the UI (#274)

* add util for compressing public key

* add chat keys to account and member

* use compressPublicKey in color hash util

* use chat keys in UI
This commit is contained in:
Pavel 2022-06-14 14:28:08 +02:00 committed by GitHub
parent dd67a504bf
commit c45d0a61f0
No known key found for this signature in database
GPG Key ID: 0EB8D75C775AB6F1
9 changed files with 65 additions and 26 deletions

View File

@ -2,6 +2,7 @@ import { keccak256 } from 'ethereum-cryptography/keccak'
import { getPublicKey, sign, utils } from 'ethereum-cryptography/secp256k1'
import { bytesToHex, concatBytes } from 'ethereum-cryptography/utils'
import { compressPublicKey } from './utils/compress-public-key'
import { generateUsername } from './utils/generate-username'
export class Account {
@ -13,12 +14,10 @@ export class Account {
constructor() {
const privateKey = utils.randomPrivateKey()
const publicKey = getPublicKey(privateKey)
const chatKey = getPublicKey(privateKey, true)
this.privateKey = bytesToHex(privateKey)
this.publicKey = bytesToHex(publicKey)
// TODO?: add 0x prefix to public key
this.chatKey = bytesToHex(chatKey)
this.chatKey = '0x' + compressPublicKey(this.publicKey)
this.username = generateUsername('0x' + this.publicKey)
}

View File

@ -1,3 +1,4 @@
import { compressPublicKey } from '../utils/compress-public-key'
import { generateUsername } from '../utils/generate-username'
import { publicKeyToColorHash } from '../utils/public-key-to-color-hash'
@ -5,13 +6,14 @@ import type { ColorHash } from '../utils/public-key-to-color-hash'
export class Member {
publicKey: string
chatKey: string
username: string
colorHash: ColorHash
constructor(publicKey: string) {
this.publicKey = publicKey
this.chatKey = '0x' + compressPublicKey(publicKey)
this.username = generateUsername(publicKey)
// TODO: can it fail?
this.colorHash = publicKeyToColorHash(publicKey)!
this.colorHash = publicKeyToColorHash(publicKey)
}
}

View File

@ -0,0 +1,30 @@
import { getPublicKey, utils } from 'ethereum-cryptography/secp256k1'
import { bytesToHex } from 'ethereum-cryptography/utils'
import { compressPublicKey } from './compress-public-key'
describe('compressPublicKey', () => {
it('should return compressed public key', () => {
const privateKey = utils.randomPrivateKey()
const publicKey = bytesToHex(getPublicKey(privateKey))
const compressedPublicKey = bytesToHex(getPublicKey(privateKey, true))
expect(compressPublicKey(publicKey)).toEqual(compressedPublicKey)
})
it('should accept public key with a base prefix', () => {
const privateKey = utils.randomPrivateKey()
const publicKey = '0x' + bytesToHex(getPublicKey(privateKey))
const compressedPublicKey = bytesToHex(getPublicKey(privateKey, true))
expect(compressPublicKey(publicKey)).toEqual(compressedPublicKey)
})
it('should throw error if public key is not a valid hex', () => {
expect(() => {
compressPublicKey('not a valid public key')
}).toThrowErrorMatchingInlineSnapshot(`"Invalid public key"`)
})
})

View File

@ -0,0 +1,10 @@
import * as secp from 'ethereum-cryptography/secp256k1'
export function compressPublicKey(publicKey: string): string {
try {
const pk = publicKey.replace(/^0[xX]/, '') // ensures hexadecimal digits without "base prefix"
return secp.Point.fromHex(pk).toHex(true)
} catch (error) {
throw new Error('Invalid public key')
}
}

View File

@ -1,22 +1,16 @@
import * as secp256k1 from 'ethereum-cryptography/secp256k1'
import { compressPublicKey } from './compress-public-key'
export type ColorHash = number[][]
const COLOR_HASH_COLORS_COUNT = 32
const COLOR_HASH_SEGMENT_MAX_LENGTH = 5
export function publicKeyToColorHash(publicKey: string): ColorHash | undefined {
const publicKeyHex = publicKey.replace(/^0[xX]/, '') // ensures hexadecimal digits without "base prefix"
export function publicKeyToColorHash(publicKey: string): ColorHash {
const compressedPublicKey = compressPublicKey(publicKey)
let compressedPublicKeyDigits: string
try {
compressedPublicKeyDigits =
secp256k1.Point.fromHex(publicKeyHex).toHex(true) // validates and adds "sign prefix" too
} catch (error) {
return undefined
}
const colorHashHex = compressedPublicKeyDigits.slice(43, 63)
const colorHashHex = compressedPublicKey.slice(43, 63)
const colorHash = hexToColorHash(
colorHashHex,
COLOR_HASH_COLORS_COUNT,

View File

@ -20,7 +20,7 @@ export const DisconnectDialog = (props: Props) => {
<Flex direction="column" align="center" gap="2">
<Avatar size={64} />
<Heading weight="600">{account.username}</Heading>
<Text color="gray">Chatkey: {account.publicKey}</Text>
<Text color="gray">Chatkey: {account.chatKey}</Text>
<EmojiHash />
</Flex>
</Dialog.Body>

View File

@ -14,7 +14,7 @@ interface Props {
export const MemberItem = (props: Props) => {
const { member, indicator, verified, untrustworthy } = props
const { publicKey, username, colorHash } = member
const { chatKey, username, colorHash } = member
return (
<Flex gap="2" align="center" css={{ height: 56 }}>
@ -65,7 +65,7 @@ export const MemberItem = (props: Props) => {
)}
</Flex>
<EthAddress size={10} color="gray">
{publicKey}
{chatKey}
</EthAddress>
</div>
</Flex>

View File

@ -25,7 +25,7 @@ export const UserItem = (props: Props) => {
</Text>
</Flex>
<EthAddress size={10} color="gray">
{account.publicKey}
{account.chatKey}
</EthAddress>
</div>
</Flex>

View File

@ -2,20 +2,24 @@ import React from 'react'
import { Avatar, Dialog, EmojiHash, Heading, Text } from '~/src/system'
import type { Member } from '~/src/protocol'
interface Props {
name: string
member: Member
}
// TODO: Add all states of contact, wait for desktop release
export const UserProfileDialog = (props: Props) => {
const { name, ...dialogProps } = props
const { member, ...dialogProps } = props
const { username, colorHash, chatKey } = member
return (
<Dialog title={`${name}'s Profile`} size="640" {...dialogProps}>
<Dialog title={`${username}'s Profile`} size="640" {...dialogProps}>
<Dialog.Body align="center">
<Avatar size="80" />
<Heading size="22">{name}</Heading>
<Text>Chatkey: 0x63FaC9201494f0bd17B9892B9fae4d52fe3BD377</Text>
<Avatar size="80" name={username} colorHash={colorHash} />
<Heading size="22">{username}</Heading>
<Text>Chatkey: {chatKey}</Text>
<EmojiHash />
</Dialog.Body>
<Dialog.Actions>