Refuse signing without keypair instead of returning zeroes#109
Merged
Conversation
…ng 0x00..00
The provider node had two duplicated fallbacks that silently returned a
64-zero-byte placeholder when no signing keypair was configured: one in
`ProviderState::sign` (lib.rs:131-134) and one in the `/checkpoint/sign`
handler (api.rs:604-608). Any provider booted without `--keyfile` would
emit cryptographically invalid signatures into the commitment / checkpoint
flow, and callers had no way to tell a real signature from a placeholder.
Change `ProviderState::sign` to return `Result<String, Error>` and yield
`Err(Error::SigningUnavailable)` when no keypair is configured. Add a new
`Error::SigningUnavailable` variant that maps to HTTP 503 Service
Unavailable with `error: "signing_unavailable"`. All five `state.sign(...)`
call sites in api.rs propagate via `?`; the duplicate match in
`sign_checkpoint_proposal_handler` was removed and now goes through the
same `state.sign(&encoded)?` path as every other handler.
Tests:
- New unit tests in `provider-node/src/lib.rs` verify that `sign()`
refuses without a keypair, that the produced signature is real sr25519
that verifies under //Alice's public key, that schnorrkel randomisation
gives distinct-but-valid signatures across calls, and that //Bob's
signature does not verify under //Alice (negative control).
- New integration tests in `provider-node/tests/api_integration.rs`
reconstruct the `CommitmentPayload` the handler signs and verify the
returned signature with `sr25519::Pair::verify`, plus dedicated tests
proving each previously zero-byte-emitting endpoint (`/commit`,
`/commitment`, `/checkpoint/sign`, `/delete`) now returns 503 with the
right error code when no keypair is configured.
- `TestServer::new()` and `start_test_provider` now use
`with_seed("//Alice")` so existing signing-bound tests still exercise
end-to-end.
bkontur
approved these changes
Jun 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The provider node had two duplicated fallbacks that silently returned a 64-zero-byte placeholder when no signing keypair was configured: one in
ProviderState::sign(lib.rs:131-134) and one in the/checkpoint/signhandler (api.rs:604-608). Any provider booted without--keyfilewould emit cryptographically invalid signatures into the commitment / checkpoint flow, and callers had no way to tell a real signature from a placeholder.Change
ProviderState::signto returnResult<String, Error>and yieldErr(Error::SigningUnavailable)when no keypair is configured. Add a newError::SigningUnavailablevariant that maps to HTTP 503 Service Unavailable witherror: "signing_unavailable". All fivestate.sign(...)call sites in api.rs propagate via?; the duplicate match insign_checkpoint_proposal_handlerwas removed and now goes through the samestate.sign(&encoded)?path as every other handler.Tests:
provider-node/src/lib.rsverify thatsign()refuses without a keypair, that the produced signature is real sr25519 that verifies under //Alice's public key, that schnorrkel randomisation gives distinct-but-valid signatures across calls, and that //Bob's signature does not verify under //Alice (negative control).provider-node/tests/api_integration.rsreconstruct theCommitmentPayloadthe handler signs and verify the returned signature withsr25519::Pair::verify, plus dedicated tests proving each previously zero-byte-emitting endpoint (/commit,/commitment,/checkpoint/sign,/delete) now returns 503 with the right error code when no keypair is configured.TestServer::new()andstart_test_providernow usewith_seed("//Alice")so existing signing-bound tests still exercise end-to-end.