Search code examples
javascriptjavablockchainsolana

How to verify a signature from the Phantom wallet?


I am able to sign a message on the client side using something like this:

const encodedMessage = new TextEncoder().encode("some message");
const signedMessage = await provider.signMessage(encodedMessage, "utf8");

Now I want to verify the signature on the back end side using Kotlin (or Java).

Problem:

  1. I cannot find the information about the algorithm that is used for signing messages in the documentation.
  2. It seems like there are no Java/Kotlin libraries that work with Phantom and Solana (found a few which are not updated for a year).

Question: How can I verify a signature from the Phantom wallet using Java? Or generally how can I do that in any language? (I will port it to Java then).


Solution

  • The easiest way to do it in Java or Kotlin is using sol4k.

    First, add it to your project (Gradle as an example):

    implementation 'org.sol4k:sol4k:0.3.2'
    

    Then call it from your Java code:

    import org.sol4k.Base58;
    import org.sol4k.PublicKey;
    // ...
    boolean verifySignature(String signature, String walletAddress) {
        String message = "signing message";
        byte[] messageBytes = message.getBytes();
        PublicKey publicKey = new PublicKey(walletAddress);
        byte[] signatureBytes = Base58.decode(signature);
        return publicKey.verify(signatureBytes, messageBytes);
    }
    

    Here, signature and walletAddress are Base58 encoded strings.

    Frontend example how to get wallet address and the signature (Phantom docs):

    const provider = window.phantom.solana;
    const encodedMessage = new TextEncoder().encode('signing message');
    const signedMessage = await provider.signMessage(encodedMessage, "utf8");
    const base58 = await import("bs58");
    const walletAddress = provider.publicKey.toString();
    const signature = base58.encode(signedMessage.signature);
    

    Here is a blogpost on the subject.