Signing is where a key identity produces proof. TKeeper signs only after the command is accepted by the key's authorities and any configured policy, audit, lifecycle, and quorum controls.
Endpoints
POST /v2/keeper/sign
POST /v2/keeper/sign/verify
Required permissions:
tkeeper.key.{keyId}.sign
tkeeper.key.{keyId}.verify
Signing flow
command
-> authority match
-> intent materialization
-> policy and key controls
-> audit gate
-> mono or threshold signing
-> signature proof
For arbitrary, TKeeper signs bytes after checking the key identity allows arbitrary.
For concrete authorities, TKeeper loads the authority document, materializes the command into an intent, extracts effects where supported, evaluates policy, and signs only when the final decision is ALLOW.
Quorum modes
| Mode | Behavior |
|---|---|
mono |
signs locally with full key material after controls pass |
threshold |
coordinator starts a threshold protocol; private key is not reconstructed |
Threshold signing protocols:
| Scheme | Threshold protocol |
|---|---|
ECDSA |
GG20 |
EdDSA |
FROST |
SCHNORR |
FROST |
BIP340 |
FROST |
TAPROOT |
FROST |
MLDSA |
threshold ML-DSA |
Commands
Arbitrary command:
{
"keyId": "demo-identity",
"command": {
"type": "arbitrary",
"authorityId": "arbitrary",
"artifact": {
"scheme": "ECDSA",
"hash": "SHA256",
"data64": "aGVsbG8="
}
}
}
Typed command:
{
"keyId": "payments-key",
"command": {
"type": "custom",
"authorityId": "payments-small",
"artifact": {
"scheme": "ECDSA",
"hash": "SHA256",
"typed": {
"amount": 100,
"currency": "USD"
}
}
}
}
EVM command:
{
"keyId": "evm-key",
"command": {
"type": "evm.transaction",
"authorityId": "evm-mainnet-erc20-usdc",
"artifact": {
"message64": "..."
}
}
}
Bitcoin and X.509 commands follow the authority type selected by their feature modules.
Schemes and algorithms
| Scheme | Mono | Threshold | Algorithms |
|---|---|---|---|
ECDSA |
local ECDSA | GG20 | SECP256K1, P256 |
SCHNORR |
not supported | FROST | SECP256K1, P256 |
BIP340 |
local BIP340 | FROST | SECP256K1 |
TAPROOT |
local Taproot key-path | FROST | SECP256K1 |
EdDSA |
local EdDSA | FROST | ED25519 |
MLDSA |
local ML-DSA | threshold ML-DSA | MLDSA44, MLDSA65, MLDSA87 |
Hash methods:
| Hash | Meaning |
|---|---|
NONE |
sign bytes as-is |
SHA256 |
hash before signing |
SHA512 |
hash before signing |
KECCAK256 |
hash before signing |
The command artifact decides the scheme and hash. The top-level sign request does not carry hash or algorithm.
Response
{
"type": "ECDSA",
"signature64": "...",
"generation": 1,
"imposters": []
}
imposters is meaningful for threshold protocols. Mono signatures return an empty list.
Verify response:
{ "valid": true }
generation is optional on verify. If omitted, TKeeper uses the active generation.
ML-DSA availability
Threshold ML-DSA uses probabilistic rejection sampling. A complete attempt can abort even when peers are healthy. TKeeper retries with fresh session state up to:
keeper.session.mldsa.max-rounds
The default is 12. Exhaustion returns SESSION_MAX_ROUNDS_EXCEEDED; treat it as availability first, not proof of corruption.
Downstream verification
The downstream system should verify that the proof matches the exact command it is about to execute and the identity it intended to trust.
Signature validity alone is insufficient. The acceptance contract should cover:
- expected key identity or public key
- canonical command and every field that changes the effect
- authority, generation, and tweak context required by the integration
- environment or domain separation between test and production
- nonce, expiry, sequence, or idempotency where replay matters
If context is enforced outside the signed payload, the verifier must reject mismatches before execution. For arbitrary, TKeeper governs only the supplied bytes; it cannot infer omitted business context.
Common failures
Verify returns false
Check that command, tweak, generation, and signature64 match the original sign request. For arbitrary commands, also check hash and scheme inside the command artifact.
Authority rejects the command
AUTHORITY_VIOLATION means the command selected an authority that is not attached to the key. INVALID_AUTHORITY_ARTIFACT means the command shape does not match the selected authority or its feature is absent. POLICY_VIOLATION means the materialized intent was understood but policy returned DENY.
No manager for scheme and algorithm
The key algorithm or quorum mode does not support the requested signature scheme.