kairos-chain 3.46.0 → 3.47.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +41 -0
- data/lib/kairos_mcp/version.rb +1 -1
- data/templates/skillsets/synoptis/bin/sdp_verify.rb +174 -0
- data/templates/skillsets/synoptis/lib/synoptis/anchoring/conventions/sdp-1.md +182 -0
- data/templates/skillsets/synoptis/lib/synoptis/anchoring/selective_disclosure.rb +540 -0
- data/templates/skillsets/synoptis/test/test_sdp_disclosure.rb +434 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e43541279a3d104b85372574c94f6fdf2d96188fb7de83d5a4d84c3f470634d7
|
|
4
|
+
data.tar.gz: 21b58d11561dd6d4177a7aa3d3832bdfe4fbde80ff2da2af198662d655a6fc81
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 41bc6c95594567c2e80ed006ea2bd21e7926361bf3cfb14fdf5a6b0a4aac17b9dca3f65faf17be1a4e86b16ce3fb9285af121d747fcdeac66eca58857d4af0bd
|
|
7
|
+
data.tar.gz: 77a5ac53384830598e90b408b4c737eb8549c219dfdeb47c38feb5939c46829c2b53dc9744da1a9914033521ff1fdf126f8d941989fe62857316863a75790e5f
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,47 @@ All notable changes to the `kairos-chain` gem will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
This project follows [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [3.47.0] - 2026-07-22
|
|
8
|
+
|
|
9
|
+
### Synoptis — selective disclosure sdp-1 (AUD-L4 slice 1)
|
|
10
|
+
|
|
11
|
+
Implements AUD-L4 design v0.3 (SDP-1..5, FROZEN, review-converged) slice 1
|
|
12
|
+
in the synoptis SkillSet. All additive: sdp-1 builds on khab-1/map-1/rpr-1
|
|
13
|
+
exactly as each prior slice built on its predecessors; no pre-existing file
|
|
14
|
+
changed.
|
|
15
|
+
|
|
16
|
+
- `conventions/sdp-1.md`: content-addressed selective-disclosure convention —
|
|
17
|
+
hash-based salted field-level disclosure (content-blinding: field values
|
|
18
|
+
hidden, record digest / field names / count public; the ZK membership
|
|
19
|
+
family is disclosed as out of scope for a later convention). Field
|
|
20
|
+
commitments (one salted digest per field, total coverage, `sdp-1/field`
|
|
21
|
+
domain separation), convention-determined disclosure profile (closed
|
|
22
|
+
schema; predicate + opened set + currency, `format` always opened),
|
|
23
|
+
presentation (closed schema per shape), three predicates
|
|
24
|
+
(typed-existence / claimed-verdict / conforming-verdict with foreignness,
|
|
25
|
+
anterior-tolerance assessment, and sibling-aware tolerance-target
|
|
26
|
+
coherence inside the checked predicate), extent-bounded currency scan
|
|
27
|
+
(issuer rule, residues disclosed unconditionally), computational
|
|
28
|
+
hiding/soundness base stated (no trusted setup).
|
|
29
|
+
- `selective_disclosure.rb`: build/parse/verify for field commitments,
|
|
30
|
+
profile, presentation (refuse-not-coerce, canonical-serialization
|
|
31
|
+
equality everywhere); signature verification from the record DIGEST alone
|
|
32
|
+
via the unchanged map-1 §1.1 attestation signature — blinded verdicts
|
|
33
|
+
without record content; conforming-verdict refuses (never degrades) when
|
|
34
|
+
operator credential or rpr-1 §2.1 assessment material is missing;
|
|
35
|
+
currency scan with unestablished-vs-unretracted discipline.
|
|
36
|
+
- `bin/sdp_verify.rb`: offline verifier (commit / binding / presentation /
|
|
37
|
+
profile / currency / convention), exit-code discipline (0/1/2), strict
|
|
38
|
+
intake (delete_suffix, canonical numerals).
|
|
39
|
+
- `test/test_sdp_disclosure.rb`: 61 design-constraint assertions
|
|
40
|
+
(SDP-1..5), including crafted-record shape refusal, verdict-vocabulary
|
|
41
|
+
closure, sibling-target coherence (rpr-1 §2.1 pooling agreement),
|
|
42
|
+
hiding of withheld values across artifacts and error paths, and
|
|
43
|
+
khab/map/rpr non-interference (37/75/76/88 regression green).
|
|
44
|
+
|
|
45
|
+
Implementation review: 3 rounds, R3 4/6 APPROVE + executable-probe
|
|
46
|
+
personas 2/2, zero remaining P0/P1 (dispositions in docs/drafts/).
|
|
47
|
+
|
|
7
48
|
## [3.46.0] - 2026-07-22
|
|
8
49
|
|
|
9
50
|
### Synoptis — reproduction endorsement rpr-1 (AUD-L3 slice 1)
|
data/lib/kairos_mcp/version.rb
CHANGED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# sdp_verify — offline verifier for sdp-1 selective-disclosure artifacts
|
|
5
|
+
# (SDP-1..5, aud_l4_selective_disclosure_design v0.3).
|
|
6
|
+
#
|
|
7
|
+
# Verifies with EXACTLY the disclosed trust base: the artifacts named on the
|
|
8
|
+
# command line plus the shipped sdp-1, rpr-1, and map-1 convention
|
|
9
|
+
# definitions. No registry, no network, no producer cooperation. (Authentic
|
|
10
|
+
# chain/log views are the caller's inputs; their integrity is the
|
|
11
|
+
# khab-1/map-1 surfaces' business.)
|
|
12
|
+
#
|
|
13
|
+
# Usage:
|
|
14
|
+
# sdp_verify.rb commit <record.json> [salts.json]
|
|
15
|
+
# builds the sdp-1 field-commitments auxiliary for a canonical record;
|
|
16
|
+
# prints the auxiliary record and (fresh or supplied) salts as JSON.
|
|
17
|
+
# sdp_verify.rb binding <aux.json> <record.json> <salts.json>
|
|
18
|
+
# checks the SDP-2 binding: every field digest and the record digest
|
|
19
|
+
# recompute from record + salts.
|
|
20
|
+
# sdp_verify.rb presentation <presentation.json> [operator_credential.json] [assessment.json]
|
|
21
|
+
# verifies a presentation. conforming-verdict REQUIRES both extras;
|
|
22
|
+
# assessment.json = {"targets":[...record strings...],
|
|
23
|
+
# "declarations":[{"tolerance":"...","position":N}...],
|
|
24
|
+
# "endorsement_position":N}.
|
|
25
|
+
# sdp_verify.rb profile <presentation.json>
|
|
26
|
+
# prints the disclosure profile and what it does/does not show.
|
|
27
|
+
# sdp_verify.rb currency <entries.json> <carrier_entry_hash> <extent>
|
|
28
|
+
# runs the sdp-1 §5 retraction scan over a supplied entry view.
|
|
29
|
+
# sdp_verify.rb convention
|
|
30
|
+
# prints the shipped sdp-1 convention digest.
|
|
31
|
+
#
|
|
32
|
+
# Exit status: 0 = VERIFIED/REPORT, 1 = REJECTED, 2 = usage / unresolvable.
|
|
33
|
+
|
|
34
|
+
require 'json'
|
|
35
|
+
require 'digest'
|
|
36
|
+
require_relative '../lib/synoptis/anchoring/entry'
|
|
37
|
+
require_relative '../lib/synoptis/anchoring/chain_credential'
|
|
38
|
+
require_relative '../lib/synoptis/anchoring/reproduction'
|
|
39
|
+
require_relative '../lib/synoptis/anchoring/selective_disclosure'
|
|
40
|
+
|
|
41
|
+
SD = Synoptis::Anchoring::SelectiveDisclosure
|
|
42
|
+
CRED = Synoptis::Anchoring::ChainCredential
|
|
43
|
+
|
|
44
|
+
def die(msg)
|
|
45
|
+
warn "sdp_verify: #{msg}"
|
|
46
|
+
exit 2
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def reject(msg)
|
|
50
|
+
puts "REJECTED: #{msg}"
|
|
51
|
+
exit 1
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Read a record artifact: at most one trailing newline is tolerated (file
|
|
55
|
+
# convenience); any other surrounding bytes stay in the string and fail the
|
|
56
|
+
# canonical check downstream (refuse-not-coerce). delete_suffix, not chomp:
|
|
57
|
+
# chomp also swallows CRLF, which would coerce a non-canonical artifact.
|
|
58
|
+
def read_file(path)
|
|
59
|
+
File.read(path).delete_suffix("\n")
|
|
60
|
+
rescue SystemCallError => e
|
|
61
|
+
die "cannot read #{path}: #{e.message}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def load_json(path, label)
|
|
65
|
+
parsed = JSON.parse(File.read(path))
|
|
66
|
+
die "#{path}: #{label} must be a JSON object or array, got #{parsed.class}" unless parsed.is_a?(Hash) || parsed.is_a?(Array)
|
|
67
|
+
parsed
|
|
68
|
+
rescue JSON::ParserError, SystemCallError => e
|
|
69
|
+
die "cannot read #{path}: #{e.message}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def load_json_hash(path, label)
|
|
73
|
+
parsed = load_json(path, label)
|
|
74
|
+
die "#{path}: #{label} must be a JSON object, got #{parsed.class}" unless parsed.is_a?(Hash)
|
|
75
|
+
parsed
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Canonical base-10 numerals only: leading zeros are refused, not
|
|
79
|
+
# reinterpreted (a non-canonical numeral is a malformed input, exit 2).
|
|
80
|
+
def strict_int(value, label)
|
|
81
|
+
die "#{label} must be a canonical base-10 integer, got #{value.inspect}" unless value.is_a?(String) && value.match?(/\A(0|[1-9]\d*)\z/)
|
|
82
|
+
Integer(value, 10)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
HEX64 = /\A[a-f0-9]{64}\z/
|
|
86
|
+
|
|
87
|
+
mode = ARGV.shift
|
|
88
|
+
|
|
89
|
+
case mode
|
|
90
|
+
when 'commit'
|
|
91
|
+
die 'usage: sdp_verify.rb commit <record.json> [salts.json]' unless (1..2).cover?(ARGV.size)
|
|
92
|
+
record = read_file(ARGV[0])
|
|
93
|
+
salts = ARGV[1] ? load_json_hash(ARGV[1], 'salts') : nil
|
|
94
|
+
built = begin
|
|
95
|
+
SD.build_field_commitments(record, salts: salts)
|
|
96
|
+
rescue SD::DisclosureError => e
|
|
97
|
+
reject e.message
|
|
98
|
+
end
|
|
99
|
+
puts JSON.pretty_generate(built)
|
|
100
|
+
warn 'NOTE: keep the salts private; each opened salt discloses exactly its field (sdp-1 §6).'
|
|
101
|
+
|
|
102
|
+
when 'binding'
|
|
103
|
+
die 'usage: sdp_verify.rb binding <aux.json> <record.json> <salts.json>' unless ARGV.size == 3
|
|
104
|
+
aux = read_file(ARGV[0])
|
|
105
|
+
record = read_file(ARGV[1])
|
|
106
|
+
salts = load_json_hash(ARGV[2], 'salts')
|
|
107
|
+
ok = begin
|
|
108
|
+
SD.verify_field_commitments(aux, record, salts)
|
|
109
|
+
rescue SD::DisclosureError => e
|
|
110
|
+
reject e.message
|
|
111
|
+
end
|
|
112
|
+
reject 'auxiliary is NOT checkably bound to the record (SDP-2: a bound-by-assertion auxiliary is a re-authoring)' unless ok
|
|
113
|
+
puts "VERIFIED: auxiliary is checkably bound to record #{Digest::SHA256.hexdigest(record)[0, 12]}… (total coverage, SDP-2)"
|
|
114
|
+
|
|
115
|
+
when 'presentation'
|
|
116
|
+
die 'usage: sdp_verify.rb presentation <presentation.json> [operator_credential.json] [assessment.json]' unless (1..3).cover?(ARGV.size)
|
|
117
|
+
pres = read_file(ARGV[0])
|
|
118
|
+
operator = ARGV[1] ? load_json_hash(ARGV[1], 'operator credential') : nil
|
|
119
|
+
assessment = ARGV[2] ? load_json_hash(ARGV[2], 'assessment material') : nil
|
|
120
|
+
report = begin
|
|
121
|
+
SD.verify_presentation(pres, operator_credential: operator, assessment: assessment)
|
|
122
|
+
rescue SD::DisclosureError, CRED::CredentialError => e
|
|
123
|
+
reject e.message
|
|
124
|
+
end
|
|
125
|
+
unless report[:valid]
|
|
126
|
+
puts "REJECTED: presentation does not verify (predicate #{report[:predicate]})"
|
|
127
|
+
report[:failures].each { |f| puts " - #{f}" }
|
|
128
|
+
exit 1
|
|
129
|
+
end
|
|
130
|
+
puts "VERIFIED: #{report[:predicate]} over committed record #{report[:record_sha256][0, 12]}…"
|
|
131
|
+
report[:opened].each { |n, v| puts " opened #{n} = #{v.inspect}" }
|
|
132
|
+
report[:notes].each { |n| puts " NOTE: #{n}" }
|
|
133
|
+
puts 'NOTE: soundness = sha256 collision resistance + Ed25519, no setup; hiding is computational, content-only (SDP-5, sdp-1 §6).'
|
|
134
|
+
|
|
135
|
+
when 'profile'
|
|
136
|
+
die 'usage: sdp_verify.rb profile <presentation.json>' unless ARGV.size == 1
|
|
137
|
+
pres = read_file(ARGV[0])
|
|
138
|
+
p = begin
|
|
139
|
+
SD.parse_presentation!(pres)
|
|
140
|
+
rescue SD::DisclosureError => e
|
|
141
|
+
reject e.message
|
|
142
|
+
end
|
|
143
|
+
profile = p['profile']
|
|
144
|
+
puts "profile (meaning fixed by sdp-1 §2, never producer gloss — SDP-4):"
|
|
145
|
+
puts " predicate: #{profile['predicate']}"
|
|
146
|
+
puts " opened: #{profile['opened'].join(', ')}"
|
|
147
|
+
puts " withheld: every other field of the referenced record (values only; names and count are public)"
|
|
148
|
+
puts " currency: #{profile['currency']}"
|
|
149
|
+
puts ' shows: existence and the opened values of ONE committed record'
|
|
150
|
+
puts ' never: non-existence, uniqueness, sibling records, contrary verdicts, producer selection (SDP-3)'
|
|
151
|
+
|
|
152
|
+
when 'currency'
|
|
153
|
+
die 'usage: sdp_verify.rb currency <entries.json> <carrier_entry_hash> <extent>' unless ARGV.size == 3
|
|
154
|
+
entries = load_json(ARGV[0], 'entries')
|
|
155
|
+
die "#{ARGV[0]}: entries must be a JSON array" unless entries.is_a?(Array)
|
|
156
|
+
carrier = ARGV[1].to_s
|
|
157
|
+
die 'carrier_entry_hash must be 64-char lowercase hex' unless carrier.match?(HEX64)
|
|
158
|
+
extent = strict_int(ARGV[2], 'extent')
|
|
159
|
+
scan = begin
|
|
160
|
+
SD.scan_currency(entries: entries, carrier_entry_hash: carrier, extent: extent)
|
|
161
|
+
rescue SD::DisclosureError => e
|
|
162
|
+
reject e.message
|
|
163
|
+
end
|
|
164
|
+
puts "REPORT: #{scan[:status]} (scanned extent #{scan[:scanned_extent]})"
|
|
165
|
+
puts " hits (positions): #{scan[:hits].join(', ')}" if scan[:hits]&.any?
|
|
166
|
+
puts " NOTE: #{scan[:note]}"
|
|
167
|
+
exit(scan[:status] == 'retracted' ? 1 : 0)
|
|
168
|
+
|
|
169
|
+
when 'convention'
|
|
170
|
+
puts "sdp-1 convention sha256: #{SD.convention_sha256}"
|
|
171
|
+
|
|
172
|
+
else
|
|
173
|
+
die 'usage: sdp_verify.rb commit|binding|presentation|profile|currency|convention …'
|
|
174
|
+
end
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# sdp-1 — KairosChain Selective Disclosure Convention, version 1
|
|
2
|
+
|
|
3
|
+
Status: committed verification convention (SDP-1..5 of
|
|
4
|
+
aud_l4_selective_disclosure_design v0.3, FROZEN). The SHA-256 over this file's
|
|
5
|
+
raw bytes is the convention integrity digest; every artifact that names
|
|
6
|
+
`sdp-1` commits it as its convention reference. A verifier holding a
|
|
7
|
+
definition whose digest does not match the committed one MUST treat the
|
|
8
|
+
artifact's convention as unresolvable and refuse to verify under it. Any
|
|
9
|
+
change to this convention is a new identifier (`sdp-2`, ...); this file is
|
|
10
|
+
never edited in place.
|
|
11
|
+
sdp-1 builds on khab-1 (record commitments, cumulative commitments, proofs),
|
|
12
|
+
map-1 (credentials, §1.1 attestation signatures, types, retraction), and
|
|
13
|
+
rpr-1 (endorsement records) and modifies none of them: every khab-1/map-1/
|
|
14
|
+
rpr-1 artifact is valid, and verifiable by its own procedure, with or without
|
|
15
|
+
any sdp-1 artifact present (SDP-2).
|
|
16
|
+
|
|
17
|
+
All record literals below are canonical JSON (keys sorted recursively,
|
|
18
|
+
`JSON.generate` compact form). A record is valid only in its canonical
|
|
19
|
+
serialization with exactly the fields shown — a non-canonical or extra-field
|
|
20
|
+
record is not an sdp-1 artifact and is ignored as noise (map-1 §4 precedent).
|
|
21
|
+
|
|
22
|
+
## 0. Scope and disclosed narrowness
|
|
23
|
+
|
|
24
|
+
sdp-1 realizes the mechanism family "hash-based salted field-level selective
|
|
25
|
+
disclosure": it blinds the *values* of fields of a committed canonical-JSON
|
|
26
|
+
record while the record's committed digest, its field *names*, and its field
|
|
27
|
+
*count* stay public. It does NOT blind which committed record an assertion
|
|
28
|
+
concerns: the AUD-L4 *membership* predicate family (showing that some record
|
|
29
|
+
is a member without revealing which) requires a zero-knowledge proving
|
|
30
|
+
system and is deliberately outside sdp-1 — a later convention covers it.
|
|
31
|
+
This narrowness is disclosed, not hidden (rpr-1 bit-identity precedent).
|
|
32
|
+
Because a record's committed digest is revealed, the khab-1 record
|
|
33
|
+
commitment IS that digest (khab-1 §1), so khab-1 inclusion and consistency
|
|
34
|
+
proofs over the referenced record apply unchanged, and the open-level
|
|
35
|
+
selection and currency reads (SDP-3) remain available to the verifier.
|
|
36
|
+
|
|
37
|
+
## 1. Field commitments (SDP-2 auxiliary, checkably bound)
|
|
38
|
+
|
|
39
|
+
{"fields":{"<name>":"<64-hex>",...},"format":"sdp-1/field-commitments",
|
|
40
|
+
"record_sha256":"<64-hex>"}
|
|
41
|
+
|
|
42
|
+
`record_sha256` is the SHA-256 of the target record string (= its khab-1
|
|
43
|
+
record commitment). `fields` carries one entry per top-level field of the
|
|
44
|
+
target record — coverage is total, so the auxiliary determines exactly one
|
|
45
|
+
record shape and an omitted field cannot be hidden by omission. Field names
|
|
46
|
+
match `[a-z0-9_]+`. Each field digest is the SHA-256 of the UTF-8 bytes of:
|
|
47
|
+
|
|
48
|
+
sdp-1/field|<salt>|<name>|<canonical JSON of the value>
|
|
49
|
+
|
|
50
|
+
where `<salt>` is 32-char lowercase hex (16 random bytes, fresh per field
|
|
51
|
+
per auxiliary). The `sdp-1/field` domain prefix is role separation (MPR-3
|
|
52
|
+
register): a field digest cannot verify as a record commitment or vice
|
|
53
|
+
versa. The auxiliary is committed as an ordinary internal-chain record
|
|
54
|
+
alongside its target; both records' membership and order are khab-1's
|
|
55
|
+
business, unchanged.
|
|
56
|
+
|
|
57
|
+
Checkable binding (SDP-2): a holder of the target record and the salts can
|
|
58
|
+
recompute `record_sha256` and every field digest; the auxiliary commits the
|
|
59
|
+
same content the record commits, or the recomputation fails. An auxiliary
|
|
60
|
+
whose digests do not recompute is not a conforming sdp-1 artifact. Residue
|
|
61
|
+
disclosed: binding checkability is available to holders of the record and
|
|
62
|
+
salts (the producer, and anyone the producer opens to); a third party holds
|
|
63
|
+
the binding as committed material whose consistency is attested by the
|
|
64
|
+
recomputations of others — the MPR-4 production/verification asymmetry.
|
|
65
|
+
|
|
66
|
+
## 2. Disclosure profile (SDP-4, closed schema)
|
|
67
|
+
|
|
68
|
+
{"currency":"scan-checkable","format":"sdp-1/profile",
|
|
69
|
+
"opened":["format","verdict"],"predicate":"claimed-verdict"}
|
|
70
|
+
|
|
71
|
+
`predicate` is one of `typed-existence` | `claimed-verdict` |
|
|
72
|
+
`conforming-verdict`. `currency` is one of `scan-checkable` |
|
|
73
|
+
`unestablished` (SDP-3: which currency reading the presentation supports is
|
|
74
|
+
declared, never implied). `opened` is the sorted, duplicate-free list of
|
|
75
|
+
opened field names and MUST include `format` (the record's format field is
|
|
76
|
+
always opened, so the closed schema of the referenced record kind is
|
|
77
|
+
readable and coverage is checkable against it). The schema is closed: no
|
|
78
|
+
other fields exist, so a profile cannot carry producer gloss — a profile
|
|
79
|
+
means what this section says a profile of its form means (SDP-4 pinning),
|
|
80
|
+
and a presentation's profile is checked against its actual opened set, so a
|
|
81
|
+
profile that overstates or understates what is opened fails verification
|
|
82
|
+
(statement-determining, SDP-4).
|
|
83
|
+
|
|
84
|
+
What every sdp-1 profile discloses by construction (SDP-3): the proof shows
|
|
85
|
+
the named predicate over the named committed record and withholds the values
|
|
86
|
+
of every field not listed in `opened`; it shows nothing about other records,
|
|
87
|
+
contrary verdicts, or the producer's selection among presentable records.
|
|
88
|
+
|
|
89
|
+
## 3. Presentation (offline artifact, never committed)
|
|
90
|
+
|
|
91
|
+
base fields, always present:
|
|
92
|
+
|
|
93
|
+
{"aux_record":"<field-commitments record string>",
|
|
94
|
+
"format":"sdp-1/presentation",
|
|
95
|
+
"opened":{"<name>":{"salt":"<32-hex>","value":<JSON value>},...},
|
|
96
|
+
"profile":{...profile object...}}
|
|
97
|
+
|
|
98
|
+
additionally, exactly when `profile.predicate` is `claimed-verdict` or
|
|
99
|
+
`conforming-verdict`: `"credential"` (the endorser's map-1 credential
|
|
100
|
+
object) and `"signature"` (128-hex, the map-1 §1.1 attestation signature
|
|
101
|
+
over the referenced endorsement record). Additionally, exactly when
|
|
102
|
+
`profile.currency` is `scan-checkable`: `"carrier_entry_hash"` (64-hex, the
|
|
103
|
+
anchor-log entry that carried the referenced record's attestation — the
|
|
104
|
+
producer's disclosure that makes the retraction scan runnable). The schema
|
|
105
|
+
is closed per shape (rpr-1 per-mode precedent).
|
|
106
|
+
|
|
107
|
+
`opened` keys must equal `profile.opened` exactly. Each opened field
|
|
108
|
+
verifies by recomputing §1's field digest from `salt`, the name, and the
|
|
109
|
+
canonical JSON of `value` against the auxiliary's committed digest.
|
|
110
|
+
|
|
111
|
+
## 4. Predicates (SDP-1 bounds)
|
|
112
|
+
|
|
113
|
+
- `typed-existence`: a committed record of the opened `format` exists with
|
|
114
|
+
digest `record_sha256`. Membership in an anchored state is shown, when
|
|
115
|
+
wanted, by a khab-1 inclusion proof over `record_sha256` — unchanged, not
|
|
116
|
+
part of the presentation.
|
|
117
|
+
- `claimed-verdict`: the opened `format` must be `rpr-1/endorsement` and
|
|
118
|
+
`verdict` must be opened. The signature verifies under the presented
|
|
119
|
+
credential over the signing string
|
|
120
|
+
|
|
121
|
+
map-1/attestation|<credential digest>|<record_sha256>
|
|
122
|
+
|
|
123
|
+
which requires NO record content (map-1 §1.1 commits the payload by
|
|
124
|
+
digest). The claim is exactly: this credential's holder claimed this
|
|
125
|
+
verdict in this committed endorsement — the weaker predicate under its
|
|
126
|
+
own name (SDP-1 face/substance rule). No foreignness, anteriority, or
|
|
127
|
+
conformance is asserted.
|
|
128
|
+
- `conforming-verdict`: `claimed-verdict`, and additionally
|
|
129
|
+
`adjudication_mode`, `target_sha256`, and `tolerance_sha256` are opened
|
|
130
|
+
(plus `procedure_sha256` exactly when the opened mode is `procedure`),
|
|
131
|
+
and verification REQUIRES the operator credential (foreignness: endorser
|
|
132
|
+
credential digest ≠ operator credential digest, rpr-1 §3) and the rpr-1
|
|
133
|
+
§2.1 declaration-set material (targets, declarations with positions, the
|
|
134
|
+
endorsement's committed position); the invoked tolerance must assess as
|
|
135
|
+
conforming, and it must be bound to the endorsement's opened target or to
|
|
136
|
+
a sibling target sharing its committed computation identification (the
|
|
137
|
+
rpr-1 §2.1 pooling rule: a sibling menu is one menu; a tolerance bound to
|
|
138
|
+
an unrelated computation fails), decided from the supplied target records.
|
|
139
|
+
Where the material is not supplied, or the coherence is undecidable in the
|
|
140
|
+
supplied view, verification fails — refuse, not degrade (SDP-1 upward
|
|
141
|
+
bound: the open form's conformance conditions are inside the checked
|
|
142
|
+
predicate, never alongside it).
|
|
143
|
+
|
|
144
|
+
## 5. Currency scan (SDP-3)
|
|
145
|
+
|
|
146
|
+
Given a view of anchor-log entries (each with `entry_hash`,
|
|
147
|
+
`attestation_type`, `depositor`, `position`, and retraction `metadata`), the
|
|
148
|
+
scan reports whether a `retraction` entry from the carrier's own depositor
|
|
149
|
+
(map-1 §3 issuer rule) targets `carrier_entry_hash` at a committed position
|
|
150
|
+
at or before a named extent. The verdict is `retracted` / `unretracted` up
|
|
151
|
+
to that extent, or `unestablished` where the carrier entry — or its
|
|
152
|
+
depositor, without which the issuer rule is undecidable — is not in the
|
|
153
|
+
supplied view. Duplicate views of one committed entry are one entry.
|
|
154
|
+
Same-issuer retractions beyond the extent or without a decidable position,
|
|
155
|
+
and non-issuer entries targeting the carrier (which retract nothing), are
|
|
156
|
+
disclosed as residue lines, never silently dropped. `unretracted` speaks
|
|
157
|
+
only to the scanned view and extent — absence beyond them proves nothing
|
|
158
|
+
(MPR-9 register). A profile declaring `currency: "unestablished"` supports
|
|
159
|
+
no scan and says so on its face.
|
|
160
|
+
|
|
161
|
+
## 6. Hiding and soundness base (SDP-1/SDP-5)
|
|
162
|
+
|
|
163
|
+
Hiding is computational and content-only: a withheld value is hidden exactly
|
|
164
|
+
as far as its field's salt is secret and sha256 preimage resistance holds —
|
|
165
|
+
16-byte random salts make guess-and-confirm infeasible even for low-entropy
|
|
166
|
+
values (the MPR-2 caveat is answered by the salt, and returns in full if a
|
|
167
|
+
salt is reused or leaks). What sdp-1 never hides: the record's committed
|
|
168
|
+
digest, field names and count, the profile, the producer's credential where
|
|
169
|
+
presented, and the fact of presentation itself — a presentation's existence,
|
|
170
|
+
timing, and provenance are outside any profile's promise (SDP-1). Soundness
|
|
171
|
+
rests on SHA-256 collision resistance and Ed25519 unforgeability only; there
|
|
172
|
+
is no setup to trust (SDP-5: transparent, stated rather than implied).
|
|
173
|
+
|
|
174
|
+
## 7. Verification procedure and trust base
|
|
175
|
+
|
|
176
|
+
All sdp-1 verification needs only: the artifacts named above, this
|
|
177
|
+
definition, the map-1 definition (credentials, signatures, retraction), the
|
|
178
|
+
rpr-1 definition (for verdict predicates), and authentic views of the
|
|
179
|
+
logs/chains the artifacts reference. No registry, no network, no producer
|
|
180
|
+
cooperation for verification — production of presentations, like production
|
|
181
|
+
of proofs, remains the producer's act (MPR-4 asymmetry), and the producer's
|
|
182
|
+
selection among presentable records is invisible by construction (SDP-3).
|