Skip to main content

Overview

Private keys are 32-byte secp256k1 secrets used for signing. This module provides both standard schemas and redacted variants that prevent accidental exposure in logs and errors.
Production recommendation: Use RedactedHex or RedactedBytes to prevent private keys from appearing in logs, error messages, or JSON serialization.

Schemas

SchemaInputOutputUse Case
PrivateKey.Hexhex stringPrivateKeyTypeDevelopment/debugging
PrivateKey.BytesUint8ArrayPrivateKeyTypeDevelopment/debugging
PrivateKey.RedactedHexhex stringRedacted<PrivateKeyType>Production
PrivateKey.RedactedBytesUint8ArrayRedacted<PrivateKeyType>Production

Basic Usage

import * as PrivateKey from 'voltaire-effect/primitives/PrivateKey'
import * as S from 'effect/Schema'

// Standard (raw value - use in dev only)
const pk = S.decodeSync(PrivateKey.Hex)(
  '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
)

// From bytes
const pk2 = S.decodeSync(PrivateKey.Bytes)(new Uint8Array(32).fill(1))
Redacted schemas wrap private keys in Effect’s Redacted<T> type, which:
  • Shows <redacted> when logged or stringified
  • Requires explicit Redacted.value() to access the underlying key
  • Prevents exposure in error messages and JSON serialization
import * as PrivateKey from 'voltaire-effect/primitives/PrivateKey'
import { Redacted } from 'effect'
import * as S from 'effect/Schema'

// Decode to Redacted type
const redactedPk = S.decodeSync(PrivateKey.RedactedHex)(
  '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
)

// Safe logging - shows "<redacted>", not the actual key
console.log(redactedPk)           // Redacted(<redacted>)
console.log(String(redactedPk))   // <redacted>

// Explicit unwrap for cryptographic operations
const unwrapped = Redacted.value(redactedPk)
const publicKey = Secp256k1.derivePublicKey(unwrapped)
const signature = Secp256k1.sign(messageHash, unwrapped)

// Round-trip encoding works normally
const encoded = S.encodeSync(PrivateKey.RedactedHex)(redactedPk)
// "0x0123456789abcdef..."

Effect API

import { Effect } from 'effect'

// Generate random key
const pk = Effect.runSync(PrivateKey.random())

// Validate key format
const isValid = Effect.runSync(PrivateKey.isValid('0x0123...'))

Cryptographic Operations

import * as Secp256k1 from '@tevm/voltaire/Secp256k1'
import { Redacted } from 'effect'

const redactedPk = S.decodeSync(PrivateKey.RedactedHex)(hexString)
const pk = Redacted.value(redactedPk) // Explicit unwrap

// Derive public key
const publicKey = Secp256k1.derivePublicKey(pk)

// Sign message
const signature = Secp256k1.sign(messageHash, pk)

// Verify signature
const isValid = Secp256k1.verify(signature, messageHash, publicKey)

Error Handling

import { Effect } from 'effect'

// Parse errors don't expose the attempted value
const result = await Effect.runPromiseExit(
  S.decodeUnknown(PrivateKey.RedactedHex)('0xinvalid')
)
// Error message: "Invalid private key format"
// NOT: "Invalid hex: 0xinvalid..."

When to Use Each Schema

ScenarioRecommended Schema
Production applicationsRedactedHex / RedactedBytes
Unit testsHex / Bytes
Debugging locallyHex / Bytes
CI/CD pipelinesRedactedHex / RedactedBytes
Logging enabledRedactedHex / RedactedBytes

See Also