Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to verify message signed by sol-wallet-adapter

Having created a signed message I'm unsure how to use the resulting signature to verify the message using the publicKey.

My use case is, I'm wanting to use a Solana Wallet to login to an API server with a pattern like:

  1. GET message: String (from API server)
  2. sign message with privateKey
  3. POST signature (to API server)
  4. verify signature with stored publicKey

I've attempted to use nodeJS crypto.verify to decode the signed message on the API side but am a bit out of my depth digging into Buffers and elliptic curves:

// Front-end code
const toHexString = (buffer: Buffer) =>
  buffer.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");

const data = new TextEncoder().encode('message to verify');
const signed = await wallet.sign(data, "hex");
await setLogin({ // sends API post call to backend
  variables: {
    publicAddress: walletPublicKey,
    signature: toHexString(signed.signature),
  },
});

// Current WIP for backend code
const ALGORITHM = "ed25519";
const fromHexString = (hexString) =>
  new Uint8Array(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
const signature = fromHexString(args.signature);
const nonceUint8 = new TextEncoder().encode('message to verify');
const verified = crypto.verify(
  ALGORITHM,
  nonceUint8,
  `-----BEGIN PUBLIC KEY-----\n${user.publicAddress}\n-----END PUBLIC KEY-----`,
  signature
);
console.log("isVerified: ", verified);

I'm pretty sure I'm going about this the wrong way and there must be an obvious method I'm missing.

As the space matures I expect a verify function or lib will appear to to consume the output of const signed = await wallet.sign(data, "hex");

Something like:

import { VerifyMessage } from '@solana/web3.js';

const verified = VerifyMessage(message, publicKey, signature, 'hex');

But after 3 days of pushing hard I'm starting to hit my limits and my brain is failing. Any help or direction where to look much appreciated 🙏

like image 313
harkl Avatar asked Jul 08 '21 00:07

harkl


Video Answer


3 Answers

Solved with input from the fantastic Project Serum discord devs. High level solution is to use libs that are also used in the sol-wallet-adapter repo, namely tweetnacl and bs58:

const signatureUint8 = base58.decode(args.signature);
const nonceUint8 = new TextEncoder().encode(user?.nonce);
const pubKeyUint8 = base58.decode(user?.publicAddress);

nacl.sign.detached.verify(nonceUint8, signatureUint8, pubKeyUint8)
// true
like image 79
harkl Avatar answered Oct 17 '22 03:10

harkl


I recommend staying in solana-labs trail and use tweetnacl

spl-token-wallet (sollet.io) signs an arbitrary message with nacl.sign.detached(message, this.account.secretKey)

https://github.com/project-serum/spl-token-wallet/blob/9c9f1d48a589218ffe0f54b7d2f3fb29d84f7b78/src/utils/walletProvider/localStorage.js#L65-L67

on the other end, verify is done with nacl.sign.detached.verify

in @solana/web3.js https://github.com/solana-labs/solana/blob/master/web3.js/src/transaction.ts#L560

Use nacl.sign.detached.verify in your backend and you should be good. I also recommend avoiding any data format manipulation, I am not sure what you were trying to do but if you do verify that each step is correct.

like image 32
Arowana Avatar answered Oct 17 '22 02:10

Arowana


For iOS, solana.request will cause error. Use solana.signMessage and base58 encode the signature.

var _signature = ''; 
try {
  signedMessage = await window.solana.request({
    method: "signMessage",
    params: {
      message: encodedMessage
    },
  }); 
  _signature = signedMessage.signature; 
} catch (e) { 
  try {
    signedMessage = await window.solana.signMessage(encodedMessage); 
    _signature = base58.encode(signedMessage.signature); 
  } catch (e1) {
    alert(e1.message);
  }
}
// 
try {
  signIn('credentials',
    {
      publicKey: signedMessage.publicKey,
      signature: _signature,
      callbackUrl: `${window.location.origin}/`
    }
  )
} catch (e) {
  alert(e.message);
}
like image 1
OO Q Avatar answered Oct 17 '22 03:10

OO Q