How to sign data with @dfinity/agent or @dfinity/identity?

Looking for a way to verify ownership of a principal off-chain.

In Metamask this can be done with eth_sign (or other methods). Once the message is signed you can do secp256k1.recover to verify ownership of a public key (and the address).
Docs: Signing Data | MetaMask Docs

With ethers it can be done with signMessage and recover the public key in a similar way.
Docs: Signing Messages — ethers.js 4.0.0 documentation

Do either @dfinity/agent or @dfinity/identity allow signing arbitrary messages?

Other suggestions welcome.

Figured it out. Here’s a working nodejs snippet.
NOTE: requires the tweetnacl library (unless there’s a way to access this functions through @dfinity/identity that I’ve missed)

const fs = require('fs/promises')
const pem = require('pem-file')
const os = require('os')

const { Ed25519KeyIdentity } = require('@dfinity/identity')
const { sign } = require('tweetnacl')

const getDefaultIdentity = async () => {
   const pemFile = await fs.readFile(os.homedir() + '/.config/dfx/identity/default/identity.pem')
   const buffer = pem.decode(pemFile)
   const secretKey = Buffer.concat([buffer.subarray(16, 48), buffer.subarray(53, 85)])
   return Ed25519KeyIdentity.fromSecretKey(secretKey)

;(async () => {

   const identity = await getDefaultIdentity()
   const message = Buffer.from('message')
   const messageSigned = await identity.sign(message).then(Buffer.from)
   console.log('signature', messageSigned.toString('hex'))

   const publicKeyRaw = Buffer.from(identity.getPublicKey().rawKey)
   const verified = sign.detached.verify(message, messageSigned, publicKeyRaw)
   console.log('verified', verified)
1 Like

Note that you often work with delegated session keys on the IC where the principal, i.e. the persistent identity, is related to the key (often a canister sig public key) that issued/signed the delegation.

…so this means a signature done in this way won’t work? Maybe specifically for II identities? Is there a way to ask for II to sign?

This works for identities/principals that are directly derived from a key pair (as in the example code above) but doesn’t work for delegated identities like Internet Identity. My note was just, that if you have a session key with a delegation then you need to verify the delegation as well and the identity needs to be derived from the delegation and not from the session key.

No, currently you can’t ask the Internet Identity canister to sign arbitrary messages. It only signs delegations.

1 Like

I’m currently looking for a way to ask an IID to sign some data, and then be able to later verify this signature against a IID / Principal.
I found this method :

How could I then verify this signature ?

Thanks in advance