# Lace-009 · Signatures
Tags: record, crypto

## Purpose

Seal records need portable authorship proof that survives transport boundaries:
a verifier signs a specific Plex-record digest, and any implementation can check the
signature from record bytes alone. This spec defines verifier, signing-secret,
and signature rules used by Seal records in the current `.H3` suite. It signs a
32-byte BLAKE3 digest with secp256k1 Schnorr arithmetic and encodes public
protocol values with B64A.

This document is for record and crypto implementors. After reading it, an
implementor should be able to generate verifier text, derive signing material,
produce signatures, and verify Seal-record signatures consistently across languages.

## Defines

Key generation, signing-secret derivation, signing, and verification.

## Text forms identify verifier and signing values

- Verifier: `V.<b64a>.H3`, where payload is a 32-byte public x-coordinate.
- Signing secret: `&.<b64a>.H3`, where payload is 32 bytes of secret derivation
  material.
- Signature: 64 signature bytes encoded with B64A.

A verifier is public. A signing secret is private local material used to derive a
signing scalar.

## Parameters define the current signature system

- Curve: secp256k1.
- Generator: `G`.
- Order: `n`.
- Field prime: `p`.
- Message input: `msg32`, a 32-byte BLAKE3 digest of signed bytes.
- Integer encoding: `bytes(x)`, the 32-byte big-endian encoding of a scalar or
  field element.

BLAKE3 derive-key context strings:

| Context | Use |
|---|---|
| `lace-🖧/adhoc-key` | signing-secret derivation |
| `lace-🖧/aux` | signing auxiliary randomness tag |
| `lace-🖧/nonce` | nonce tag |
| `lace-🖧/challenge` | challenge tag |

`derive_key(context, input)` means the first 32 bytes of BLAKE3 derive-key
output for that context and input. Context strings are encoded as the exact
UTF-8 bytes of the displayed text.

## Signer generation produces an even-y verifier

Implementations MUST generate random signing scalars as follows:

1. Choose random 32-byte `d0` with `0 < d0 < n`.
2. Compute `P = d0*G`.
3. If `P.y` is odd, set `d = n - d0`; otherwise set `d = d0`.
4. The signing scalar is `d` and verifier bytes are `bytes((d*G).x)`.

The even-y convention makes one verifier text correspond to one public point.

## Signing-secret derivation maps secret text to a scalar

To derive signing material from a signing secret payload, implementations MUST:

1. Reject payloads whose decoded length is not exactly 32 bytes.
2. Use BLAKE3 XOF derive mode with context `lace-🖧/adhoc-key`.
3. Read 32-byte candidates until one satisfies `0 < d0 < n`.
4. Apply the same even-y normalization used by signer generation.

## Signing binds a digest to a verifier

Inputs are signing scalar `d`, verifier x-coordinate `Px`, message digest
`msg32`, and fresh nonzero 32-byte `auxRand32`.

Implementations MUST sign as follows:

1. `t = derive_key("lace-🖧/aux", auxRand32)`.
2. `mask = t xor bytes(d)`.
3. `k0 = derive_key("lace-🖧/nonce", mask || Px || msg32) mod n`; reject zero.
4. Compute `R = k0*G`; use `k = n-k0` when `R.y` is odd, else `k = k0`.
5. `e = derive_key("lace-🖧/challenge", bytes(R.x) || Px || msg32) mod n`.
6. `s = (k + e*d) mod n`.
7. Signature bytes are `bytes(R.x) || bytes(s)`.

`auxRand32` MUST be unique per signature and MUST NOT be all zero.

## Verification accepts only the matching signature

Inputs are verifier x-coordinate `Px`, signature `r||s`, and message digest
`msg32`.

Implementations MUST verify as follows:

1. Reject `Px >= p`, `r >= p`, or `s >= n`.
2. Recover point `P` from `Px` using the even-y root; reject `Px` values that do
   not identify a secp256k1 point.
3. Compute `e = derive_key("lace-🖧/challenge", bytes(r) || Px || msg32) mod n`.
4. Compute `R' = s*G - e*P`.
5. Reject infinity or odd `R'.y`.
6. Accept only when `R'.x == r`.

Implementations MUST use constant-time scalar and point operations.

## Rejection examples

Reject examples include an empty signing secret, all-zero auxiliary value,
`Px >= p`, `Px` with no curve point, `r >= p`, `s >= n`, odd recovered `R'`,
and any signature whose recomputed `R'.x` differs from `r`.
