Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
concentricspheres committed Dec 21, 2024
0 parents commit 11df0b1
Show file tree
Hide file tree
Showing 14 changed files with 2,456 additions and 0 deletions.
22 changes: 22 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# http://editorconfig.org

root = true

[*]
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
charset = utf-8

[*.py]
max_line_length = 119
indent_size = 4

# The JSON files contain newlines inconsistently
[*.json]
indent_size = 2

[*.yml]
indent_style = space
indent_size = 2
43 changes: 43 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Create and publish the Docker image

on:
push:
branches: [ "main", "dev" ]
# Publish semver tags as releases.
tags: [ 'v*.*.*' ]

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Build and push Docker image
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.DS_Store

config
output
config.yml

# VS Code
.vscode

__pycache__

# Build executables and resources
build/
dirk-tools.spec

# Temporary folder created when building executable
eth2spec
25 changes: 25 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FROM python:3.9.10-bullseye as builder

RUN python --version

RUN curl -sSL https://install.python-poetry.org | python -

ENV PATH="/root/.local/bin:$PATH"

WORKDIR /app

COPY . .

RUN poetry install

RUN ./build.sh

FROM debian:bullseye-slim

RUN apt-get update && apt-get install -y ca-certificates bash tzdata hwloc libhwloc-dev wget

COPY --from=builder /app/build/dirk-tools/dirk-tools /usr/local/bin/

RUN mkdir /var/lib/dirk-tools && chmod 0777 /var/lib/dirk-tools

ENTRYPOINT [ "/usr/local/bin/dirk-tools" ]
132 changes: 132 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# dirk-tools
A command-line collection of utilities to use with [Dirk](https://github.com/attestantio/dirk/).

## Usage

### Signing an arbitrary message

`dirk-tools --config config.yml sign-arbitrary-message [ARGS]`

```
Options:
--message TEXT The message you want to sign with the validator
keys.
--domain TEXT 32-byte hex string domain in which to sign the
message
--output-dir DIRECTORY The folder where signed messages will be saved.
```

Ethereum 2.0 uses BLS signatures with the BLS12-381 curve, primarily to:

- Sign beacon chain objects (blocks, attestations, etc.).
- Enable aggregation of many signatures into a single, compact multi-signature.

SSZ (Simple Serialize) is the canonical way of encoding structured data prior to hashing and signing. For example:

- A BeaconBlock is an SSZ container with fields: slot, proposer_index, parent_root, state_root, and body_root.
- An Attestation is an SSZ container with fields: slot, index, beacon_block_root, source, target.

These containers are then serialized via SSZ, hashed, domain-separated, and signed using the BLS curve. Existing containers are Ethereum-specific and not intended for arbitrary messages.

Ethereum 2.0 also includes domain separation in the hashing process. This ensures that signatures cannot be replayed across different message types (e.g., confusing a block signature with an attestation signature). This is done by mixing in a 4-byte domain type, plus a version or fork identifier, before hashing.

In order to be able to sign an arbitrary message, we defined the following container:

```python
class ArbitraryMessage(Container):
message: Bytes32
```

This provides the flexibility to handle messages of any length by following these steps:

- Hash the message using SHA-256 to produce a 32-byte digest.
- Wrap the digest in the ArbitraryMessage container.
- Compute the SSZ hash tree root.
- Sign the root using Dirk.

### Verify a message signature

`dirk-tools verify-signature [OPTIONS]`

```
Options:
--message TEXT The original message that was signed.
--hash-tree-root TEXT If the original message is not passed, pass the hash tree root of the message.
--domain TEXT 32-byte hex string domain in which the message was signed.
--public-key TEXT The public key.
--signature TEXT The signature.
```

Alternatively, the signature can also be verified with ethdo:

`ethdo signature verify --data="0xMESSAGE_HASH_TREE_ROOT" --signature="0xSIGNATURE" --public-key="0xPUBLIC_KEY" --domain="0xDOMAIN" --verbose`

## Configuration

By default, `dirk-tools` loads the `config.yml` in the current folder in the current folder.

Otherwise it can be with the `--config` option, e.g:

`dirk-tools --config /path/to/config.yml [COMMAND] [ARGS]`

```yaml
dirk:
# Hostname and port of the Dirk instance.
endpoint: dirk.example.com:13141

# Path to the client certificate to authenticate with Dirk.
client_cert: /path/to/certs/client.crt

# Path to the key to authenticate with Dirk.
client_key: /path/to/certs/client.key

# Path to the Certificate Authority certificate.
ca_cert: /path/to/certs/dirk_authority.crt

# Name of the Wallet
wallet: Wallet
```
## Development
### Requirements
- python ^3.9.10 built with a shared Python Library
Linux:
```shell
sudo apt-get install python3-dev
```

MacOS with pyenv:
```shell
env PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.9.10
```

- [Poetry](https://python-poetry.org/)

```shell
curl -sSL https://install.python-poetry.org | python -
```

### Install Dependencies

```shell
poetry install
```

### Running locally

```shell
poetry run python dirk_tools/main.py --config /path/to/config [COMMAND] [ARGS] --config /path/to/config.yml
```

### Building Executable

```shell
./build.sh
```

## License

[Apache License v2](LICENSE)
14 changes: 14 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# eth2spec's setup.py tries to locate the file tests/core/pyspec/eth2spec/VERSION.txt
# which breaks when running under the pyinstaller packed mode.
# As a workaround, we temporarily create the path it expects.
mkdir eth2spec
touch eth2spec/VERSION.txt

poetry run pyinstaller \
--onefile \
--collect-data eth2spec \
--collect-data dirk_tools ./dirk_tools/main.py \
--name dirk-tools \
--distpath build/dirk-tools

rm -rf eth2spec
15 changes: 15 additions & 0 deletions config.sample.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
dirk:
# Hostname and port of the Dirk instance.
endpoint: dirk.example.com:13141

# Path to the client certificate to authenticate with Dirk.
client_cert: /path/to/certs/client.crt

# Path to the key to authenticate with Dirk.
client_key: /path/to/certs/client.key

# Path to the Certificate Authority certificate.
ca_cert: /path/to/certs/dirk_authority.crt

# Name of the Wallet
wallet: Wallet
Empty file added dirk_tools/__init__.py
Empty file.
Empty file added dirk_tools/commands/__init__.py
Empty file.
Loading

0 comments on commit 11df0b1

Please sign in to comment.