A lightweight Express.js service that exposes endpoints to verify secp256k1 signatures, proof chains, and key timelines using [`@34a1/crypto`](https://gitlab.com/34a1/crypto).
Available from https://gitlab.com/34a1/verify-server.
---
There is a public facing instance available at https://verify.34a.xyz which you can use for testing. In production environments you **should definitely** be running your own or you'll be trusting me to verify all your signatures!
---
## ๐ Endpoints
### `GET /`
Health check.
**Response**
```json
{ "status": "ok" }
```
---
### `POST /`
Verify a single secp256k1 signature.
**Request**
```json
{
"message": "aabbcc... (hex-encoded message, typically a 32-byte hash)",
"signature": "1122... (64-byte hex signature)",
"pubKey": "04abcd... (33/65-byte hex public key)"
}
```
**Response**
```json
{ "isValid": true }
```
---
### `POST /verifyBatch`
Verify multiple signature checks in one request.
**Request**
```json
{
"verifications": [
{
"message": "aabbcc...",
"signature": "1122...",
"pubKey": "04abcd..."
},
{
"message": "deadbeef...",
"signature": "2233...",
"pubKey": "03abcd..."
}
]
}
```
**Response**
```json
{ "results": [ true, false ] }
```
---
### `POST /verifyProofs`
Validate a chain of proofs from the keyserver.
**Request**
```json
{
"proofs": [
{
"id": 1,
"message": "{\"action\":\"register\",\"signed_by\":\"abcd\"}",
"signature": "1122...",
"signed_by": "abcd",
"created_at": "2025-09-14T12:00:00Z"
},
{
"id": 2,
"message": "{\"action\":\"addKey\",\"nonce\":1,\"new_key\":\"efgh\"}",
"signature": "3344...",
"signed_by": "abcd",
"created_at": "2025-09-14T12:05:00Z"
}
]
}
```
**Response**
```json
{
"chainStatus": "active",
"activeKeys": ["abcd", "efgh"],
"revokedKeys": [],
"proofsVerified": true
}
```
---
### `POST /verifyKeysWithTimeline`
Validate that a set of keys are linked by the proof chain and return the timeline.
**Request**
```json
{
"proofs": [
{
"id": 1,
"message": "{\"action\":\"register\",\"signed_by\":\"abcd\"}",
"signature": "1122...",
"signed_by": "abcd",
"created_at": "2025-09-14T12:00:00Z"
},
{
"id": 2,
"message": "{\"action\":\"addKey\",\"nonce\":1,\"new_key\":\"efgh\"}",
"signature": "3344...",
"signed_by": "abcd",
"created_at": "2025-09-14T12:05:00Z"
}
],
"keys": ["abcd", "efgh"]
}
```
**Response**
```json
{
"linked": true,
"keyStatus": [
{ "key": "abcd", "status": "active" },
{ "key": "efgh", "status": "active" }
],
"status": "active",
"timeline": [
{
"id": 1,
"action": "register",
"signedBy": "abcd",
"targetKey": "abcd",
"nonce": null,
"createdAt": "2025-09-14T12:00:00Z"
},
{
"id": 2,
"action": "addKey",
"signedBy": "abcd",
"targetKey": "efgh",
"nonce": 1,
"createdAt": "2025-09-14T12:05:00Z"
}
]
}
```
---
## ๐ Development
### Clone the repo
```bash
git clone git@gitlab.com:34a1/verify-server.git
```
### Install dependencies
```bash
npm install
```
### Run locally
```bash
npm start
```
Service runs on port **1338** by default.
---
## ๐ Notes
- Relies on [`@34a1/crypto`](https://gitlab.com/34a1/crypto) for signature and proof verification logic.
- Does not persist state; all verification is stateless.
- Errors return `400` with `{ "error": "..." }`.
- Proofs must have strictly increasing nonces except for the initial `register`.
- The verifier does not hash your message internally.
- You must provide exactly the bytes that were signed โ whether thatโs a 32-byte SHA-256 hash or any other payload youโve signed yourself.
Available from https://gitlab.com/34a1/verify-server.
---
There is a public facing instance available at https://verify.34a.xyz which you can use for testing. In production environments you **should definitely** be running your own or you'll be trusting me to verify all your signatures!
---
## ๐ Endpoints
### `GET /`
Health check.
**Response**
```json
{ "status": "ok" }
```
---
### `POST /`
Verify a single secp256k1 signature.
**Request**
```json
{
"message": "aabbcc... (hex-encoded message, typically a 32-byte hash)",
"signature": "1122... (64-byte hex signature)",
"pubKey": "04abcd... (33/65-byte hex public key)"
}
```
**Response**
```json
{ "isValid": true }
```
---
### `POST /verifyBatch`
Verify multiple signature checks in one request.
**Request**
```json
{
"verifications": [
{
"message": "aabbcc...",
"signature": "1122...",
"pubKey": "04abcd..."
},
{
"message": "deadbeef...",
"signature": "2233...",
"pubKey": "03abcd..."
}
]
}
```
**Response**
```json
{ "results": [ true, false ] }
```
---
### `POST /verifyProofs`
Validate a chain of proofs from the keyserver.
**Request**
```json
{
"proofs": [
{
"id": 1,
"message": "{\"action\":\"register\",\"signed_by\":\"abcd\"}",
"signature": "1122...",
"signed_by": "abcd",
"created_at": "2025-09-14T12:00:00Z"
},
{
"id": 2,
"message": "{\"action\":\"addKey\",\"nonce\":1,\"new_key\":\"efgh\"}",
"signature": "3344...",
"signed_by": "abcd",
"created_at": "2025-09-14T12:05:00Z"
}
]
}
```
**Response**
```json
{
"chainStatus": "active",
"activeKeys": ["abcd", "efgh"],
"revokedKeys": [],
"proofsVerified": true
}
```
---
### `POST /verifyKeysWithTimeline`
Validate that a set of keys are linked by the proof chain and return the timeline.
**Request**
```json
{
"proofs": [
{
"id": 1,
"message": "{\"action\":\"register\",\"signed_by\":\"abcd\"}",
"signature": "1122...",
"signed_by": "abcd",
"created_at": "2025-09-14T12:00:00Z"
},
{
"id": 2,
"message": "{\"action\":\"addKey\",\"nonce\":1,\"new_key\":\"efgh\"}",
"signature": "3344...",
"signed_by": "abcd",
"created_at": "2025-09-14T12:05:00Z"
}
],
"keys": ["abcd", "efgh"]
}
```
**Response**
```json
{
"linked": true,
"keyStatus": [
{ "key": "abcd", "status": "active" },
{ "key": "efgh", "status": "active" }
],
"status": "active",
"timeline": [
{
"id": 1,
"action": "register",
"signedBy": "abcd",
"targetKey": "abcd",
"nonce": null,
"createdAt": "2025-09-14T12:00:00Z"
},
{
"id": 2,
"action": "addKey",
"signedBy": "abcd",
"targetKey": "efgh",
"nonce": 1,
"createdAt": "2025-09-14T12:05:00Z"
}
]
}
```
---
## ๐ Development
### Clone the repo
```bash
git clone git@gitlab.com:34a1/verify-server.git
```
### Install dependencies
```bash
npm install
```
### Run locally
```bash
npm start
```
Service runs on port **1338** by default.
---
## ๐ Notes
- Relies on [`@34a1/crypto`](https://gitlab.com/34a1/crypto) for signature and proof verification logic.
- Does not persist state; all verification is stateless.
- Errors return `400` with `{ "error": "..." }`.
- Proofs must have strictly increasing nonces except for the initial `register`.
- The verifier does not hash your message internally.
- You must provide exactly the bytes that were signed โ whether thatโs a 32-byte SHA-256 hash or any other payload youโve signed yourself.