# Crypto

The `Crypto` service is the platform's **cryptographically secure** source of
randomness, plus message digests and UUID generation. Reach for it when the
output must be unguessable: session tokens, password salts, API keys, secure
identifiers, or hashing file contents.

This is deliberately separate from the `Random` module. `Random` is a fast,
seedable **pseudo**-random generator — perfect for simulations, sampling, and
deterministic tests, but **not** safe for secrets. `Crypto` is backed by the
host platform's CSPRNG (`node:crypto` on Node, the Web Crypto API in the
browser) and should be used whenever security matters.

```ts
import { NodeRuntime, NodeServices } from "@effect/platform-node"
import { Crypto, Effect } from "effect"

const program = Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto

  // 16 cryptographically secure random bytes
  const bytes = yield* crypto.randomBytes(16)

  // A sortable, secure identifier
  const id = yield* crypto.randomUUIDv7

  return { bytes, id }
})

// `NodeServices.layer` bundles Crypto with FileSystem, Path, Terminal, etc.
NodeRuntime.runMain(program.pipe(Effect.provide(NodeServices.layer)))
```

You retrieve the service with `yield* Crypto.Crypto` and provide it at the edge
of your program. On Node either provide the aggregate `NodeServices.layer`
(which includes `Crypto`) or the focused `NodeCrypto.layer`:

