Una guía sobre firmas en Starknet
Resumen
Este artículo describe el proceso de firmar y verificar una firma en Starknet. Comienza introduciendo la Abstracción de Cuentas y cómo modifica la verificación de firmas en comparación con blockchains tradicionales como Ethereum. Luego proporciona ejemplos de código completos en TypeScript y Go para firmar un mensaje y verificar una firma utilizando dos métodos disponibles en Starknet: usando la clave pública del usuario y usando la dirección de cuenta del usuario.
Esta publicación se basa en el artículo publicado originalmente en dev.to por Bastien Faivre.
Abstracción de Cuentas
La Abstracción de Cuentas es una característica central de Starknet que cambia fundamentalmente cómo funcionan las cuentas en comparación con cadenas como Ethereum. En Starknet, las cuentas son contratos inteligentes que pueden implementar lógica arbitraria para la validación de transacciones. Esto significa que diferentes contratos de cuenta pueden implementar diferentes métodos de verificación de firmas. Aunque la mayoría de las cuentas de Starknet siguen un estándar para la verificación de firmas, es esencial entender que el contrato de cuenta en sí define la lógica de validación.
Firmar un mensaje
Al firmar un mensaje en Starknet, primero necesitas obtener una clave privada y su cuenta correspondiente. Hay diferentes formas de hacerlo dependiendo del lenguaje y la biblioteca utilizada. En TypeScript, puedes usar una biblioteca como `starknet` o `starknet.js`. En Go, puedes usar la biblioteca `starknet.go` desarrollada por Nethermind.
Aquí hay un ejemplo de firmar un mensaje en TypeScript:
import { Signature, constants, ec, hash, stark } from "starknet";
// Generate a private key (usually you would use a secure storage method)
const privateKey = stark.randomAddress();
// Get the public key from the private key
const publicKey = ec.starkCurve.getStarkKey(privateKey);
// The message to sign
const message = "Hello, Starknet!";
// Hash the message
const messageHash = hash.starknetKeccak(message);
// Sign the message hash
const signature = ec.starkCurve.sign(messageHash, privateKey);
// The signature is an array of two elements: r and s
console.log("Signature:", signature);Verificar una firma usando la clave pública
Verificar una firma usando la clave pública es sencillo en la mayoría de las plataformas blockchain. En Starknet, puedes verificar una firma usando la clave pública del firmante con código como este:
// Verify the signature using the public key
const isValid = ec.starkCurve.verify(messageHash, signature, publicKey);
console.log("Is the signature valid?", isValid);Verificar una firma usando la dirección de cuenta
En Starknet, debido a la Abstracción de Cuentas, a veces necesitas verificar una firma usando la dirección de cuenta del firmante en lugar de su clave pública. Esto requiere llamar al método `is_valid_signature` en el contrato de cuenta. (Nota: El artículo original menciona `isPrefixedMessageValid`, pero los contratos de cuenta estándar a menudo usan `is_valid_signature`. El método exacto puede variar.)
import { Account, Provider, constants, stark, Signature } from "starknet";
// Initialize a provider to connect to Starknet
const provider = new Provider({ sequencer: { network: constants.NetworkName.SN_MAIN } }); // Or your desired network
// Assume signerAddress, pkForSigner, messageHash and signature are defined
// const signerAddress = "0x123...";
// const pkForSigner = "0x456..."; // or connect with a wallet signer
// const messageHash = "0x789...";
// const signature: Signature = ["0xabc...", "0xdef..."];
async function verifySignatureUsingAccount(signerAddress: string, pkForSigner: string, msgHash: string, sig: Signature) {
const account = new Account(provider, signerAddress, pkForSigner);
try {
const result = await account.call("is_valid_signature", [
msgHash, // hash
sig.length.toString(), // signature_len
...sig // signature (r, s)
]);
// For Ready Wallet/Braavos standard accounts, a single felt "0x1" (VALID_SIGNATURE) is returned on success.
// Cairo0 contracts might return an array if the function has multiple return values.
// Check the specific account contract for exact return format if issues arise.
const isValid = Array.isArray(result) ? result[0] === "0x1" : result.result[0] === "0x1";
console.log("Is the signature valid (using account)?", isValid);
return isValid;
} catch (error) {
console.error("Error verifying signature using account:", error);
return false;
}
}
// Example usage (ensure variables are set)
// verifySignatureUsingAccount(signerAddress, pkForSigner, messageHash, signature);Trabajar con una billetera (Ready Wallet, Braavos, etc.)
Al trabajar con una billetera como Ready Wallet o Braavos, típicamente no tendrás acceso directo a la clave privada del usuario. En su lugar, necesitarás usar la interfaz de la billetera para solicitar al usuario que firme un mensaje.
// This is a conceptual example, actual implementation depends on the wallet connector library (e.g., starknet-react, get-starknet)
async function signMessageWithWallet(wallet: any, message: string) { // Use specific wallet type from your library
try {
// The method might be `signMessage`, `personalSign`, or similar
// The exact structure for `typedData` or `message` depends on the wallet and standard (e.g., EIP-712 for Starknet)
const signature = await wallet.account.signMessage({ message }); // Example structure, might need TypedData for some wallets
console.log("Signature from wallet:", signature);
return signature;
} catch (error) {
console.error("Error signing message with wallet:", error);
return null;
}
}Conclusión
El modelo de Abstracción de Cuentas de Starknet proporciona flexibilidad para la verificación de firmas pero requiere entender las diferencias del modelo tradicional de firmas de blockchain. Siguiendo los ejemplos proporcionados, deberías poder firmar mensajes y verificar firmas efectivamente en tus aplicaciones de Starknet. Recuerda que los detalles específicos de implementación pueden variar dependiendo del proveedor de billetera y el contrato de cuenta que se esté usando. Siempre consulta la documentación específica de la billetera o contrato de cuenta con el que estés trabajando.
Para más información, consulta el artículo original en dev.to por Bastien Faivre.