# How mpcium Zeroizes Key Material in Memory: Security Measures Explained

> Understand how mpcium zeroizes key material in memory. Discover its three-layer strategy for overwriting BigInts, byte slices, and secure containers to enhance security.

- Repository: [Fystack Labs/mpcium](https://github.com/fystack/mpcium)
- Tags: deep-dive
- Published: 2026-03-02

---

**mpcium implements a three-layer zeroization strategy that explicitly overwrites `big.Int` fields, raw byte slices, and secure container objects to ensure cryptographic key material does not persist in heap memory beyond its intended lifecycle.**

The `fystack/mpcium` repository provides a secure multi-party computation (MPC) framework where protecting private key material from memory-dump attacks is critical. The codebase employs a dedicated zero-knowledge security layer that combines explicit memory overwriting with Go runtime finalizers to eliminate sensitive data as soon as it leaves scope.

## Three-Layer Zeroization Architecture

The security measures protecting key material in memory are implemented across three coordinated mechanisms in the `pkg/security` package.

### Zeroing `big.Int` Fields in TSS Structures

The TSS (Threshold Signature Scheme) library relies heavily on `math/big.Int` for cryptographic operations. Because `big.Int` stores its value in a mutable word slice, simply dereferencing the variable does not clear the underlying memory.

In [`pkg/security/zeroize.go`](https://github.com/fystack/mpcium/blob/main/pkg/security/zeroize.go), the `zeroBigInt` function iterates over `x.Bits()` and sets every word to zero before forcing the value to zero:

```go
// pkg/security/zeroize.go
func zeroBigInt(x *big.Int) {
    if x == nil {
        return
    }
    bits := x.Bits()
    for i := range bits {
        bits[i] = 0
    }
    x.SetInt64(0)
}

```

This routine is invoked by higher-level helpers like `ZeroEcdsaKeygenLocalPartySaveData` and `ZeroEddsaKeygenLocalPartySaveData` to sanitize entire TSS data structures after key generation.

### Overwriting Raw Byte Slices

For general-purpose buffers that temporarily hold passwords, serialized keys, or network messages, [`pkg/security/memory.go`](https://github.com/fystack/mpcium/blob/main/pkg/security/memory.go) provides `ZeroBytes`. This function walks the slice and writes zero to each element, then triggers a garbage collection pass to reduce the window where the data might exist in freed heap memory:

```go
// pkg/security/memory.go
func ZeroBytes(data []byte) {
    for i := range data {
        data[i] = 0
    }
    runtime.GC()
}

```

This primitive is used throughout the codebase whenever a function receives sensitive input that must not outlive the current scope.

### Finalizer-Based Secure Containers

To automate zeroization when objects go out of scope, mpcium implements `SecureBytes`—a wrapper that registers a Go finalizer. When the `SecureBytes` object is garbage-collected (or when `Clear()` is called explicitly), the finalizer invokes the zeroing routine:

```go
// pkg/security/memory.go
type SecureBytes struct {
    data []byte
}

func NewSecureBytes(data []byte) *SecureBytes {
    sb := &SecureBytes{data: data}
    runtime.SetFinalizer(sb, (*SecureBytes).zero)
    return sb
}

func (sb *SecureBytes) zero() {
    ZeroBytes(sb.data)
}

```

This pattern provides defense-in-depth: even if a developer forgets to call `Clear()`, the finalizer acts as a safety net when the runtime reclaims the memory.

## Integration Points in the MPC Workflow

The zeroization primitives are woven into every stage where secret material is produced, stored, or transmitted.

### Key Generation Sessions

During ECDSA and EdDSA key generation, the `saveData` structures returned by the TSS protocol contain sensitive shares. In [`pkg/mpc/ecdsa_keygen_session.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/ecdsa_keygen_session.go) (lines 102–108), the code defers zeroization immediately after receiving the data:

```go
defer security.ZeroEcdsaKeygenLocalPartySaveData(saveData)
defer security.ZeroBytes(keyBytes)

```

This ensures that if the function exits early due to an error or panic, the sensitive buffers are still overwritten before the stack unwinds.

### Signing Sessions

Per-operation private material is handled with similar care. In [`pkg/mpc/ecdsa_signing_session.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/ecdsa_signing_session.go) (line 136), the signing routine clears the key data immediately after the signature is produced:

```go
security.ZeroBytes(keyData)

```

This minimizes the window during which the ephemeral signing key exists in memory.

### CLI Password Handling

At the application boundary, user-supplied passwords are sanitized before the program returns control to the shell. In [`cmd/mpcium/main.go`](https://github.com/fystack/mpcium/blob/main/cmd/mpcium/main.go) (lines 382–387), the CLI zeroes password bytes after authentication:

```go
security.ZeroBytes(passwordBytes)

```

## Implementation Details and Code Examples

### Zeroing a `big.Int` Used by the TSS Library

When working with threshold signature shares that use `math/big.Int`, always use the dedicated zeroization helper:

```go
import "github.com/fystack/mpcium/pkg/security"

// Assume 'share' is a *big.Int obtained from a TSS round
security.ZeroBigIntForensic(share) // Calls the internal zeroBigInt routine

```

The implementation iterates over `x.Bits()` and clears each word ([source](https://github.com/fystack/mpcium/blob/master/pkg/security/zeroize.go#L37-L45)).

### Zeroing a Byte Slice That Holds a Serialized Key

For temporary buffers containing JSON-encoded keys or passwords:

```go
keyBytes, _ := json.Marshal(saveData) // keyBytes now contains private key material
defer security.ZeroBytes(keyBytes)     // guaranteed cleanup when the function returns

```

The slice is overwritten element-wise and a GC cycle is triggered ([source](https://github.com/fystack/mpcium/blob/master/pkg/security/memory.go#L10-L22)).

### Using the `SecureBytes` Wrapper for Temporary Secrets

For automated cleanup via finalizers:

```go
secret := security.NewSecureBytes([]byte("my-super-secret"))
defer secret.Clear() // Explicit clear; finalizer is a safety net

// Use the raw bytes only when needed
payload := secret.Bytes()
doSomething(payload)

```

`SecureBytes` registers `runtime.SetFinalizer` to invoke `ZeroBytes` when the object is garbage-collected ([source](https://github.com/fystack/mpcium/blob/master/pkg/security/memory.go#L56-L63)).

## Summary

- **Explicit Overwriting**: The `zeroBigInt` and `ZeroBytes` functions in `pkg/security` manually overwrite memory words and byte slices to prevent data remanence.
- **Automated Cleanup**: `SecureBytes` leverages Go's `runtime.SetFinalizer` to ensure zeroization occurs even when developers forget explicit `Clear()` calls.
- **Workflow Integration**: Deferred zeroization calls in [`ecdsa_keygen_session.go`](https://github.com/fystack/mpcium/blob/main/ecdsa_keygen_session.go), [`ecdsa_signing_session.go`](https://github.com/fystack/mpcium/blob/main/ecdsa_signing_session.go), and [`cmd/mpcium/main.go`](https://github.com/fystack/mpcium/blob/main/cmd/mpcium/main.go) ensure secrets are cleared during key generation, signing, and CLI password handling.
- **Defense in Depth**: Combining immediate GC hints, explicit loops, and finalizers minimizes the attack surface for memory-dump forensic analysis.

## Frequently Asked Questions

### How does mpcium prevent big.Int values from lingering in memory?

mpcium prevents `big.Int` values from lingering by using the `zeroBigInt` function in [`pkg/security/zeroize.go`](https://github.com/fystack/mpcium/blob/main/pkg/security/zeroize.go). This function accesses the internal word slice via `x.Bits()` and iterates through each word, setting it to zero before calling `x.SetInt64(0)`. This ensures that the underlying memory backing the arbitrary-precision integer is explicitly overwritten rather than simply dereferenced.

### What is the difference between ZeroBytes and SecureBytes?

`ZeroBytes` is a procedural function that immediately overwrites a byte slice with zeros and triggers garbage collection, requiring the caller to manage the lifecycle manually. `SecureBytes` is an object-oriented wrapper that encapsulates the byte slice and registers a Go finalizer via `runtime.SetFinalizer`; this ensures that `ZeroBytes` is called automatically when the `SecureBytes` object is garbage collected, even if the developer forgets to explicitly call `Clear()`.

### Does mpcium zeroize key material after signing operations?

Yes, mpcium zeroizes key material immediately after signing operations. In [`pkg/mpc/ecdsa_signing_session.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/ecdsa_signing_session.go) at line 136, the code calls `security.ZeroBytes(keyData)` right after the signature is produced. This ensures that the ephemeral private material used for the signing session does not persist in heap memory once the cryptographic operation completes.

### Are the zeroization routines tested for effectiveness?

Yes, the zeroization routines include unit tests that verify the overwriting behavior. The [`pkg/security/zeroize_test.go`](https://github.com/fystack/mpcium/blob/main/pkg/security/zeroize_test.go) file contains tests confirming that `zeroBigInt` actually overwrites the backing words of the `big.Int`, while [`pkg/security/memory_test.go`](https://github.com/fystack/mpcium/blob/main/pkg/security/memory_test.go) validates that `ZeroBytes` successfully clears byte slices and that `SecureBytes` finalizers trigger correctly during garbage collection cycles.