Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ton-blockchain/acton/llms.txt

Use this file to discover all available pages before exploring further.

The @acton/crypto module provides host-assisted cryptographic primitives for use inside Acton scripts and tests. It covers the full lifecycle of working with Ed25519 keys on TON: generating a BIP39-compatible mnemonic, deriving a key pair from that mnemonic or from a raw 256-bit seed, signing cells and raw hashes, and generating both cryptographically secure and deterministic random bytes. Because these operations run on the Acton host, they can use the full standard-library cryptography of the underlying Rust runtime rather than being limited to TVM instructions.
@acton/crypto is a host-side module. It cannot be imported in contract source files (contracts/). For on-chain signature verification, use the Tolk stdlib function isSignatureValid instead.

Import

import "@acton/crypto"

Types

KeyPair

struct KeyPair {
    privateKey: int   // 256-bit Ed25519 seed
    publicKey: int    // 256-bit Ed25519 public key
}
Both fields are plain int for direct compatibility with TVM builtins like isSignatureValid.

Mnemonic

type Mnemonic = array<string>
An array of 24 BIP39 English words, as returned by crypto.createMnemonic().

Functions

Mnemonic Generation

fun crypto.createMnemonic(): Mnemonic
Generates a new random BIP39-compatible 24-word mnemonic phrase. Each call produces a fresh, cryptographically random mnemonic.
val words = crypto.createMnemonic();
// words[0] .. words[23] — 24 BIP39 English words

Key Derivation from Mnemonic

fun Mnemonic.toKeyPair(self): KeyPair
Derives an Ed25519 key pair from a mnemonic phrase. The input must be a 24-word BIP39 mnemonic, for example as returned by crypto.createMnemonic().
val words = crypto.createMnemonic();
val kp = words.toKeyPair();
// kp.privateKey — 32-byte Ed25519 seed as int
// kp.publicKey  — 32-byte Ed25519 public key as int

Key Generation Without Mnemonic

fun crypto.generateKeyPair(): KeyPair
Generates a random Ed25519 key pair without creating a mnemonic. Significantly faster than createMnemonic + toKeyPair because it skips BIP39 word generation. Use when you do not need to store or recover the mnemonic.
val kp = crypto.generateKeyPair();

Key Derivation from Seed

fun crypto.seedToKeyPair(seed: uint256): KeyPair
Derives a deterministic Ed25519 key pair from a 256-bit integer seed. The same seed always produces the same key pair.
val kp = crypto.seedToKeyPair(mySeed);

Signing

// Sign a cell — hashes the cell then signs the hash
fun crypto.sign(privateKey: int, data: cell): slice

// Sign a raw 256-bit hash directly
fun crypto.rawSign(privateKey: int, data: int): slice
Both functions return a 512-bit (64-byte) Ed25519 signature as a slice.
val kp = crypto.generateKeyPair();

// High-level: hash + sign in one step
val signature = crypto.sign(kp.privateKey, myMessageCell);

// Low-level: sign an already-computed hash
val hash = myMessageCell.hash();
val signature = crypto.rawSign(kp.privateKey, hash);
The resulting signature can be verified on-chain with isSignatureValid(hash, signature, kp.publicKey).

Secure Random Bytes

fun crypto.getSecureRandomBytes(bytesNum: uint16): slice
Generates bytesNum cryptographically secure random bytes. The accepted range is 1..127. Values of 0 or >= 128 will fail.
val randomBytes = crypto.getSecureRandomBytes(32);

Fast Deterministic Random Bytes

fun crypto.getFastRandomBytes(bytesNum: uint16, seed: int? = null): slice
Generates bytesNum deterministic random bytes using a seed. The maximum is 127 bytes.
  • When seed is provided, the output is fully reproducible regardless of time.
  • When seed is omitted, blockchain.now() is used as the seed at the moment of the call.
The same seed always produces the same bytes, which makes this function ideal for reproducible test scenarios.
// Fully deterministic — always the same bytes
val bytes = crypto.getFastRandomBytes(16, 42);

// Time-locked — same within a fixed emulation time
testing.setNow(1700004321);
val a = crypto.getFastRandomBytes(16);
val b = crypto.getFastRandomBytes(16);
// a == b because both calls used the same blockchain.now()

Complete Examples

Deploy Script With Wallet Signing

import "@acton/crypto"
import "@acton/emulation/scripts"
import "@acton/emulation/network"
import "@acton/io"

fun main() {
    // Generate a fresh key pair for a new wallet
    val words = crypto.createMnemonic();
    val kp = words.toKeyPair();

    println("New public key: 0x{:x}", kp.publicKey);
    println("Mnemonic: {}", words);

    // Use the key pair to sign a custom external message
    val body = MyExternalMsg { queryId: 42, action: 1 };
    val msgCell = body.toCell();
    val signature = crypto.sign(kp.privateKey, msgCell);

    val externalMsg = net.createExternalMessage(contractAddress, SignedBody {
        signature: signature as bits512,
        body: body,
    });

    val result = net.sendExternal(externalMsg);
    expect(result).toBeAccepted();
}

Test With Deterministic Keys

import "@acton/crypto"
import "@acton/testing/expect"
import "@acton/emulation/testing"
import "@acton/emulation/network"

get fun `test signature validation`() {
    // Deterministic key pair from a fixed seed — same every run
    val kp = crypto.seedToKeyPair(0xDEADBEEF);

    val deployer = testing.treasury("deployer");

    // Deploy a contract that stores kp.publicKey
    val wallet = MyWallet.fromStorage({ publicKey: kp.publicKey });
    net.send(deployer.address, wallet.deploy(deployer.address, ton("0.1")));

    // Build and sign an external message
    val body = WalletAction { seqno: 1, action: Transfer { to: deployer.address, value: ton("0.01") } };
    val signature = crypto.sign(kp.privateKey, body.toCell());

    val msg = net.createExternalMessage(wallet.address, SignedRequest {
        signature: signature as bits512,
        body: body,
    });

    val result = net.sendExternal(msg);
    expect(result).toBeAccepted();
}

Secure Random in a Script

import "@acton/crypto"
import "@acton/io"

fun main() {
    // Generate a 32-byte random salt for a deployment
    val salt = crypto.getSecureRandomBytes(32);
    println("Salt for deployment: 0x{:x}", salt.hash());
}

Build docs developers (and LLMs) love