Skip to content

Commit

Permalink
lint
Browse files Browse the repository at this point in the history
  • Loading branch information
patnir committed Sep 20, 2024
1 parent 7e1530e commit 7a3398f
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 127 deletions.
3 changes: 2 additions & 1 deletion ironfish-cli/src/commands/wallet/multisig/dkg/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ export class DkgCreateCommand extends IronfishCommand {
}

this.logger.log(
`\nEnter ${totalParticipants - 1
`\nEnter ${
totalParticipants - 1
} identities of all other participants (excluding yours) `,
)
const identities = await this.collectStrings('Identity', totalParticipants - 1, [
Expand Down
10 changes: 7 additions & 3 deletions ironfish-cli/src/commands/wallet/multisig/dkg/round1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,18 @@ export class DkgRound1Command extends IronfishCommand {
}

if (flags.ledger) {
const identityResponse = await client.wallet.multisig.getIdentity({ name: participantName })
const identityResponse = await client.wallet.multisig.getIdentity({
name: participantName,
})
const identity = identityResponse.content.identity
identities.push(identity)

const uniqueIdentities = [...new Set(identities)]

const { secretPackage, publicPackage } = await this.performRound1WithLedger(uniqueIdentities, minSigners)

const { secretPackage, publicPackage } = await this.performRound1WithLedger(
uniqueIdentities,
minSigners,
)

this.log('\nRound 1 Encrypted Secret Package:\n')
this.log(secretPackage.toString('hex'))
Expand Down
41 changes: 22 additions & 19 deletions ironfish-cli/src/commands/wallet/multisig/dkg/round2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,23 @@ export class DkgRound2Command extends IronfishCommand {
round1PublicPackages = round1PublicPackages.map((i) => i.trim())

if (flags.ledger) {
await this.performRound2WithLedger(round1PublicPackages, round1SecretPackage)
const { secretPackage, publicPackage } = await this.performRound2WithLedger(
round1PublicPackages,
round1SecretPackage,
)

this.log('\nRound 2 Encrypted Secret Package:\n')
this.log(secretPackage.toString('hex'))
this.log()

this.log('\nRound 2 Public Package:\n')
this.log(publicPackage.toString('hex'))
this.log()

this.log()
this.log('Next step:')
this.log('Send the round 2 public package to each participant')

return
}

Expand All @@ -96,26 +112,13 @@ export class DkgRound2Command extends IronfishCommand {
async performRound2WithLedger(
round1PublicPackages: string[],
round1SecretPackage: string,
): Promise<void> {
): Promise<{
secretPackage: Buffer
publicPackage: Buffer
}> {
const ledger = await createLedgerInstance(true, this.logger)

// TODO(hughy): determine how to handle multiple identities using index
const { publicPackage, secretPackage } = await ledger.dkgRound2(
0,
round1PublicPackages,
round1SecretPackage,
)

this.log('\nRound 2 Encrypted Secret Package:\n')
this.log(secretPackage.toString('hex'))
this.log()

this.log('\nRound 2 Public Package:\n')
this.log(publicPackage.toString('hex'))
this.log()

this.log()
this.log('Next step:')
this.log('Send the round 2 public package to each participant')
return await ledger.dkgRound2(0, round1PublicPackages, round1SecretPackage)
}
}
160 changes: 66 additions & 94 deletions ironfish-cli/src/commands/wallet/multisig/dkg/round3.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import {
deserializePublicPackage,
deserializeRound2CombinedPublicPackage,
} from '@ironfish/rust-nodejs'
import { AccountFormat, RpcClient, encodeAccountImport } from '@ironfish/sdk'
import { AccountFormat, encodeAccountImport } from '@ironfish/sdk'
import { Flags } from '@oclif/core'
import { IronfishCommand } from '../../../../command'
import { RemoteFlags } from '../../../../flags'
Expand Down Expand Up @@ -112,13 +108,55 @@ export class DkgRound3Command extends IronfishCommand {
round2PublicPackages = round2PublicPackages.map((i) => i.trim())

if (flags.ledger) {
await this.performRound3WithLedger(
client,
participantName,
const identityResponse = await client.wallet.multisig.getIdentity({
name: participantName,
})
const identity = identityResponse.content.identity

const { dkgKeys, publicKeyPackage } = await this.performRound3WithLedger(
identity,
round1PublicPackages,
round2PublicPackages,
round2SecretPackage,
)

const accountImport = {
...dkgKeys,
multisigKeys: {
publicKeyPackage: publicKeyPackage.toString('hex'),
identity,
},
version: 4,
name: participantName,
spendingKey: null,
createdAt: null,
}

// Import multisig account
const response = await client.wallet.importAccount({
account: encodeAccountImport(accountImport, AccountFormat.Base64Json),
})

this.log()
this.log(
`Account ${response.content.name} imported with public address: ${dkgKeys.publicAddress}`,
)

this.log()
this.log('Creating an encrypted backup of multisig keys from your Ledger device...')
this.log()

const encryptedKeys = await this.backupKeysWithLedger()

this.log()
this.log('Encrypted Ledger Multisig Backup:')
this.log(encryptedKeys.toString('hex'))
this.log()
this.log('Please save the encrypted keys show above.')
this.log(
'Use `ironfish wallet:multisig:ledger:restore` if you need to restore the keys to your Ledger.',
)

return
}

Expand All @@ -136,99 +174,33 @@ export class DkgRound3Command extends IronfishCommand {
)
}

async backupKeysWithLedger(): Promise<Buffer> {
const ledger = await createLedgerInstance(true, this.logger)
return ledger.dkgBackupKeys()
}

async performRound3WithLedger(
client: RpcClient,
participantName: string,
identity: string,
round1PublicPackagesStr: string[],
round2PublicPackagesStr: string[],
round2SecretPackage: string,
): Promise<void> {
const ledger = await createLedgerInstance(true, this.logger)

const identityResponse = await client.wallet.multisig.getIdentity({ name: participantName })
const identity = identityResponse.content.identity

// Sort packages by identity
const round1PublicPackages = round1PublicPackagesStr
.map(deserializePublicPackage)
.sort((a, b) => a.identity.localeCompare(b.identity))

// Filter out packages not intended for participant and sort by sender identity
const round2CombinedPublicPackages = round2PublicPackagesStr.map(
deserializeRound2CombinedPublicPackage,
)
const round2PublicPackages = round2CombinedPublicPackages
.flatMap((combined) =>
combined.packages.filter((pkg) => pkg.recipientIdentity === identity),
)
.sort((a, b) => a.senderIdentity.localeCompare(b.senderIdentity))

// Extract raw parts from round1 and round2 public packages
const participants = []
const round1FrostPackages = []
const gskBytes = []
for (const pkg of round1PublicPackages) {
// Exclude participant's own identity and round1 public package
if (pkg.identity !== identity) {
participants.push(pkg.identity)
round1FrostPackages.push(pkg.frostPackage)
}

gskBytes.push(pkg.groupSecretKeyShardEncrypted)
): Promise<{
dkgKeys: {
publicAddress: string
viewKey: string
incomingViewKey: string
outgoingViewKey: string
proofAuthorizingKey: string
}
publicKeyPackage: Buffer
}> {
const ledger = await createLedgerInstance(true, this.logger)

const round2FrostPackages = round2PublicPackages.map((pkg) => pkg.frostPackage)

// Perform round3 with Ledger
await ledger.dkgRound3(
0,
participants,
round1FrostPackages,
round2FrostPackages,
return ledger.dkgRound3(
identity,
round1PublicPackagesStr,
round2PublicPackagesStr,
round2SecretPackage,
gskBytes,
)

// Retrieve all multisig account keys and publicKeyPackage
const dkgKeys = await ledger.dkgRetrieveKeys()

const publicKeyPackage = await ledger.dkgGetPublicPackage()

const accountImport = {
...dkgKeys,
multisigKeys: {
publicKeyPackage: publicKeyPackage.toString('hex'),
identity,
},
version: 4,
name: participantName,
spendingKey: null,
createdAt: null,
}

// Import multisig account
const response = await client.wallet.importAccount({
account: encodeAccountImport(accountImport, AccountFormat.Base64Json),
})

this.log()
this.log(
`Account ${response.content.name} imported with public address: ${dkgKeys.publicAddress}`,
)

this.log()
this.log('Creating an encrypted backup of multisig keys from your Ledger device...')
this.log()

const encryptedKeys = await ledger.dkgBackupKeys()

this.log()
this.log('Encrypted Ledger Multisig Backup:')
this.log(encryptedKeys.toString('hex'))
this.log()
this.log('Please save the encrypted keys show above.')
this.log(
'Use `ironfish wallet:multisig:ledger:restore` if you need to restore the keys to your Ledger.',
)
}
}
72 changes: 62 additions & 10 deletions ironfish-cli/src/utils/ledger.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import {
deserializePublicPackage,
deserializeRound2CombinedPublicPackage,
} from '@ironfish/rust-nodejs'
import { AccountImport, createRootLogger, Logger } from '@ironfish/sdk'
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid'
import IronfishApp, {
Expand Down Expand Up @@ -214,29 +218,77 @@ export class Ledger {
}

dkgRound3 = async (
index: number,
participants: string[],
round1PublicPackages: string[],
round2PublicPackages: string[],
identity: string,
round1PublicPackagesStr: string[],
round2PublicPackagesStr: string[],
round2SecretPackage: string,
gskBytes: string[],
): Promise<void> => {
): Promise<{
dkgKeys: {
publicAddress: string
viewKey: string
incomingViewKey: string
outgoingViewKey: string
proofAuthorizingKey: string
}
publicKeyPackage: Buffer
}> => {
if (!this.app) {
throw new Error('Connect to Ledger first')
}

// Sort packages by identity
const round1PublicPackages = round1PublicPackagesStr
.map(deserializePublicPackage)
.sort((a, b) => a.identity.localeCompare(b.identity))

// Filter out packages not intended for participant and sort by sender identity
const round2CombinedPublicPackages = round2PublicPackagesStr.map(
deserializeRound2CombinedPublicPackage,
)
const round2PublicPackages = round2CombinedPublicPackages
.flatMap((combined) =>
combined.packages.filter((pkg) => pkg.recipientIdentity === identity),
)
.sort((a, b) => a.senderIdentity.localeCompare(b.senderIdentity))

// Extract raw parts from round1 and round2 public packages
const participants = []
const round1FrostPackages = []
const gskBytes = []
for (const pkg of round1PublicPackages) {
// Exclude participant's own identity and round1 public package
if (pkg.identity !== identity) {
participants.push(pkg.identity)
round1FrostPackages.push(pkg.frostPackage)
}

gskBytes.push(pkg.groupSecretKeyShardEncrypted)
}

const round2FrostPackages = round2PublicPackages.map((pkg) => pkg.frostPackage)

this.logger.log('Please approve the request on your ledger device.')

return this.tryInstruction(
await this.tryInstruction(
this.app.dkgRound3Min(
index,
0,
participants,
round1PublicPackages,
round2PublicPackages,
round1FrostPackages,
round2FrostPackages,
round2SecretPackage,
gskBytes,
),
)

// Retrieve all multisig account keys and publicKeyPackage
const dkgKeys = await this.dkgRetrieveKeys()

const publicKeyPackage = await this.dkgGetPublicPackage()

return {
dkgKeys,
publicKeyPackage,
}
}

dkgRetrieveKeys = async (): Promise<{
Expand Down

0 comments on commit 7a3398f

Please sign in to comment.