@sanning/proof 0.11.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/handoff.js +20 -1
- package/package.json +1 -1
- package/src/handoff.ts +21 -1
package/dist/handoff.js
CHANGED
|
@@ -40,6 +40,9 @@
|
|
|
40
40
|
// compared absent to absent and found them equal.
|
|
41
41
|
// - A pair whose two envelope signing keys are equal does not verify.
|
|
42
42
|
// - Every hand-off record a reader holds is read, not only the ones that pair.
|
|
43
|
+
// - A formed pair verifies only when each record names the other's signer
|
|
44
|
+
// (v1.16, A21), or it fails `counterparty_named`. Up to 0.11.0 grading
|
|
45
|
+
// never read whom either record names.
|
|
43
46
|
//
|
|
44
47
|
// THE THREE ATTACKS THE ADVERSARIAL GATE LANDED (proof#133, rulings 1 to 3),
|
|
45
48
|
// and they are one root cause: candidacy and the self-hand-off check compared
|
|
@@ -144,7 +147,7 @@ const HEX64 = /^[0-9a-fA-F]{64}$/;
|
|
|
144
147
|
const LOWER_HEX64 = /^[0-9a-f]{64}$/;
|
|
145
148
|
// The order a reader names the checks a formed pair failed, fixed so two
|
|
146
149
|
// kernels report one list rather than two orderings of it.
|
|
147
|
-
const CHECK_ORDER = ["message_hash", "sequence", "self_handoff"];
|
|
150
|
+
const CHECK_ORDER = ["message_hash", "sequence", "self_handoff", "counterparty_named"];
|
|
148
151
|
const VERDICT_RANK = { verified: 0, failed: 1, malformed: 2 };
|
|
149
152
|
// ASCII whitespace, listed rather than delegated: `String.trim()` and Python's
|
|
150
153
|
// `str.strip()` do not strip the same set (`U+FEFF` is whitespace to one and
|
|
@@ -478,6 +481,22 @@ function gradePair(subject, counterpart) {
|
|
|
478
481
|
failed.add("message_hash");
|
|
479
482
|
if (!sameNumber(subjectEvent.sequence, counterpartEvent.sequence))
|
|
480
483
|
failed.add("sequence");
|
|
484
|
+
// Each record names the OTHER's signer (v1.16, A21). Candidacy reads the key
|
|
485
|
+
// the subject names and nothing the candidate says, so up to and including
|
|
486
|
+
// 0.11.0 a sent record addressed to C paired `verified` with B's receipt of
|
|
487
|
+
// it, and a receipt naming C as its sender paired `verified` with A's send.
|
|
488
|
+
// Both halves of the naming are graded, each against the envelope key the
|
|
489
|
+
// other record was SIGNED with, compared as a key. The Python half is
|
|
490
|
+
// `_grade_pair`.
|
|
491
|
+
const [sent, received] = eventType(subject) === "handoff.sent" ? [subject, counterpart] : [counterpart, subject];
|
|
492
|
+
const sentNames = normalizedSigningKey(section(sent.record, "event").counterparty_public_key);
|
|
493
|
+
const receivedNames = normalizedSigningKey(section(received.record, "event").counterparty_public_key);
|
|
494
|
+
// The send names who received it.
|
|
495
|
+
if (sentNames !== normalizedSigningKey(received.publicKey))
|
|
496
|
+
failed.add("counterparty_named");
|
|
497
|
+
// The receipt names who sent it.
|
|
498
|
+
if (receivedNames !== normalizedSigningKey(sent.publicKey))
|
|
499
|
+
failed.add("counterparty_named");
|
|
481
500
|
const checks = CHECK_ORDER.filter((name) => failed.has(name));
|
|
482
501
|
return { verdict: checks.length > 0 ? "failed" : "verified", checks: [...checks] };
|
|
483
502
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanning/proof",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "TypeScript kernel of the Sanning verification stack: RFC 8785 (JCS) canonicalization, SHA-256, and Ed25519 verification for Verifiable Event Envelopes. Full-family verifier (inline + external commitment); accepts sanning.agent/v1 and sanning.events/v2. Conformance-gated byte-for-byte against the test-vectors corpus.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/handoff.ts
CHANGED
|
@@ -40,6 +40,9 @@
|
|
|
40
40
|
// compared absent to absent and found them equal.
|
|
41
41
|
// - A pair whose two envelope signing keys are equal does not verify.
|
|
42
42
|
// - Every hand-off record a reader holds is read, not only the ones that pair.
|
|
43
|
+
// - A formed pair verifies only when each record names the other's signer
|
|
44
|
+
// (v1.16, A21), or it fails `counterparty_named`. Up to 0.11.0 grading
|
|
45
|
+
// never read whom either record names.
|
|
43
46
|
//
|
|
44
47
|
// THE THREE ATTACKS THE ADVERSARIAL GATE LANDED (proof#133, rulings 1 to 3),
|
|
45
48
|
// and they are one root cause: candidacy and the self-hand-off check compared
|
|
@@ -147,7 +150,7 @@ const LOWER_HEX64 = /^[0-9a-f]{64}$/;
|
|
|
147
150
|
|
|
148
151
|
// The order a reader names the checks a formed pair failed, fixed so two
|
|
149
152
|
// kernels report one list rather than two orderings of it.
|
|
150
|
-
const CHECK_ORDER = ["message_hash", "sequence", "self_handoff"] as const;
|
|
153
|
+
const CHECK_ORDER = ["message_hash", "sequence", "self_handoff", "counterparty_named"] as const;
|
|
151
154
|
const VERDICT_RANK: Record<string, number> = { verified: 0, failed: 1, malformed: 2 };
|
|
152
155
|
|
|
153
156
|
// ASCII whitespace, listed rather than delegated: `String.trim()` and Python's
|
|
@@ -548,6 +551,23 @@ function gradePair(
|
|
|
548
551
|
const counterpartHash = String(counterpartEvent.message_hash ?? "").toLowerCase();
|
|
549
552
|
if (subjectHash !== counterpartHash) failed.add("message_hash");
|
|
550
553
|
if (!sameNumber(subjectEvent.sequence, counterpartEvent.sequence)) failed.add("sequence");
|
|
554
|
+
// Each record names the OTHER's signer (v1.16, A21). Candidacy reads the key
|
|
555
|
+
// the subject names and nothing the candidate says, so up to and including
|
|
556
|
+
// 0.11.0 a sent record addressed to C paired `verified` with B's receipt of
|
|
557
|
+
// it, and a receipt naming C as its sender paired `verified` with A's send.
|
|
558
|
+
// Both halves of the naming are graded, each against the envelope key the
|
|
559
|
+
// other record was SIGNED with, compared as a key. The Python half is
|
|
560
|
+
// `_grade_pair`.
|
|
561
|
+
const [sent, received] =
|
|
562
|
+
eventType(subject) === "handoff.sent" ? [subject, counterpart] : [counterpart, subject];
|
|
563
|
+
const sentNames = normalizedSigningKey(section(sent.record, "event").counterparty_public_key);
|
|
564
|
+
const receivedNames = normalizedSigningKey(
|
|
565
|
+
section(received.record, "event").counterparty_public_key,
|
|
566
|
+
);
|
|
567
|
+
// The send names who received it.
|
|
568
|
+
if (sentNames !== normalizedSigningKey(received.publicKey)) failed.add("counterparty_named");
|
|
569
|
+
// The receipt names who sent it.
|
|
570
|
+
if (receivedNames !== normalizedSigningKey(sent.publicKey)) failed.add("counterparty_named");
|
|
551
571
|
const checks = CHECK_ORDER.filter((name) => failed.has(name));
|
|
552
572
|
return { verdict: checks.length > 0 ? "failed" : "verified", checks: [...checks] };
|
|
553
573
|
}
|