Skip to content

Commit

Permalink
feat: add create signature method in identity
Browse files Browse the repository at this point in the history
  • Loading branch information
xstelea committed Jun 13, 2024
1 parent 0e29693 commit bcda653
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 13 deletions.
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/dapp-toolkit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"dependencies": {
"@noble/curves": "^1.4.0",
"base64url": "^3.0.1",
"blakejs": "^1.2.1",
"bowser": "^2.11.0",
"buffer": "^6.0.3",
"immer": "^10.0.4",
Expand Down Expand Up @@ -92,4 +93,4 @@
"publishConfig": {
"registry": "https://registry.npmjs.org"
}
}
}
26 changes: 26 additions & 0 deletions packages/dapp-toolkit/src/modules/wallet-request/crypto/blake2b.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { Result } from 'neverthrow'
import { err, ok } from 'neverthrow'
import blake from 'blakejs'
import { Buffer } from 'buffer'

const bufferToArrayBuffer = (buffer: Buffer): ArrayBuffer => {
const arrayBuffer = new ArrayBuffer(buffer.length)
const view = new Uint8Array(arrayBuffer)
for (let i = 0; i < buffer.length; ++i) {
view[i] = buffer[i]
}
return arrayBuffer
}

const bufferToUnit8Array = (buffer: Buffer): Uint8Array =>
new Uint8Array(bufferToArrayBuffer(buffer))

export const blake2b = (input: Buffer): Result<Buffer, Error> => {
try {
return ok(blake.blake2bHex(bufferToUnit8Array(input), undefined, 32)).map(
(hex) => Buffer.from(hex, 'hex'),
)
} catch (error) {
return err(error as Error)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Buffer } from 'buffer'
import type { Result } from 'neverthrow'
import { blake2b } from './blake2b'

export const createSignatureMessage = ({
interactionId,
dAppDefinitionAddress,
origin,
}: {
interactionId: string
dAppDefinitionAddress: string
origin: string
}): Result<string, { reason: string; jsError: Error }> => {
const prefix = Buffer.from('C', 'ascii')
const lengthOfDappDefAddress = dAppDefinitionAddress.length
const lengthOfDappDefAddressBuffer = Buffer.from(
lengthOfDappDefAddress.toString(16),
'hex',
)
const dappDefAddressBuffer = Buffer.from(dAppDefinitionAddress, 'utf-8')
const originBuffer = Buffer.from(origin, 'utf-8')
const interactionIdBuffer = Buffer.from(interactionId, 'hex')

const messageBuffer = Buffer.concat([
prefix,
interactionIdBuffer,
lengthOfDappDefAddressBuffer,
dappDefAddressBuffer,
originBuffer,
])

return blake2b(messageBuffer)
.map((hash) => Buffer.from(hash).toString('hex'))
.mapErr((jsError) => ({ reason: 'couldNotHashMessage', jsError }))
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { x25519 } from '@noble/curves/ed25519'
import { x25519, ed25519 } from '@noble/curves/ed25519'
import { Buffer } from 'buffer'
import { Result, err, ok } from 'neverthrow'

Expand All @@ -8,6 +8,7 @@ export type KeyPairProvider = (privateKeyHex?: string) => {
getPublicKey: () => string
getPrivateKey: () => string
calculateSharedSecret: (publicKeyHex: string) => Result<string, Error>
sign: (messageHex: string) => Result<string, Error>
}

export type Curve25519 = ReturnType<typeof Curve25519>
Expand All @@ -29,5 +30,13 @@ export const Curve25519: KeyPairProvider = (
}
}

return { getPublicKey, getPrivateKey, calculateSharedSecret }
const sign = (messageHex: string): Result<string, Error> => {
try {
return ok(toHex(ed25519.sign(privateKeyHex, messageHex)))
} catch (error) {
return err(error as Error)
}
}

return { getPublicKey, getPrivateKey, calculateSharedSecret, sign }
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { err, ok, okAsync } from 'neverthrow'
import { ResultAsync, err, ok, okAsync } from 'neverthrow'
import { StorageModule } from '../../storage/local-storage.module'
import type { KeyPairProvider } from '../crypto'
import { createSignatureMessage } from '../crypto/create-signature-message'

export const IdentityKind = {
dApp: 'dApp',
Expand Down Expand Up @@ -42,9 +43,12 @@ export const IdentityModule = (input: {
)

const getOrCreateIdentity = (kind: IdentityKind) =>
getIdentity(kind).andThen((keyPair) =>
keyPair ? okAsync(keyPair) : createIdentity(kind),
)
getIdentity(kind)
.andThen((keyPair) => (keyPair ? okAsync(keyPair) : createIdentity(kind)))
.mapErr((error) => ({
reason: 'couldNotGetOrCreateIdentity',
jsError: error,
}))

const deriveSharedSecret = (kind: IdentityKind, publicKey: string) =>
getIdentity(kind)
Expand All @@ -57,8 +61,39 @@ export const IdentityModule = (input: {
: err({ reason: 'DappIdentityNotFound' }),
)

const createSignature = ({
kind,
interactionId,
dAppDefinitionAddress,
origin,
}: {
kind: IdentityKind
interactionId: string
dAppDefinitionAddress: string
origin: string
}): ResultAsync<
string,
{
reason: string
jsError: Error
}
> =>
getOrCreateIdentity(kind).andThen((identity) =>
createSignatureMessage({
interactionId,
dAppDefinitionAddress,
origin,
}).andThen((message) =>
identity.sign(message).mapErr((error) => ({
reason: 'couldNotSignMessage',
jsError: error,
})),
),
)

return {
get: (kind: IdentityKind) => getOrCreateIdentity(kind),
deriveSharedSecret,
createSignature,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,19 @@ export const RadixConnectRelayModule = (input: {
walletInteraction: WalletInteraction,
callbackFns: Partial<CallbackFns>,
): ResultAsync<WalletInteractionResponse, SdkError> =>
sessionModule
.getCurrentSession()
.mapErr(() =>
SdkError('FailedToReadSession', walletInteraction.interactionId),
)
.andThen((session) =>
ResultAsync.combine([
identityModule
.get('dApp')
.mapErr(() =>
SdkError('FailedToGetDappIdentity', walletInteraction.interactionId),
),
sessionModule
.getCurrentSession()
.mapErr(() =>
SdkError('FailedToReadSession', walletInteraction.interactionId),
),
])
.andThen(([dAppIdentity, session]) =>
(session.status === 'Pending'
? sendWalletLinkingRequest(session)
: sendWalletInteractionRequest(session, walletInteraction)
Expand Down

0 comments on commit bcda653

Please sign in to comment.