WebAssembly interface layer providing high-performance cryptographic functions for blockchain applications in the Polkadot ecosystem.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Secp256k1 elliptic curve cryptography functions including key generation, signing, signature recovery, and public key compression/expansion operations. This is the same curve used by Bitcoin and Ethereum.
Generates a secp256k1 keypair from a secret key seed.
/**
* Generates secp256k1 keypair from secret key
* @param seckey - 32-byte secret key as Uint8Array
* @returns 64-byte uncompressed public key as Uint8Array
*/
function secp256k1FromSeed(seckey: Uint8Array): Uint8Array;Usage Example:
import { waitReady, secp256k1FromSeed } from "@polkadot/wasm-crypto";
await waitReady();
const secretKey = new Uint8Array(32).fill(1); // Example secret key
const publicKey = secp256k1FromSeed(secretKey);
console.log("Secret key length:", secretKey.length); // 32
console.log("Public key length:", publicKey.length); // 64 (uncompressed)Signs a message hash using secp256k1 ECDSA.
/**
* Signs a message hash using secp256k1 ECDSA
* @param msgHash - 32-byte message hash as Uint8Array
* @param seckey - 32-byte secret key as Uint8Array
* @returns 65-byte signature as Uint8Array (64-byte signature + 1-byte recovery ID)
*/
function secp256k1Sign(msgHash: Uint8Array, seckey: Uint8Array): Uint8Array;Usage Example:
import { waitReady, secp256k1FromSeed, secp256k1Sign, sha256 } from "@polkadot/wasm-crypto";
await waitReady();
const secretKey = new Uint8Array(32).fill(1);
const publicKey = secp256k1FromSeed(secretKey);
// Hash the message first
const message = new TextEncoder().encode("Hello, secp256k1!");
const messageHash = sha256(message);
const signature = secp256k1Sign(messageHash, secretKey);
console.log("Signature length:", signature.length); // 65Recovers the public key from a secp256k1 signature and message hash.
/**
* Recovers public key from secp256k1 signature
* @param msgHash - 32-byte message hash as Uint8Array
* @param sig - 64-byte signature as Uint8Array (without recovery ID)
* @param recovery - Recovery ID (0, 1, 2, or 3)
* @returns 64-byte uncompressed public key as Uint8Array
*/
function secp256k1Recover(msgHash: Uint8Array, sig: Uint8Array, recovery: number): Uint8Array;Usage Example:
import {
waitReady,
secp256k1FromSeed,
secp256k1Sign,
secp256k1Recover,
sha256
} from "@polkadot/wasm-crypto";
await waitReady();
const secretKey = new Uint8Array(32).fill(1);
const originalPublicKey = secp256k1FromSeed(secretKey);
const message = new TextEncoder().encode("Hello, secp256k1!");
const messageHash = sha256(message);
const fullSignature = secp256k1Sign(messageHash, secretKey);
const signature = fullSignature.slice(0, 64); // Remove recovery ID
const recoveryId = fullSignature[64]; // Extract recovery ID
const recoveredPublicKey = secp256k1Recover(messageHash, signature, recoveryId);
// Compare original and recovered public keys
const keysMatch = Array.from(originalPublicKey).join(',') ===
Array.from(recoveredPublicKey).join(',');
console.log("Keys match:", keysMatch); // trueCompresses a secp256k1 public key from 64 bytes to 33 bytes.
/**
* Compresses secp256k1 public key
* @param pubkey - 64-byte uncompressed public key as Uint8Array
* @returns 33-byte compressed public key as Uint8Array
*/
function secp256k1Compress(pubkey: Uint8Array): Uint8Array;Usage Example:
import { waitReady, secp256k1FromSeed, secp256k1Compress } from "@polkadot/wasm-crypto";
await waitReady();
const secretKey = new Uint8Array(32).fill(1);
const uncompressedPublicKey = secp256k1FromSeed(secretKey);
const compressedPublicKey = secp256k1Compress(uncompressedPublicKey);
console.log("Uncompressed length:", uncompressedPublicKey.length); // 64
console.log("Compressed length:", compressedPublicKey.length); // 33Expands a compressed secp256k1 public key from 33 bytes to 64 bytes.
/**
* Expands compressed secp256k1 public key
* @param pubkey - 33-byte compressed public key as Uint8Array
* @returns 64-byte uncompressed public key as Uint8Array
*/
function secp256k1Expand(pubkey: Uint8Array): Uint8Array;Usage Example:
import {
waitReady,
secp256k1FromSeed,
secp256k1Compress,
secp256k1Expand
} from "@polkadot/wasm-crypto";
await waitReady();
const secretKey = new Uint8Array(32).fill(1);
const originalPublicKey = secp256k1FromSeed(secretKey);
// Compress then expand
const compressedPublicKey = secp256k1Compress(originalPublicKey);
const expandedPublicKey = secp256k1Expand(compressedPublicKey);
// Keys should match after compression/expansion cycle
const keysMatch = Array.from(originalPublicKey).join(',') ===
Array.from(expandedPublicKey).join(',');
console.log("Compression/expansion cycle preserves key:", keysMatch); // trueimport {
waitReady,
secp256k1FromSeed,
secp256k1Sign,
secp256k1Recover,
secp256k1Compress,
secp256k1Expand,
sha256
} from "@polkadot/wasm-crypto";
async function demonstrateSecp256k1() {
await waitReady();
// Generate keypair
const secretKey = new Uint8Array(32);
crypto.getRandomValues(secretKey); // Use random secret in production
const publicKey = secp256k1FromSeed(secretKey);
// Test compression/expansion
const compressedPubKey = secp256k1Compress(publicKey);
const expandedPubKey = secp256k1Expand(compressedPubKey);
console.log("Compression/expansion works:",
Array.from(publicKey).join(',') === Array.from(expandedPubKey).join(',')
);
// Sign and recover
const message = new TextEncoder().encode("Test message for secp256k1");
const messageHash = sha256(message);
const fullSignature = secp256k1Sign(messageHash, secretKey);
const signature = fullSignature.slice(0, 64);
const recoveryId = fullSignature[64];
const recoveredPubKey = secp256k1Recover(messageHash, signature, recoveryId);
console.log("Key recovery works:",
Array.from(publicKey).join(',') === Array.from(recoveredPubKey).join(',')
);
return {
secretKey,
publicKey,
compressedPubKey,
signature,
recoveredPubKey
};
}
demonstrateSecp256k1();Install with Tessl CLI
npx tessl i tessl/npm-polkadot--wasm-crypto