Issue 1707 ciphertext binding signature - #1814
Open
toniasteve15-ui wants to merge 10 commits into
Open
Conversation
… policies, postage, and receipts
…eval in kv-repository and postage-service
Define a versioned CiphertextBinding structure and signing preimage that binds the ciphertext commitment, protected headers (algorithm/nonce/mac), suite identifier, and protocol version without duplicating raw ciphertext bytes in the signature input. New exports in signed-envelope.ts: - CiphertextBinding / SignedEnvelope types - buildCiphertextBinding(payload, commitment) - buildBindingPreimage(binding, network, version) - verifyBindingSignature(envelope, expectedSender, network, version) - assertBindingConsistency(envelope) Acceptance criteria verified: - Ciphertext substitution invalidates commitment verification - Ciphertext substitution invalidates signature verification - Signed preimage is versioned and deterministic (JCS + domain prefix) - Raw ciphertext bytes not duplicated in signature input - Tests cover substitution and commitment mismatch scenarios Tests: 20 new, 272 total passing, 0 regressions
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.
#closes #1707
PR: Envelope Signature Coverage for Ciphertext Binding
Branch:
issue-1707-ciphertext-binding-signatureBase:
issue-1495-concurrency-tokensIssue: #1707
Scope:
src/services/crypto/only — no API, relay, UI, Soroban contract, or routing changesProblem
SealedEnvelopehas the shape{ payload, ciphertext }. The wallet signs only thepayloadobject. Theciphertextfield is serialized as a separate, unsigned top-level field at relay submission time.This means an adversary who intercepts a relay submission can:
ciphertextbytes with arbitrary data.payload.content_commitment.payloadis still valid because the ciphertext is never covered.The signature format does not make the relationship between payload commitments and transmitted ciphertext unambiguous.
Solution
Introduce
CiphertextBinding— a deterministic, JCS-canonicalized object that the wallet signs alongside the payload. It binds:ciphertext_commitment(v1:sha256:hex:<hex>)protected_headers.nonceprotected_headers.macsuiteversionThe wallet signs the binding preimage, not raw ciphertext bytes:
A
SignedEnvelopeextendsSealedEnvelopewithbinding+signature. Recipients verify the Ed25519 signature over the preimage and optionally callassertBindingConsistencyto confirm the binding matches the live payload fields.Changed Files
[NEW]
src/services/crypto/signed-envelope.tsCiphertextBindingSignedEnvelopeBINDING_OPERATION"ciphertext_binding"buildCiphertextBinding(payload, commitment)buildBindingPreimage(binding, network?, version?)verifyBindingSignature(envelope, sender, network?, version?)assertBindingConsistency(envelope)[NEW]
tests/unit/crypto/signed-envelope.test.ts20 tests across 5 suites covering all acceptance criteria.
Security Properties
Important
All four acceptance criteria from #1707 are enforced by the implementation and verified by tests.
ciphertext_commitmentis SHA-256 of exact byte sequencecommitment mismatch › substitution attackbindingchanges → old Ed25519 sig is invalid over new bindingverifyBindingSignature › ciphertext substitutionbuildBindingPreimage › deterministic,version-sensitivebuildBindingPreimage › commitment hash (not raw ciphertext bytes)Note
assertBindingConsistencycatches a second class of attack where an adversary transmits a tamperedbindingfield alongside forged payload metadata but cannot forge a valid Ed25519 signature over the new binding.Test Results
Suites added:
Reviewer Checklist
CiphertextBindingfields match the spec in the issue descriptionStealth_Mail_Protocol:v1:<network>:ciphertext_binding:…) is acceptable for the wallet signing stepverifyBindingSignaturecorrectly gates onpayload.sender === expectedSender(defense-in-depth)assertBindingConsistencyis documented as a secondary check — primary security comes fromverifyBindingSignaturenode_modules/.bin/vitest run tests/unit/crypto/)Out of Scope (Separate Issues)
SignedEnvelopeinto the relay submission path (integration issue)buildBindingPreimagebefore submission (wallet integration issue)openEnvelopecallingverifyBindingSignatureon inbound messages (inbound integration issue)#closes