Skip to content

Sign

Signs a felt message using the account's private key from the keystore. The signature is compatible with Starknet's signature verification scheme and returns two felt components (r, s).

Method Signature

func (account *Account) Sign(ctx context.Context, msg *felt.Felt) ([]*felt.Felt, error)

Source: signature.go

Parameters

  • ctx - Context for cancellation and timeout
  • msg - Message to sign as felt

Returns

  • []*felt.Felt - Signature as array [r, s]
  • error - Error if signing fails

Usage Example

package main
 
import (
	"context"
	"fmt"
	"log"
	"math/big"
	"os"
 
	"github.com/NethermindEth/juno/core/felt"
	"github.com/NethermindEth/starknet.go/account"
	"github.com/NethermindEth/starknet.go/curve"
	"github.com/NethermindEth/starknet.go/rpc"
	"github.com/NethermindEth/starknet.go/utils"
	"github.com/joho/godotenv"
)
 
func main() {
	ctx := context.Background()
 
	if err := godotenv.Load(); err != nil {
		log.Fatal("Failed to load .env file:", err)
	}
 
	rpcURL := os.Getenv("STARKNET_RPC_URL")
	if rpcURL == "" {
		log.Fatal("STARKNET_RPC_URL not set in .env file")
	}
 
	provider, err := rpc.NewProvider(ctx, rpcURL)
	if err != nil {
		log.Fatal("Failed to create provider:", err)
	}
 
	accountAddress := os.Getenv("ACCOUNT_ADDRESS")
	publicKey := os.Getenv("ACCOUNT_PUBLIC_KEY")
	privateKey := os.Getenv("ACCOUNT_PRIVATE_KEY")
 
	if accountAddress == "" || publicKey == "" || privateKey == "" {
		log.Fatal("ACCOUNT_ADDRESS, ACCOUNT_PUBLIC_KEY, or ACCOUNT_PRIVATE_KEY not set")
	}
 
	ks := account.NewMemKeystore()
	privKeyBI, ok := new(big.Int).SetString(privateKey, 0)
	if !ok {
		log.Fatal("Failed to parse private key")
	}
	ks.Put(publicKey, privKeyBI)
 
	accountAddressFelt, err := utils.HexToFelt(accountAddress)
	if err != nil {
		log.Fatal("Failed to parse account address:", err)
	}
 
	accnt, err := account.NewAccount(
		provider,
		accountAddressFelt,
		publicKey,
		ks,
		account.CairoV2,
	)
	if err != nil {
		log.Fatal("Failed to create account:", err)
	}
 
	message := new(felt.Felt).SetUint64(12345)
	fmt.Printf("Message to sign: %s\n", message.String())
	fmt.Printf("Message (decimal): %d\n", message.Uint64())
 
	signature, err := accnt.Sign(ctx, message)
	if err != nil {
		log.Fatal("Failed to sign message:", err)
	}
 
	fmt.Printf("Signature components:\n")
	fmt.Printf("  r: %s\n", signature[0].String())
	fmt.Printf("  s: %s\n", signature[1].String())
 
	pubKeyFelt, _ := utils.HexToFelt(publicKey)
	isValid, err := curve.Verify(message.BigInt(new(big.Int)), signature[0].BigInt(new(big.Int)), signature[1].BigInt(new(big.Int)), pubKeyFelt.BigInt(new(big.Int)))
	if err != nil {
		log.Fatal("Failed to verify signature:", err)
	}
	fmt.Printf("Signature verification: %v\n", isValid)
 
	messageStr := "Hello Starknet!"
	fmt.Printf("Original message: \"%s\"\n", messageStr)
 
	messageFelt := new(felt.Felt).SetBigInt(utils.UTF8StrToBig(messageStr))
	fmt.Printf("Message as felt: %s\n", messageFelt.String())
 
	signature2, err := accnt.Sign(ctx, messageFelt)
	if err != nil {
		log.Fatal("Failed to sign message:", err)
	}
 
	fmt.Printf("Signature:\n")
	fmt.Printf("  r: %s\n", signature2[0].String())
	fmt.Printf("  s: %s\n", signature2[1].String())
 
	isValid2, err := curve.Verify(messageFelt.BigInt(new(big.Int)), signature2[0].BigInt(new(big.Int)), signature2[1].BigInt(new(big.Int)), pubKeyFelt.BigInt(new(big.Int)))
	if err != nil {
		log.Fatal("Failed to verify signature:", err)
	}
	fmt.Printf("Signature valid: %v\n", isValid2)
 
	txHash, _ := utils.HexToFelt("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")
	fmt.Printf("Transaction hash: %s\n", txHash.String())
 
	signature3, err := accnt.Sign(ctx, txHash)
	if err != nil {
		log.Fatal("Failed to sign transaction hash:", err)
	}
 
	fmt.Printf("Transaction signature:\n")
	fmt.Printf("  r: %s\n", signature3[0].String())
	fmt.Printf("  s: %s\n", signature3[1].String())
 
	isValid3, err := curve.Verify(txHash.BigInt(new(big.Int)), signature3[0].BigInt(new(big.Int)), signature3[1].BigInt(new(big.Int)), pubKeyFelt.BigInt(new(big.Int)))
	if err != nil {
		log.Fatal("Failed to verify signature:", err)
	}
	fmt.Printf("Signature valid: %v\n", isValid3)
}

Error Handling

signature, err := acc.Sign(ctx, message)
if err != nil {
	// Handle errors like:
	// - Key not found in keystore
	// - Signing failure
	return err
}

Common Use Cases

  • Sign arbitrary messages for off-chain verification
  • Create signatures for custom authentication schemes
  • Sign data for cross-chain message passing
  • Generate proofs of ownership or authorization
  • Low-level signing operations (most users should use transaction-specific signing methods)