```ts
import { NodeCrypto, NodeRuntime } from "@effect/platform-node"
import { Crypto, Effect } from "effect"

const program = Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto
  return yield* crypto.randomUUIDv4
})

// Provide just the Crypto service
NodeRuntime.runMain(program.pipe(Effect.provide(NodeCrypto.layer)))
```
**Some operations can fail:** `randomBytes`, `digest`, `randomUUIDv4`, and `randomUUIDv7` live in the error
channel with [`PlatformError`](#errors) — they touch the host platform, which
can reject input (e.g. a negative byte count) or fail at the OS level. The
numeric helpers (`random`, `randomInt`, `randomShuffle`, ...) are derived
locally and never fail.

## Secure random bytes and tokens

`randomBytes(size)` returns `size` cryptographically secure bytes as a
`Uint8Array`. To turn those bytes into a transmittable token, encode them with
the [`Encoding`](https://effect.plants.sh/platform/encoding/) module — hex for fixed-width IDs,
base64url for compact URL-safe tokens.

```ts
import { Crypto, Effect, Encoding } from "effect"

const makeToken = Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto

  // 32 bytes = 256 bits of entropy: a solid default for session tokens
  const bytes = yield* crypto.randomBytes(32)

  // Hex: 64 lowercase characters
  const hex = Encoding.encodeHex(bytes)
  // => "a3f1...c0"  (64 chars)

  // Base64url: shorter, safe in URLs and cookies (no +, /, or =)
  const urlSafe = Encoding.encodeBase64Url(bytes)
  // => "o_HK...wA"  (~43 chars)

  return { hex, urlSafe }
})
```
**Tip:** Prefer `randomBytes` + an encoder over building a token out of `randomInt`
strings: bytes give you exact, well-defined entropy, and the encoders are
documented in [Encoding](https://effect.plants.sh/platform/encoding/).

## Hashing and digests

`digest(algorithm, data)` computes a one-way cryptographic hash of a byte
array. The supported algorithms are described by the [`DigestAlgorithm`](#digestalgorithm)
type: `"SHA-1"`, `"SHA-256"`, `"SHA-384"`, and `"SHA-512"`.

```ts
import { Crypto, Effect, Encoding } from "effect"

const hashContents = (data: Uint8Array) =>
  Effect.gen(function*() {
    const crypto = yield* Crypto.Crypto

    // SHA-256 produces 32 bytes
    const digest = yield* crypto.digest("SHA-256", data)

    // Present the digest as a hex string, as most tools do
    return Encoding.encodeHex(digest)
    // => "e3b0c44298fc1c149afbf4c8996fb924..."  (64 hex chars)
  })
```

A realistic use is fingerprinting a file's bytes (read with the
[FileSystem](https://effect.plants.sh/platform/file-system/) service):

```ts
import { Crypto, Effect, Encoding, FileSystem } from "effect"

const fileChecksum = (path: string) =>
  Effect.gen(function*() {
    const fs = yield* FileSystem.FileSystem
    const crypto = yield* Crypto.Crypto

    const bytes = yield* fs.readFile(path)
    const digest = yield* crypto.digest("SHA-256", bytes)

    return Encoding.encodeHex(digest)
  })
```
**SHA-1:** `"SHA-1"` is provided only for interoperability with existing protocols. Do not
use it for new security-sensitive designs; prefer `"SHA-256"` or stronger.

## Secure UUIDs

`Crypto` generates UUIDs from secure random bytes. Two versions are available.

```ts
import { Crypto, Effect } from "effect"

const ids = Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto

  const v4 = yield* crypto.randomUUIDv4
  // => "f47ac10b-58cc-4372-a567-0e02b2c3d479"  (random)

  const v7 = yield* crypto.randomUUIDv7
  // => "018f6c1e-7b2a-7c3d-9e4f-0a1b2c3d4e5f"  (time-ordered)

  return { v4, v7 }
})
```

- **`randomUUIDv4`** — fully random. Use it when you just need a unique,
  unpredictable identifier with no ordering requirement.
- **`randomUUIDv7`** — embeds a millisecond Unix timestamp in the high bits, so
  IDs generated later sort lexicographically after earlier ones. Prefer v7 for
  database primary keys and any place where roughly time-sortable IDs improve
  index locality. (The timestamp comes from Effect's `Clock`, so it is
  `TestClock`-controllable in tests.)

## Secure numeric randomness

`Crypto` exposes the same numeric helpers as the `Random` module, but every
value is drawn from the secure byte source rather than a seeded PRNG. Use these
when the number itself must be unpredictable (e.g. a random delay used as a
security measure, a shuffled draw with stakes).

```ts
import { Crypto, Effect } from "effect"

const draws = Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto

  const d = yield* crypto.random            // 0 <= d < 1
  const flip = yield* crypto.randomBoolean  // true | false
  const die = yield* crypto.randomIntBetween(1, 6) // 1..6 inclusive
  const hand = yield* crypto.randomShuffle([1, 2, 3, 4, 5])

  return { d, flip, die, hand }
})
```
**Crypto vs Random:** `Random` is seedable and reproducible — ideal for tests,
property-based testing, and simulations — but its output is predictable, so it
must never be used for secrets. `Crypto`'s numeric helpers are slower and
unseedable, but cryptographically secure. Pick `Random` for fairness and
reproducibility; pick `Crypto` when the value is security-relevant.

## Errors

The fallible operations fail with [`PlatformError`](https://effect.plants.sh/platform/), the shared
error type for platform services. Its `reason` field is either a `BadArgument`
(invalid input rejected before the operation, e.g. a negative `randomBytes`
size) or a `SystemError` (a failure reported by the host platform). Match on it
like any tagged error:

```ts
import { Crypto, Effect } from "effect"

const program = Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto
  return yield* crypto.randomBytes(-1) // rejected: not a valid size
}).pipe(
  Effect.catchTag("PlatformError", (error) =>
    // `error.reason` is a `BadArgument` or `SystemError`
    Effect.succeed(`crypto failed: ${error.reason.message}`)
  )
)
```
**Tip:** For non-secure, seedable random numbers — simulations, sampling, and
deterministic tests — use the `Random` module instead.
`Crypto` and `Random` share the same numeric helper shapes, so swapping between
them is mostly mechanical.

## API reference

The full service surface lives on the `Crypto` interface. Retrieve it with
`const crypto = yield* Crypto.Crypto`, then call these members.

### `randomBytes`

`randomBytes(size: number): Effect<Uint8Array, PlatformError>` — generates
`size` cryptographically secure random bytes. Fails with a `PlatformError`
(`BadArgument`) if `size` is not a non-negative safe integer.

```ts
import { Crypto, Effect } from "effect"

Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto
  const bytes = yield* crypto.randomBytes(8)
  // => Uint8Array(8) [ 0x9c, 0x2f, ... ]
})
```

### `digest`

`digest(algorithm: DigestAlgorithm, data: Uint8Array): Effect<Uint8Array, PlatformError>`
— computes a cryptographic hash of `data`. The output length depends on the
algorithm (SHA-256 → 32 bytes, SHA-512 → 64 bytes).

```ts
import { Crypto, Effect } from "effect"

Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto
  const hash = yield* crypto.digest("SHA-512", new TextEncoder().encode("hello"))
  // => Uint8Array(64) [ ... ]
})
```

### `randomUUIDv4`

`randomUUIDv4: Effect<string, PlatformError>` — a fully random version-4 UUID
string. An `Effect` value (not a function); `yield*` it directly.

```ts
import { Crypto, Effect } from "effect"

Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto
  const id = yield* crypto.randomUUIDv4
  // => "f47ac10b-58cc-4372-a567-0e02b2c3d479"
})
```

### `randomUUIDv7`

`randomUUIDv7: Effect<string, PlatformError>` — a time-ordered version-7 UUID
string. The leading bits encode the current time (from `Clock`), so values are
roughly sortable by creation time. Prefer for database keys.

```ts
import { Crypto, Effect } from "effect"

Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto
  const id = yield* crypto.randomUUIDv7
  // => "018f6c1e-7b2a-7c3d-9e4f-0a1b2c3d4e5f"
})
```

### `random`

`random: Effect<number>` — a secure random float in `[0, 1)`. The cryptographic
analogue of `Math.random()`. Never fails.

```ts
import { Crypto, Effect } from "effect"

Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto
  const n = yield* crypto.random
  // => 0.5733... (0 <= n < 1)
})
```

### `randomBoolean`

`randomBoolean: Effect<boolean>` — a secure random boolean (each outcome ~50%).

```ts
import { Crypto, Effect } from "effect"

Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto
  const b = yield* crypto.randomBoolean
  // => true
})
```

### `randomInt`

`randomInt: Effect<number>` — a secure random integer between
`Number.MIN_SAFE_INTEGER` and `Number.MAX_SAFE_INTEGER`, both inclusive.

```ts
import { Crypto, Effect } from "effect"

Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto
  const n = yield* crypto.randomInt
  // => -4503599627370496
})
```

### `randomBetween`

`randomBetween(min: number, max: number): Effect<number>` — a secure random
float between `min` (inclusive) and `max` (exclusive).

```ts
import { Crypto, Effect } from "effect"

Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto
  const n = yield* crypto.randomBetween(10, 20)
  // => 14.82... (10 <= n < 20)
})
```

### `randomIntBetween`

`randomIntBetween(min: number, max: number, options?: { halfOpen?: boolean }): Effect<number>`
— a secure random integer in a range. `min` is rounded up with `Math.ceil`, `max`
down with `Math.floor`. The range is **inclusive** by default; pass
`{ halfOpen: true }` to exclude the upper bound.

```ts
import { Crypto, Effect } from "effect"

Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto

  const inclusive = yield* crypto.randomIntBetween(1, 6)
  // => one of 1, 2, 3, 4, 5, 6

  const halfOpen = yield* crypto.randomIntBetween(0, 10, { halfOpen: true })
  // => one of 0..9 (10 excluded)
})
```

### `randomShuffle`

`randomShuffle<A>(elements: Iterable<A>): Effect<Array<A>>` — returns a new
array with the elements shuffled using the secure generator (Fisher–Yates). The
input is not mutated.

```ts
import { Crypto, Effect } from "effect"

Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto
  const shuffled = yield* crypto.randomShuffle(["a", "b", "c", "d"])
  // => ["c", "a", "d", "b"]
})
```

### `nextIntUnsafe`

`nextIntUnsafe(): number` — a **synchronous** secure random integer between
`Number.MIN_SAFE_INTEGER` and `Number.MAX_SAFE_INTEGER` (inclusive). Plain
method, not an `Effect`; the `Unsafe` suffix marks that it runs side-effecting
work directly. Prefer `randomInt` inside effects.

```ts
import { Crypto, Effect } from "effect"

Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto
  const n = crypto.nextIntUnsafe()
  // => 729348572349
})
```

### `nextDoubleUnsafe`

`nextDoubleUnsafe(): number` — a **synchronous** secure random float in
`[0, 1)`. Plain method, not an `Effect`. Prefer `random` inside effects.

```ts
import { Crypto, Effect } from "effect"

Effect.gen(function*() {
  const crypto = yield* Crypto.Crypto
  const n = crypto.nextDoubleUnsafe()
  // => 0.118... (0 <= n < 1)
})
```

### `DigestAlgorithm`

The string-literal type of digest algorithms accepted by `digest`:

```ts
import { Crypto } from "effect"

type DigestAlgorithm = "SHA-1" | "SHA-256" | "SHA-384" | "SHA-512"

const algorithm: Crypto.DigestAlgorithm = "SHA-256"
```

### `Crypto` (service tag)

`Crypto.Crypto` is the `Context.Service` tag for the platform cryptography
service. `yield*` it to retrieve the service; provide an implementation (such as
`NodeCrypto.layer`) to satisfy it.

```ts
import { Crypto, Effect, Layer } from "effect"

// The type of the requirement added to an effect that uses Crypto:
type Requires = Crypto.Crypto

// Providing a layer satisfies `Crypto.Crypto`
declare const myCryptoLayer: Layer.Layer<Crypto.Crypto>
const provide = <A, E>(self: Effect.Effect<A, E, Crypto.Crypto>) =>
  Effect.provide(self, myCryptoLayer)
```

### `make`

`make(impl): Crypto` builds a full `Crypto` service from two primitives: a
synchronous `randomBytes(size) => Uint8Array` and a `digest(algorithm, data)`.
All the numeric helpers, shuffling, and UUID generation are **derived** from
`randomBytes`. Use it for platform integrations, custom runtimes, or test
layers.

```ts
import { Crypto, Effect, Layer } from "effect"

// A deterministic test layer — bytes are all-zero, digest is the identity.
// Useful for asserting behavior without real entropy.
const TestCrypto = Layer.succeed(
  Crypto.Crypto,
  Crypto.make({
    randomBytes: (size) => new Uint8Array(size),
    digest: (_algorithm, data) => Effect.succeed(data)
  })
)
```
**Caution:** `impl.randomBytes` must return cryptographically secure bytes of exactly the
requested length, and a **fresh** array per call — UUID formatting mutates the
returned bytes in place.