# Core Architecture of the croc Project: Secure P2P File Transfer in Go

> Explore the core architecture of the croc project, featuring a monolithic Client struct for secure P2P file transfer in Go using PAKE, relays, and AES-GCM encryption for CLI and library use.

- Repository: [Zack/croc](https://github.com/schollz/croc)
- Tags: architecture
- Published: 2026-07-26

---

**The croc file transfer tool centers around a monolithic `Client` struct in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) that orchestrates secure peer-to-peer transfers through PAKE key exchange, relay-assisted TCP connections, and AES-GCM encryption, enabling both CLI and programmatic library usage.**

The croc project is a cross-platform, peer-to-peer file transfer tool written in Go that eliminates the need for server-side infrastructure while maintaining end-to-end encryption. Understanding the core architecture of the croc project reveals how it balances simplicity with security, using a centralized relay architecture for NAT traversal while keeping data transfer direct between peers. At its heart, a single **Client** object manages the entire lifecycle of a transfer, from discovery and handshake to encrypted data streaming and reconnection logic.

## The Central Client Architecture

The architecture revolves entirely around the **`Client`** struct defined in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go). This object encapsulates all runtime state including connection handles, file metadata, progress tracking, and configuration options.

The `Client` implements two high-level workflows:

- **`Send`** – Initiates transfers by gathering file metadata, establishing secure connections, and streaming data chunks.
- **`Receive`** – Listens for incoming connections, performs handshake verification, and writes received chunks to disk.

Both workflows share the same internal state machine, allowing croc to function as either a sender or receiver without separate binaries. The `Options` struct (defined in the same file) captures all user-configurable parameters including relay addresses, encryption settings, compression flags, and bandwidth throttling.

## Connection Layer: TCP and Communication Abstractions

