Courier vectors: decode the two keys nothing was reading

Cross-model review (codex) on the previous commits.

`packet.payloadIs` and `signature.verify` were the only non-comment keys the
Decodable shapes did not declare, so either could be renamed or deleted from the
published file and every test stayed green — the exact staleness this PR exists
to prevent, surviving in the two fields that tell a second implementer what to
feed the verifier.

Both are declared now, and `payloadIs` is checked rather than merely present:
it states a byte count, and that count is asserted against the real encoded
payload. Prose that states a number is a claim like any other.

Verified by mutation: renaming either key fails decoding, and stating 73 bytes
where the payload is 74 fails the length assertion alone.

Codex also read the pre-fix diff and re-reported the unchecked Data indexing
already fixed two commits ago, and claimed Ed25519 signing is deterministic so
the non-determinism assertion should fail. The latter is wrong for CryptoKit
specifically: `Curve25519.Signing` randomizes rather than following RFC 8032's
deterministic construction, which the test asserts and the suite confirms on
every run. No change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ecgang 2026-07-26 11:55:42 -07:00
parent 29ebbcfb62
commit 44f8456c70

View File

@ -104,6 +104,9 @@ struct CourierVectorTests {
let version: UInt8
let type: String
let ttlOnWire: UInt8
/// Declared so it cannot be renamed or dropped unnoticed; the
/// byte count it names is asserted against the real payload.
let payloadIs: String
}
struct Flags: Decodable {
let unsignedUnpadded: String
@ -124,6 +127,9 @@ struct CourierVectorTests {
let publicKey: String
let signatureLength: Int
let deterministic: Bool
/// Declared for the same reason as `payloadIs`: an undeclared key
/// can vanish from the published file and every test stays green.
let verify: String
}
let inputs: Inputs
@ -177,6 +183,12 @@ struct CourierVectorTests {
#expect(encoded.hexEncodedString() == v.envelopeTLV.encoded)
#expect(encoded.count == v.envelopeTLV.encodedLength)
// The prose in `packet.payloadIs` states this byte count. Prose that
// states a number is a claim like any other, and this is the one place
// it can be checked rather than trusted.
#expect(v.packetSigning.packet.payloadIs.contains("\(encoded.count) bytes"),
"packet.payloadIs disagrees with the real payload length")
// 0x02 carries 000001a3185c5000 == 1_800_000_000_000 ms, not seconds.
let decoded = try #require(CourierEnvelope.decode(encoded))
#expect(decoded.expiry == v.inputs.expiryMillis)
@ -302,6 +314,9 @@ struct CourierVectorTests {
let a = try key.signature(for: preimage)
let b = try key.signature(for: preimage)
#expect(v.signature.deterministic == false)
// The published instruction must keep naming the field it points at,
// so renaming `signingPreimage` cannot leave it dangling.
#expect(v.signature.verify.contains("signingPreimage"))
#expect(Data(a) != Data(b), "CryptoKit Ed25519 signing is randomized")
#expect(key.publicKey.isValidSignature(a, for: preimage))
#expect(key.publicKey.isValidSignature(b, for: preimage))