CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-polkadot--util-crypto

A collection of useful crypto utilities for Polkadot ecosystem projects

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

signatures.mddocs/

Digital Signatures

Signing and verification functions for multiple cryptographic schemes with automatic signature format detection. Supports sr25519, ed25519, secp256k1, and Ethereum-style signatures.

Capabilities

Sr25519 Signatures

Sr25519 signing and verification with support for Schnorr signatures and VRF.

/**
 * Sign a message using sr25519
 * @param message - Message string or bytes to sign
 * @param keypair - Keypair object with publicKey and secretKey
 * @returns 64-byte signature
 */
function sr25519Sign(message: string | Uint8Array, keypair: Partial<Keypair>): Uint8Array;

/**
 * Verify sr25519 signature
 * @param message - Original message bytes
 * @param signature - 64-byte signature to verify
 * @param publicKey - 32-byte public key
 * @returns true if signature is valid
 */
function sr25519Verify(message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): boolean;

Usage Example:

import { sr25519PairFromSeed, sr25519Sign, sr25519Verify } from "@polkadot/util-crypto";

const seed = new Uint8Array(32);
const pair = sr25519PairFromSeed(seed);
const message = new TextEncoder().encode("Hello Polkadot");

// Sign message
const signature = sr25519Sign(message, pair);

// Verify signature
const isValid = sr25519Verify(message, signature, pair.publicKey);
console.log("Signature valid:", isValid);

Sr25519 VRF (Verifiable Random Functions)

VRF signing and verification for randomness generation with proof.

/**
 * Generate VRF signature and proof
 * @param secretKey - 64-byte secret key
 * @param context - Context bytes for VRF
 * @param message - Message to sign
 * @param extra - Optional extra randomness
 * @returns VRF signature and proof
 */
function sr25519VrfSign(secretKey: Uint8Array, context: Uint8Array, message: Uint8Array, extra?: Uint8Array): Uint8Array;

/**
 * Verify VRF signature and proof
 * @param publicKey - 32-byte public key
 * @param context - Context bytes for VRF
 * @param message - Original message
 * @param proof - VRF proof to verify
 * @param extra - Optional extra randomness
 * @returns true if VRF proof is valid
 */
function sr25519VrfVerify(publicKey: Uint8Array, context: Uint8Array, message: Uint8Array, proof: Uint8Array, extra?: Uint8Array): boolean;

Ed25519 Signatures

Ed25519 signing and verification with deterministic signatures.

/**
 * Sign a message using ed25519
 * @param publicKey - 32-byte public key
 * @param secretKey - 32 or 64-byte secret key
 * @param message - Message bytes to sign
 * @returns 64-byte signature
 */
function ed25519Sign(publicKey: Uint8Array, secretKey: Uint8Array, message: Uint8Array): Uint8Array;

/**
 * Verify ed25519 signature
 * @param message - Original message bytes
 * @param signature - 64-byte signature to verify
 * @param publicKey - 32-byte public key
 * @returns true if signature is valid
 */
function ed25519Verify(message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): boolean;

Usage Example:

import { ed25519PairFromSeed, ed25519Sign, ed25519Verify } from "@polkadot/util-crypto";

const seed = new Uint8Array(32);
const pair = ed25519PairFromSeed(seed);
const message = new TextEncoder().encode("Hello World");

// Sign message
const signature = ed25519Sign(pair.publicKey, pair.secretKey, message);

// Verify signature
const isValid = ed25519Verify(message, signature, pair.publicKey);

Secp256k1 Signatures

Secp256k1 signing, verification, and public key recovery for Ethereum compatibility.

/**
 * Sign message hash using secp256k1
 * @param msgHash - 32-byte message hash
 * @param secretKey - 32-byte private key
 * @returns Signature with recovery info
 */
function secp256k1Sign(msgHash: Uint8Array, secretKey: Uint8Array): Uint8Array;

/**
 * Verify secp256k1 signature
 * @param msgHash - 32-byte message hash
 * @param signature - Signature bytes
 * @param publicKey - Public key for verification
 * @returns true if signature is valid
 */
function secp256k1Verify(msgHash: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): boolean;

/**
 * Recover public key from signature
 * @param msgHash - 32-byte message hash
 * @param signature - Signature bytes
 * @param recovery - Recovery parameter (0-3)
 * @returns Recovered public key
 */
function secp256k1Recover(msgHash: Uint8Array, signature: Uint8Array, recovery: number): Uint8Array;

/**
 * Compress secp256k1 public key from uncompressed (65 bytes) to compressed (33 bytes)
 * @param publicKey - Public key to compress (33 or 65 bytes)
 * @param onlyJs - Force JavaScript implementation
 * @returns Compressed public key (33 bytes)
 */
function secp256k1Compress(publicKey: Uint8Array, onlyJs?: boolean): Uint8Array;

/**
 * Expand secp256k1 public key from compressed (33 bytes) to uncompressed coordinates (64 bytes)
 * @param publicKey - Public key to expand (33 or 65 bytes)
 * @param onlyJs - Force JavaScript implementation
 * @returns Uncompressed public key coordinates (64 bytes, without 0x04 prefix)
 */