croc abstracts network complexity through two distinct layers. The **TCP layer** ([`src/tcp/tcp.go`](https://github.com/schollz/croc/blob/main/src/tcp/tcp.go)) manages low-level socket connections to public relays or locally-started relays, handling multiplexed streams and reconnection logic through functions like `ConnectToTCPServer`.

Above this sits the **`comm.Comm`** abstraction ([`src/comm/comm.go`](https://github.com/schollz/croc/blob/main/src/comm/comm.go)), a thin wrapper that provides:

- **Message framing** – Ensures complete JSON message delivery over TCP streams.
- **Heartbeat handling** – Maintains connection viability during idle periods.
- **Send/Receive primitives** – `comm.Send` and `comm.Receive` methods used throughout the codebase.

This layered approach allows the higher-level `Client` to focus on transfer logic while the lower layers handle network resilience.

## Security Architecture: PAKE and Encryption

Security is implemented through a two-phase cryptographic handshake. First, the **PAKE (Password-Authenticated Key Exchange)** handshake establishes a shared secret without transmitting the password itself. This occurs in [`croc.go`](https://github.com/schollz/croc/blob/main/croc.go) through `senderWaitForHandshake` on the sender side and corresponding receiver logic.

Once the PAKE exchange completes, all subsequent communication uses **AES-GCM symmetric encryption** implemented in [`src/crypt/crypt.go`](https://github.com/schollz/croc/blob/main/src/crypt/crypt.go). The `crypt.Encrypt` and `crypt.Decrypt` functions protect file chunks and control messages, ensuring that even if relay servers are compromised, transferred data remains inaccessible.

## Message Protocol and File Handling

The **`message`** package ([`src/message/message.go`](https://github.com/schollz/croc/blob/main/src/message/message.go)) defines the JSON-encoded protocol used after encryption. Key message types include:

- **PAKE messages** – Exchange public parameters for key derivation.
- **File metadata** – `FileInfo` structs containing name, size, hash, permissions, and symlink targets.
- **Data chunks** – Binary payloads with sequence identifiers.
- **Acknowledgments** – Receipt confirmations for flow control.

Before transfer begins, `GetFilesInfo` in [`croc.go`](https://github.com/schollz/croc/blob/main/croc.go) walks source paths, applies `.gitignore` rules, handles exact-path exclusions, and optionally creates zip archives for folders. This preprocessing ensures the receiver knows exactly what to expect before bytes flow.

## Relay and Discovery Mechanisms

croc solves NAT traversal through a hybrid approach. By default, it connects to public relay servers, but it can also spawn **local relays** for LAN transfers using [`src/webrelay/webrelay.go`](https://github.com/schollz/croc/blob/main/src/webrelay/webrelay.go). The local relay advertises its presence via **peerdiscovery**, allowing devices on the same network to connect directly without internet bandwidth.

If LAN discovery fails, the client falls back to the public relay specified in `Options.RelayAddress`. The `webrelay` implementation handles HTTP signaling for the optional web UI (`getcroc.com`), though this is separate from the core TCP relay functionality.

## Resilience and State Management

Transfer reliability relies on sophisticated reconnection logic. The `transferWithReconnect` function in [`croc.go`](https://github.com/schollz/croc/blob/main/croc.go) automatically attempts reconnection to the same or alternate relays upon network interruption, preserving transfer state including progress bars and file positions.

Additional utilities in [`src/utils/utils.go`](https://github.com/schollz/croc/blob/main/src/utils/utils.go) provide:

- **Rate limiting** – Throttling bandwidth usage.
- **Progress tracking** – Visual feedback via progress bars.
- **QR-code generation** – For easy mobile device pairing.
- **Clipboard integration** – Automatic secret copying.

## Using croc: CLI and Library Patterns

The architecture supports two primary usage modes: command-line interface and Go library integration.

### Command-Line Usage

The most common interaction occurs through the CLI defined in [`main.go`](https://github.com/schollz/croc/blob/main/main.go):

```bash

# Sender side – transfer a directory

croc send /path/to/myfolder

# Receiver side – receive the files (copy the secret printed by the sender)

croc receive

```

### Programmatic Usage as a Library

For embedded applications, import the `croc` package directly:

```go
package main

import (
	"fmt"
	"github.com/schollz/croc/v10/src/croc"
	"github.com/schollz/croc/v10/src/models"
)

func main() {
	// Create a client with custom options
	opts := croc.Options{
		IsSender:      true,
		SharedSecret:  "demo-secret-1234",
		RelayAddress:  models.DEFAULT_RELAY,
		RelayPassword: models.DEFAULT_PASSPHRASE,
		Debug:         true,
	}
	cl, err := croc.New(opts)
	if err != nil {
		panic(err)
	}

	// Gather file information
	files, empty, total, err := croc.GetFilesInfo([]string{"example.txt"}, false, false, nil)
	if err != nil {
		panic(err)
	}

	// Start the transfer
	if err = cl.Send(files, empty, total); err != nil {
		fmt.Println("transfer failed:", err)
	} else {
		fmt.Println("transfer completed")
	}
}

```

### Receiving Programmatically

```go
package main

import (
	"fmt"
	"github.com/schollz/croc/v10/src/croc"
	"github.com/schollz/croc/v10/src/models"
)

func main() {
	// Receiver options – use the same secret as the sender
	opts := croc.Options{
		IsSender:      false,
		SharedSecret:  "demo-secret-1234",
		RelayAddress:  models.DEFAULT_RELAY,
		RelayPassword: models.DEFAULT_PASSPHRASE,
	}
	cl, err := croc.New(opts)
	if err != nil {
		panic(err)
	}

	// Start receiving
	if err = cl.Receive(); err != nil {
		fmt.Println("receive failed:", err)
	} else {
		fmt.Println("receive completed")
	}
}

```

## Summary

- The **core architecture of the croc project** centers on a single `Client` struct in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) that manages both sending and receiving workflows.
- **TCP connections** ([`src/tcp/tcp.go`](https://github.com/schollz/croc/blob/main/src/tcp/tcp.go)) and the **`comm.Comm`** wrapper ([`src/comm/comm.go`](https://github.com/schollz/croc/blob/main/src/comm/comm.go)) provide reliable transport with automatic reconnection support.
- **PAKE key exchange** and **AES-GCM encryption** ([`src/crypt/crypt.go`](https://github.com/schollz/croc/blob/main/src/crypt/crypt.go)) secure all transfers without requiring certificate infrastructure.
- The **JSON message protocol** ([`src/message/message.go`](https://github.com/schollz/croc/blob/main/src/message/message.go)) handles metadata exchange and chunked data transmission.
- **Hybrid relay architecture** supports both public relays and local LAN discovery via [`src/webrelay/webrelay.go`](https://github.com/schollz/croc/blob/main/src/webrelay/webrelay.go).
- The codebase functions as both a standalone CLI and an importable Go library, with all state contained within the `Client` object.

## Frequently Asked Questions

### How does croc establish secure connections without prior key exchange?

croc uses **PAKE (Password-Authenticated Key Exchange)** to derive encryption keys from the user-provided shared secret. As implemented in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go), the PAKE handshake allows both parties to generate identical session keys (`kA/kB`) without transmitting the actual password across the network, preventing man-in-the-middle attacks even when using public relay servers.

### What happens if the network connection drops during a file transfer?

The `transferWithReconnect` function in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) automatically attempts to re-establish the TCP connection to the same or alternative relays. This reconnection logic preserves the transfer state, allowing transfers to resume from the last acknowledged chunk rather than restarting from the beginning.

### Can croc be integrated into existing Go applications as a library?

Yes. The `Client` struct in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) is designed for programmatic use through the `croc.New()` constructor and `Send()` / `Receive()` methods. Applications can configure transfer behavior via the `Options` struct, including custom relay addresses, debug logging, and compression settings without invoking the CLI.

### How does croc handle large files or directories efficiently?

Before transfer, `GetFilesInfo` in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) enumerates all files and breaks them into chunks defined in [`src/models/constants.go`](https://github.com/schollz/croc/blob/main/src/models/constants.go). The **message protocol** ([`src/message/message.go`](https://github.com/schollz/croc/blob/main/src/message/message.go)) streams these chunks with flow control via acknowledgments, while **TCP multiplexing** in [`src/tcp/tcp.go`](https://github.com/schollz/croc/blob/main/src/tcp/tcp.go) maintains concurrent channels for data and control signals.