> ## Documentation Index
> Fetch the complete documentation index at: https://sava.software/llms.txt
> Use this file to discover all available pages before exploring further.

# Vanity Address Generator

> Generate addresses with a defined prefix and/or suffix.

<Card title="GitHub Repository" icon="github" horizontal={true} href="https://github.com/sava-software/sava/tree/main/sava-vanity#vanity-address-generator" />

## Configuration

<Info>
  **GitHub Access Token**: [Generate a classic token](https://github.com/settings/tokens) with the `read:packages` scope to access
  dependencies hosted on GitHub Package Repository.
</Info>

```properties .gradle/gradle.properties theme={null}
savaGithubPackagesUsername=GITHUB_USERNAME
savaGithubPackagesPassword=GITHUB_TOKEN
```

## Compile

```shell theme={null}
./sava-vanity/compile.sh
```

## Run

```shell theme={null}
./sava-vanity/genKeys.sh --prefix="abc" --outDir=".keys"
```

### Docker

Instead of running the local jlink binary, you can run a Docker image by passing the `docker` flag with the image name
and tag.

Build the image:

```shell theme={null}
docker build --build-arg PROJECT=sava-vanity -t sava-vanity:local -f sava-vanity/Dockerfile .
```

Run it:

```shell theme={null}
./sava-vanity/genKeys.sh --docker="sava-vanity:local" --prefix="abc" --outDir=".keys"
```

By default, the image is built only when it is not found locally. Pass the `build` flag to force a
rebuild even if the image already exists:

```shell theme={null}
./sava-vanity/genKeys.sh --docker="sava-vanity:local" --build --prefix="abc" --outDir=".keys"
```

When not using Docker, the local jlink binary image (`./gradlew :sava-vanity:image`) is built
automatically when it has not been built yet. Pass the `build` flag to force a rebuild of the local
binary image even if it already exists:

```shell theme={null}
./sava-vanity/genKeys.sh --build --prefix="abc" --outDir=".keys"
```

An `outDir` is required so the generated keys are saved to disk; the host directory is created if
necessary and bind-mounted into the container with write permissions so that generated keys are
persisted on the host:

```shell theme={null}
./sava-vanity/genKeys.sh --docker="sava-vanity:local" --prefix="abc" --outDir=".keys"
```

### Args

* A `prefix` and/or `suffix` must be provided.
* `outDir` is required so the generated keys are saved to disk.
* `numThreads` defaults to half of the systems CPU's.
* `keyFileFormat` controls the on-disk key file format and may be `properties` (default) or `json`.
* Each thread will check every `checkFound` iterations if `numKeys` have been found.
* `p1337Letters` allows alphabetic characters to be replaced by visually similar numbers.
* `1337Numbers` allows numbers to be replaced by visually similar alphabetic characters.
* `screen` may be enabled to manage the session so that it can be re-attached if a remote session is disconnected.
  * `ctrl+a -> d` to detach
  * `screen -r` to re-attach

### Run Control

* jvmArgs="-server -Xms64M -Xmx128M"
* \[d | docker | dockerImage]=
* \[b | build]=false
* screen=0
* \[nt | numThreads]=
* \[nk | numKeys]=1
* \[kf | keyFormat]="base64KeyPair"
* \[kff | keyFileFormat]="properties"
* \[cf | checkFound]=131072
* \[ld | logDelay]="5S"
* \[o | outDir]='.keys' (required)
* \[sv | sigVerify]=false

### Encryption

The generated secret key can be encrypted at rest by enabling the `encrypt` flag. The password is
never passed on the command line or as a JVM system property (both of which are visible in process
listings); it is supplied to the Java runtime only via the `SAVA_VANITY_ENCRYPT_PASSWORD`
environment variable.

* \[e | encrypt]=false
* \[pw | password] — securely prompts for the password (with confirmation) and forwards it to the
  Java runtime via the environment variable. Implies `encrypt=true`.
* \[pe | passwordEnv]=ENV\_VAR\_NAME — reads the password from an already-exported environment variable
  for fully non-interactive runs. Implies `encrypt=true`.

If `encrypt=true` is set without `password`/`passwordEnv`, and the
`SAVA_VANITY_ENCRYPT_PASSWORD` environment variable is not present, the application falls back to
reading the password from the interactive Java Console.

```shell theme={null}
# Securely prompt for the encryption password.
./sava-vanity/genKeys.sh --prefix="abc" --password

# Non-interactive: read the password from an existing environment variable.
export MY_VANITY_PASSWORD="..."
./sava-vanity/genKeys.sh --prefix="abc" --passwordEnv=MY_VANITY_PASSWORD
```

#### Key Derivation (KDF)

The password is run through a key derivation function before it is used to encrypt the secret. The
`kdf` flag selects the function and the secret is always encrypted with AES-256/GCM. The KDF parameters can be
customized; when they are omitted, hardened defaults are used.

* \[kdf]=argon2id — `argon2id` (memory-hard, the default) or `pbkdf2` (`PBKDF2WithHmacSHA512`).
* \[kit | kdfIterations] — number of iterations. Applies to both `pbkdf2` and `argon2id`.
* \[kmem | kdfMemoryKB] — Argon2id memory cost in KiB. Only valid with `kdf=argon2id`.
* \[kpar | kdfParallelism] — Argon2id parallelism (lanes). Only valid with `kdf=argon2id`.

Argon2id parameter tuning is all-or-nothing: either provide none of `kdfMemoryKB`,
`kdfParallelism` and `kdfIterations` (to use the defaults) or provide all three.

Because Argon2id is memory-hard, each concurrent derivation allocates `kdfMemoryKB` of heap
(default 262144 KB / 256 MiB). When `kdf=argon2id` is selected, `genKeys.sh` automatically sizes
the JVM heap to `(kdfMemoryKB × numThreads) + 128 MiB` so concurrent derivations do not exhaust
the default heap. Passing your own `--jvm` args disables this auto-sizing.

```shell theme={null}
# Use Argon2id (the default) with the hardened defaults.
./sava-vanity/genKeys.sh --prefix="abc" --password

# Use Argon2id with fully customized parameters (all three are required).
./sava-vanity/genKeys.sh --prefix="abc" --password --kdf=argon2id \
  --kdfMemoryKB=262144 --kdfParallelism=4 --kdfIterations=3

# Opt out of Argon2id and customize only the PBKDF2 iteration count.
./sava-vanity/genKeys.sh --prefix="abc" --password --kdf=pbkdf2 --kdfIterations=600000
```

### Prefix

* \[p | prefix]=""
* \[pc | pCaseSensitive]=false
* \[pn | p1337Numbers]=true
* \[pl | p1337Letters]=true

### Suffix

* \[s | suffix]=""
* \[sc | sCaseSensitive]=false
* \[sn | s1337Numbers]=true
* \[sl | s1337Letters]=true
