From 2f497d3902865c9b3c301a46ee41d29cb9388bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 4 Apr 2024 16:48:09 +0300 Subject: [PATCH] Signing objects, verifying signatures. --- .../sdk-js/sdk-js-cookbook-v13.md | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/docs/sdk-and-tools/sdk-js/sdk-js-cookbook-v13.md b/docs/sdk-and-tools/sdk-js/sdk-js-cookbook-v13.md index 38fb41ceb..b31110319 100644 --- a/docs/sdk-and-tools/sdk-js/sdk-js-cookbook-v13.md +++ b/docs/sdk-and-tools/sdk-js/sdk-js-cookbook-v13.md @@ -928,6 +928,112 @@ const encoded = codec.encodeNested(paymentStruct); console.log(encoded.toString("hex")); ``` +## Signing objects + +:::note +For **dApps**, use the available **[signing providers](/sdk-and-tools/sdk-js/sdk-js-signing-providers)** instead. +::: + +Creating a `UserSigner` from a JSON wallet: + +``` +import { UserSigner } from "@multiversx/sdk-wallet"; +import { promises } from "fs"; + +const fileContent = await promises.readFile("../testwallets/alice.json", { encoding: "utf8" }); +const walletObject = JSON.parse(fileContent); +let signer = UserSigner.fromWallet(walletObject, "password"); +``` + +Creating a `UserSigner` from a PEM file: + +``` +const pemText = await promises.readFile("../testwallets/alice.pem", { encoding: "utf8" }); +signer = UserSigner.fromPem(pemText); +``` + +Signing a transaction (as we've seen [before](#signing-a-transaction)): + +``` +import { Transaction, TransactionComputer } from "@multiversx/sdk-core"; + +const transaction = new Transaction({ + nonce: 91, + sender: "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + receiver: "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", + value: 1000000000000000000n, + gasLimit: 50000n, + chainID: "D" +}); + +const transactionComputer = new TransactionComputer() +let serializedTransaction = transactionComputer.computeBytesForSigning(transaction); +transaction.signature = await signer.sign(serializedTransaction); + +console.log("Signature", Buffer.from(transaction.signature).toString("hex")); +``` + +Signing an arbitrary message: + +``` +import { Message, MessageComputer } from "@multiversx/sdk-core"; + +let message = new Message({ + data: Buffer.from("hello") +}); + +const messageComputer = new MessageComputer(); +let serializedMessage = messageComputer.computeBytesForSigning(message); +message.signature = await signer.sign(serializedMessage); + +console.log("Signature", Buffer.from(message.signature).toString("hex")); +``` + +## Verifying signatures + +Creating a `UserVerifier`: + +``` +import { UserVerifier } from "@multiversx/sdk-wallet"; + +const aliceVerifier = UserVerifier.fromAddress(addressOfAlice); +const bobVerifier = UserVerifier.fromAddress(addressOfBob); +``` + +Verifying a signature: + +``` +serializedTransaction = transactionComputer.computeBytesForSigning(transaction); +serializedMessage = messageComputer.computeBytesForSigning(message); + +console.log("Is signature of Alice?", aliceVerifier.verify(serializedTransaction, transaction.signature)); +console.log("Is signature of Alice?", aliceVerifier.verify(serializedMessage, message.signature)); +console.log("Is signature of Bob?", bobVerifier.verify(serializedTransaction, transaction.signature)); +console.log("Is signature of Bob?", bobVerifier.verify(serializedMessage, message.signature)); +``` + +### Handling messages over boundaries + +Generally speaking, signed [`Message`](https://multiversx.github.io/mx-sdk-js-core/v13/classes/Message.html) objects are meant to be sent to a remote party (e.g. a service), which can then verify the signature. + +In order to prepare a message for transmission, you can use the [`MessageComputer.packMessage()`](https://multiversx.github.io/mx-sdk-js-core/v13/classes/MessageComputer.html#packMessage) utility method: + +``` +const packedMessage = messageComputer.packMessage(message); + +console.log("Packed message", packedMessage); +``` + +Then, on the receiving side, you can use [`MessageComputer.unpackMessage()`](https://multiversx.github.io/mx-sdk-js-core/v13/classes/MessageComputer.html#unpackMessage) to reconstruct the message, prior verification: + +``` +const unpackedMessage = messageComputer.unpackMessage(packedMessage); +const serializedUnpackedMessage = messageComputer.computeBytesForVerifying(unpackedMessage); + +console.log("Unpacked message", unpackedMessage); +console.log("Is signature of Alice?", aliceVerifier.verify(serializedUnpackedMessage, message.signature)); +``` + :::important This page is a work in progress. Please check back later for more content. :::