function secp256k1Expand(publicKey: Uint8Array, onlyJs?: boolean): Uint8Array;

/**
 * Add a tweak to a secp256k1 private key
 * @param seckey - Private key (32 bytes)
 * @param tweak - Tweak value (32 bytes)
 * @param onlyBn - Force BN.js implementation
 * @returns Modified private key (32 bytes)
 */
function secp256k1PrivateKeyTweakAdd(seckey: Uint8Array, tweak: Uint8Array, onlyBn?: boolean): Uint8Array;

Usage Example:

import { 
  secp256k1PairFromSeed, 
  secp256k1Sign, 
  secp256k1Verify,
  secp256k1Recover,
  secp256k1Compress,
  secp256k1Expand,
  secp256k1PrivateKeyTweakAdd,
  keccak256AsU8a 
} from "@polkadot/util-crypto";

const seed = new Uint8Array(32);
const pair = secp256k1PairFromSeed(seed);
const message = new TextEncoder().encode("Hello Ethereum");
const messageHash = keccak256AsU8a(message);

// Sign message hash
const signature = secp256k1Sign(messageHash, pair.secretKey);

// Verify signature
const isValid = secp256k1Verify(messageHash, signature, pair.publicKey);

// Recover public key
const recoveredKey = secp256k1Recover(messageHash, signature, 0);

// Compress public key
const compressedKey = secp256k1Compress(pair.publicKey);

// Expand compressed key to coordinates  
const expandedKey = secp256k1Expand(compressedKey);

// Add tweak to private key
const tweak = new Uint8Array(32);
const tweakedPrivateKey = secp256k1PrivateKeyTweakAdd(pair.secretKey, tweak);

Universal Signature Verification

Automatic detection and verification of different signature formats.

/**
 * Verify signature with automatic format detection
 * @param message - Original message bytes
 * @param signature - Signature in any supported format
 * @param addressOrPublicKey - Address string or public key bytes
 * @returns Verification result with details
 */
function signatureVerify(
  message: Uint8Array, 
  signature: Uint8Array | string, 
  addressOrPublicKey: string | Uint8Array
): VerifyResult;

interface VerifyResult {
  /** The detected crypto interface, or 'none' if not detected */
  crypto: 'none' | KeypairType;
  /** The validity for this result, false if invalid */
  isValid: boolean;
  /** Flag to indicate if the passed data was wrapped in <Bytes>...</Bytes> */
  isWrapped: boolean;
  /** The extracted publicKey */
  publicKey: Uint8Array;
}

Usage Example:

import { signatureVerify } from "@polkadot/util-crypto";

const message = new TextEncoder().encode("Test message");
const signature = "0x..."; // Any signature format
const address = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";

const result = signatureVerify(message, signature, address);

console.log("Crypto scheme:", result.crypto);
console.log("Is valid:", result.isValid);
console.log("Public key:", result.publicKey);

Key Derivation and Signing

Sr25519 Key Derivation

Hard and soft key derivation for hierarchical signing.

/**
 * Derive sr25519 public key (soft derivation)
 * @param publicKey - Parent public key
 * @param chainCode - Chain code for derivation
 * @returns Derived public key
 */
function sr25519DerivePublic(publicKey: Uint8Array, chainCode: Uint8Array): Uint8Array;

/**
 * Derive sr25519 key pair (soft derivation)
 * @param pair - Parent key pair
 * @param chainCode - Chain code for derivation
 * @returns Derived key pair
 */
function sr25519DeriveSoft(pair: Keypair, chainCode: Uint8Array): Keypair;

/**
 * Hard derivation for sr25519
 * @param seed - Parent seed
 * @param chainCode - Chain code for derivation
 * @returns Derived seed
 */
function sr25519DeriveHard(seed: Uint8Array, chainCode: Uint8Array): Uint8Array;

/**
 * Sr25519 Diffie-Hellman agreement
 * @param publicKey - Other party's public key
 * @param secretKey - Own secret key
 * @returns Shared secret
 */
function sr25519Agreement(publicKey: Uint8Array, secretKey: Uint8Array): Uint8Array;

Ed25519 Key Derivation

/**
 * Hard derivation for ed25519
 * @param seed - Parent seed
 * @param chainCode - Chain code for derivation
 * @returns Derived seed
 */
function ed25519DeriveHard(seed: Uint8Array, chainCode: Uint8Array): Uint8Array;

Signature Format Notes

  • Sr25519: 64-byte signatures, supports batch verification
  • Ed25519: 64-byte deterministic signatures, very fast verification
  • Secp256k1: Variable length with recovery, Ethereum-compatible
  • Multi-format: signatureVerify handles automatic detection

Security Considerations

  • Always verify signatures before trusting signed data
  • Use appropriate hash functions for each signature scheme
  • Be careful with signature malleability in secp256k1
  • VRF provides both signature and verifiable randomness
  • Store private keys securely and never reuse nonces

Install with Tessl CLI

npx tessl i tessl/npm-polkadot--util-crypto

docs

address.md

base-encoding.md

crypto-init.md

ethereum.md

hashing.md

index.md

json-encryption.md

key-derivation-pbkdf.md

key-derivation.md

keypairs.md

mnemonic.md

random.md

signatures.md

tile.json