carlos / contra Public

Clone
git clone https://amadan.net/carlos/contra

Plain git — no account needed to clone.

Download

Download this file

1{
2 "format": "contra-golden-vectors",
3 "version": 1,
4 "spec": "PROTOCOL.md; wire formats pinned in discussion 19",
5 "generator": "vectors/gen/gen.c against OpenSSL 3.5.6 7 Apr 2026",
6 "note": "Every input here is generated: fixture(label) = SHA-256(\"contra/v1/vectors/\" || label). Nothing in this file is a real secret, and nothing in it may be reused as one.",
7 "binding": "The Go, JS and Swift crypto suites must all pass this file. Changing a value here is changing the protocol.",
8 "external_anchors": {
9 "note": "Published third-party vectors. gen.c recomputes each one and aborts on mismatch before generating anything below.",
10 "sources": ["PHC argon2 reference vectors", "RFC 5869 cases 1 and 3", "RFC 4231 case 1", "NIST CAVP AES-256-GCM"]
11 },
12 "argon2id": {
13 "params": {"m_kib": 65536, "t": 3, "p": 1, "tag_len": 32},
14 "floor": {"m_kib": 65536, "t": 3, "note": "clients refuse anything weaker a server offers"},
15 "cases": [
16 {
17 "name": "S_pw",
18 "passphrase_utf8": "contra-golden-vector-passphrase-do-not-use-8f3a1c",
19 "passphrase_hex": "636f6e7472612d676f6c64656e2d766563746f722d706173737068726173652d646f2d6e6f742d7573652d386633613163",
20 "salt_hex": "962c1e2ca2b4c0602e6ec706e76e3eac",
21 "out_hex": "6bf83f20da63fb1c818ce0f12e93294ba999b4ad156a7e5ae680f9f38fdd493b"
22 }
23 ]
24 },
25 "hkdf": {
26 "construction": "RFC 5869 extract-then-expand, SHA-256; an absent salt is zero-length; info is the label's ASCII bytes with no NUL",
27 "cases": [
28 {
29 "name": "seed_login",
30 "info": "contra/v1/login",
31 "ikm_hex": "6bf83f20da63fb1c818ce0f12e93294ba999b4ad156a7e5ae680f9f38fdd493b",
32 "salt_hex": "",
33 "l": 32,
34 "okm_hex": "4f2b905bcff9d01c15bbb82bb0a9d26a1267f35278928d1bd38e8c838ef68b8a"
35 },
36 {
37 "name": "KEK_pw",
38 "info": "contra/v1/kek",
39 "ikm_hex": "6bf83f20da63fb1c818ce0f12e93294ba999b4ad156a7e5ae680f9f38fdd493b",
40 "salt_hex": "f60fb281e8c72f6725add4cbd40e7b08",
41 "l": 32,
42 "okm_hex": "e70a2f643ee0dc6123d042ca574b44994135d7776016e3d181fc32f93db40d82"
43 },
44 {
45 "name": "seed_rc_login",
46 "info": "contra/v1/rc-login",
47 "ikm_hex": "70da5ffc983510bba4672030946b9eed",
48 "salt_hex": "",
49 "l": 32,
50 "okm_hex": "46b18c0c2a54c5ef6baeeda49ab42fd24ae8401912020cf94c02a51f1436240b"
51 },
52 {
53 "name": "KEK_rc",
54 "info": "contra/v1/rc-kek",
55 "ikm_hex": "70da5ffc983510bba4672030946b9eed",
56 "salt_hex": "",
57 "l": 32,
58 "okm_hex": "58c5e4bd32d767d48a63d3f77ed67bad6c1fb4017d90a2f098cb32e8b87ff27b"
59 },
60 {
61 "name": "KEK_prf",
62 "info": "contra/v1/prf-kek",
63 "ikm_hex": "6f926e3f71aec7803ffeeef8598e91de4195a42067688c8f4e3fd24c00c50c49",
64 "salt_hex": "ce414df9c26826e10c1c4f359823885eb5eb39f89ead15583cade016d317f276",
65 "l": 32,
66 "okm_hex": "25a832e73062849b768e245a28a1139f3a0171d41a05a34ce8d2615e7ecacad9"
67 }
68 ]
69 },
70 "kcv": {
71 "construction": "HMAC-SHA-256(KEK, \"contra/v1/kcv\")[..16]",
72 "cases": [
73 {"name": "KCV_pw", "kek_hex": "e70a2f643ee0dc6123d042ca574b44994135d7776016e3d181fc32f93db40d82", "kcv_hex": "fc6587261be8f190edd03ee21eda38b4"},
74 {"name": "KCV_rc", "kek_hex": "58c5e4bd32d767d48a63d3f77ed67bad6c1fb4017d90a2f098cb32e8b87ff27b", "kcv_hex": "a4e31d3daede8f7051c4ff6a9cea876b"},
75 {"name": "KCV_prf", "kek_hex": "25a832e73062849b768e245a28a1139f3a0171d41a05a34ce8d2615e7ecacad9", "kcv_hex": "a6a270fb61f6a4dc3c8378d76784c8bc"}
76 ]
77 },
78 "p256_from_seed": {
79 "construction": "candidate_i = HKDF-SHA-256(ikm=seed, salt=\"\", info=\"contra/v1/ec-p256\" || byte(i)); accept when 1 <= OS2IP(candidate) <= n-1, else i += 1",
80 "public_key_encoding": "SEC1 uncompressed, 0x04 || X || Y",
81 "cases": [
82 {
83 "name": "LK_pw",
84 "seed_hex": "4f2b905bcff9d01c15bbb82bb0a9d26a1267f35278928d1bd38e8c838ef68b8a",
85 "candidates_tried": 1,
86 "candidates": ["ae4fd50980acd2da69b6b3d77be8f4347b36d5429639f42e0753e784718cc05b"],
87 "d_hex": "ae4fd50980acd2da69b6b3d77be8f4347b36d5429639f42e0753e784718cc05b",
88 "public_uncompressed_hex": "0465b117b08f92789048944fced0df2343d93b77e8c92448a3f2be170ea91755066a7f789fdf979c17ed782cf9f24cdec565ad8fe752e9f24e974e4c5270cb908f"
89 },
90 {
91 "name": "LK_rc",
92 "seed_hex": "46b18c0c2a54c5ef6baeeda49ab42fd24ae8401912020cf94c02a51f1436240b",
93 "candidates_tried": 1,
94 "candidates": ["5e849fc53c753f9bd0f76ad1b3d3d997c1b7837a1ee733666a69679f2fca9e01"],
95 "d_hex": "5e849fc53c753f9bd0f76ad1b3d3d997c1b7837a1ee733666a69679f2fca9e01",
96 "public_uncompressed_hex": "048b58c6f080a5fe442a996ad8c7104fc2ecc23fac14d5bfb834fbf949640dae7a4ff41f793d4d7ae97103fe8d5d13faf99b46c52f46a36ce5416d9346b8fac90f"
97 },
98 {
99 "name": "rejects_at_i0",
100 "seed_hex": "636f6e7472612f76312f766563746f722d73656172636821000000028d6ed394",
101 "candidates_tried": 2,
102 "candidates": ["ffffffff664667834724f9a77479bf20190521865ac9486dcc6c225972783d8b", "5868322caaf160cdb5b9289459bd504c3c48f6397bade3c3bf07a7f2deefd8e8"],
103 "d_hex": "5868322caaf160cdb5b9289459bd504c3c48f6397bade3c3bf07a7f2deefd8e8",
104 "public_uncompressed_hex": "040fa92cfa882ba8b5d2977fcd7d5805751d54c3530daabce40f3f8ccfdc5715ddb75a2e638f11f685eebff0ac49872d0f8033d5c871202c796ec6400acf1c9afa"
105 }
106 ]
107 },
108 "p256_rejecting_seed": {
109 "note": "A rejection has probability about 2^-32, so this seed was searched for. Without it the rejection branch is dead code in all three languages.",
110 "seed_recipe": "\"contra/v1/vector-search!\" || u64be(k)",
111 "k": 10962785172,
112 "seed_hex": "636f6e7472612f76312f766563746f722d73656172636821000000028d6ed394"
113 },
114 "crockford": {
115 "alphabet": "0123456789ABCDEFGHJKMNPQRSTVWXYZ",
116 "packing": "MSB-first over the raw bytes, left-aligned; 16 bytes -> 26 symbols with two zero pad bits. Decoding rejects a non-zero pad, so every value has exactly one encoding.",
117 "normalize": "strip '-' and whitespace, uppercase, O->0, I->1, L->1; U is not in the alphabet and is an error",
118 "encode_cases": [
119 {"bytes_hex": "00000000000000000000000000000000", "symbols": "00000000000000000000000000"},
120 {"bytes_hex": "ffffffffffffffffffffffffffffffff", "symbols": "ZZZZZZZZZZZZZZZZZZZZZZZZZW"},
121 {"bytes_hex": "f60fb281e8c72f6725add4cbd40e7b08", "symbols": "YR7V50F8RWQPE9DDTK5X83KV10"},
122 {"bytes_hex": "70da5ffc983510bba4672030946b9eed", "symbols": "E3D5ZZ4R6M8BQ93740R98TWYXM"}
123 ],
124 "normalize_cases": [
125 {"input": "c1-oi1l-0O1I", "normalized": "C101110011"},
126 {"input": " A1 oL Li ", "normalized": "A10111"},
127 {"input": "c1-abc-def", "normalized": "C1ABCDEF"},
128 {"input": "C1-UUUU", "error": "character outside the Crockford alphabet"},
129 {"input": "c1?abc", "error": "character outside the Crockford alphabet"}
130 ],
131 "decode_cases": [
132 {"symbols": "E3D5ZZ4R6M8BQ93740R98TWYXM", "bytes_hex": "70da5ffc983510bba4672030946b9eed"},
133 {"symbols": "E3D5ZZ4R6M8BQ93740R98TWYXN", "error": "non-zero pad bits in the final symbol", "rejected": true}
134 ]
135 },
136 "printed_code": {
137 "form": "tag(2) || data(26) || checksum(4), printed as TAG-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX",
138 "checksum": "first 20 bits, MSB-first, of SHA-256(payload_bytes) -- over the 16 raw bytes, not the string",
139 "cases": [
140 {"name": "account_key", "tag": "A1", "payload_hex": "f60fb281e8c72f6725add4cbd40e7b08", "checksum20": 543112, "normalized": "A1YR7V50F8RWQPE9DDTK5X83KV10GJC8", "printed": "A1-YR7V5-0F8RW-QPE9D-DTK5X-83KV1-0GJC8"},
141 {"name": "recovery_code", "tag": "C1", "payload_hex": "70da5ffc983510bba4672030946b9eed", "checksum20": 573888, "normalized": "C1E3D5ZZ4R6M8BQ93740R98TWYXMHGE0", "printed": "C1-E3D5Z-Z4R6M-8BQ93-740R9-8TWYX-MHGE0"}
142 ],
143 "repair": {
144 "note": "substitute one character, then brute-force all 30 payload positions x 32 symbols against the checksum; return every survivor in position-then-alphabet order for the caller to try against the KCV",
145 "correct_normalized": "C1E3D5ZZ4R6M8BQ93740R98TWYXMHGE0",
146 "typo_normalized": "C1E3D5Z84R6M8BQ93740R98TWYXMHGE0",
147 "typo_position": 7,
148 "candidates": ["C1E3D5ZZ4R6M8BQ93740R98TWYXMHGE0"],
149 "candidate_count": 1,
150 "correct_is_a_candidate": true
151 }
152 },
153 "aead": {
154 "algorithm": "AES-256-GCM, 96-bit nonce, 128-bit tag",
155 "aad": "\"contra/v1/aad\" || 0x00 || u32be(len(scope_id)) || scope_id || u32be(len(object_type)) || object_type || u32be(len(object_id)) || object_id || u64be(version)",
156 "scope_id": "the account id for account-scoped objects, the vault id for vault-scoped ones",
157 "account_id_hex": "b22c6a5eae1be9d6a773f474fd0532b0",
158 "vault_id_hex": "d7331f78b34eb0cc299252e2624070db",
159 "rk_hex": "e3769479962198ef9dbcf21e4822b0e2d45f9918f1e7bf86aa6208fc3e3ad3c6",
160 "wraps": [
161 {
162 "name": "W_pw",
163 "object_type": "wrap.pw",
164 "kek_hex": "e70a2f643ee0dc6123d042ca574b44994135d7776016e3d181fc32f93db40d82",
165 "kcv_hex": "fc6587261be8f190edd03ee21eda38b4",
166 "wrap_id_hex": "cc715de83e6bec8114d5478e1b2e13d6",
167 "version": 1,
168 "nonce_hex": "63ca9a59270f1867de916493",
169 "aad_hex": "636f6e7472612f76312f6161640000000010b22c6a5eae1be9d6a773f474fd0532b000000007777261702e707700000010cc715de83e6bec8114d5478e1b2e13d60000000000000001",
170 "ciphertext_hex": "54960d310960a2b99c8df592b1017490c7e89507caef806e00e32ea4263aba34",
171 "tag_hex": "b270200424ec37c3a06158abc13a2c00"
172 },
173 {
174 "name": "W_rc",
175 "object_type": "wrap.rc",
176 "kek_hex": "58c5e4bd32d767d48a63d3f77ed67bad6c1fb4017d90a2f098cb32e8b87ff27b",
177 "kcv_hex": "a4e31d3daede8f7051c4ff6a9cea876b",
178 "wrap_id_hex": "7d4f2401a54f0af0f9c2123e89ce940e",
179 "version": 1,
180 "nonce_hex": "5758cf37dbe4daad674c8ce7",
181 "aad_hex": "636f6e7472612f76312f6161640000000010b22c6a5eae1be9d6a773f474fd0532b000000007777261702e7263000000107d4f2401a54f0af0f9c2123e89ce940e0000000000000001",
182 "ciphertext_hex": "3a0c3081efb8d7c4224e299d7aa4f1ed2e502b10f3b01925de4af09a48c61eed",
183 "tag_hex": "9bb37b5e3d79fd21d91907ca261aee75"
184 },
185 {
186 "name": "W_prf",
187 "object_type": "wrap.prf",
188 "kek_hex": "25a832e73062849b768e245a28a1139f3a0171d41a05a34ce8d2615e7ecacad9",
189 "kcv_hex": "a6a270fb61f6a4dc3c8378d76784c8bc",
190 "wrap_id_hex": "be8b97ce6d27b2fb61229efc81f502b4",
191 "version": 1,
192 "nonce_hex": "2ff8fef97b48f6969b78b23f",
193 "aad_hex": "636f6e7472612f76312f6161640000000010b22c6a5eae1be9d6a773f474fd0532b000000008777261702e70726600000010be8b97ce6d27b2fb61229efc81f502b40000000000000001",
194 "ciphertext_hex": "0b5f5c20153730681bf09e0740b64b7f49f6d3180f1365dd3bead4fffcbe06ea",
195 "tag_hex": "0900826fc6463dbdf94fe5cacbf1c585"
196 }
197 ],
198 "item": {
199 "scope": "vault",
200 "vault_id_hex": "d7331f78b34eb0cc299252e2624070db",
201 "object_type": "item",
202 "item_id_hex": "4580c14ff986936588b14e66e247978d",
203 "version": 1,
204 "k_vault_hex": "576894008c1a94f71704db728d37bfa9f0023cca4fd8d2ae48f6af81a4b959a5",
205 "nonce_hex": "50e4e9c4a5166e560d453550",
206 "aad_hex": "636f6e7472612f76312f6161640000000010d7331f78b34eb0cc299252e2624070db000000046974656d000000104580c14ff986936588b14e66e247978d0000000000000001",
207 "plaintext_utf8": "{\"title\":\"Generated vector item\",\"username\":\"vector@example.invalid\",\"secret\":\"not-a-real-value\"}",
208 "plaintext_hex": "7b227469746c65223a2247656e65726174656420766563746f72206974656d222c22757365726e616d65223a22766563746f72406578616d706c652e696e76616c6964222c22736563726574223a226e6f742d612d7265616c2d76616c7565227d",
209 "ciphertext_hex": "47296118e291596d6ba9d4c6919abb042b01888060a0d6cf13bf224ccf7cc57678945ec6ae628deaff76f21a79463fcc6b3f31a222902be2a23497c86cad77864e40f5cf00db37bacf4580fe0e6f5a969eb4bd8a84fff06ef87b85ca2d9d86200d",
210 "tag_hex": "8c033da48e3a51c5a8e7618c95cba27f"
211 }
212 },
213 "handoff": {
214 "note": "PROTOCOL.md rung 1: an enrolled device seals the Account Key to a fresh device's ephemeral public key, and the server relays a blob it cannot open",
215 "shared_secret": "X(d*P), big-endian at the field width; Y discarded, per SEC 1 3.3.1",
216 "key": "HKDF-SHA-256(ikm=shared_secret, salt=ephemeral_public || recipient_public, info=\"contra/v1/ecies\", L=32)",
217 "envelope": "ephemeral_public(65) || nonce(12) || ciphertext || tag(16)",
218 "recipient_seed_hex": "9b99cffdf8c8336ee1052a5d23d8c6a89233b6f4b8dce3abb67467797ff5f47c",
219 "recipient_scalar_hex": "7066a8a9a92ab829b8410497f8832950dd2c873d27c8e8719fd07b1bdb2c2689",
220 "recipient_public_hex": "04a3bd4385af0b7002d753e994b46b670b515961d7c937be9bd67bb32bfc195fbd00893a7972b680c821681c479e54bfc36b0bff3555883d36d836914bc942eef3",
221 "ephemeral_seed_hex": "80d827ebf9b6cbd89ebdc4e883f1f6604e55ee6639ff0523c89cd2ce4cbfd069",
222 "ephemeral_scalar_hex": "29bb73bd46d37937e6aec53e555e8121248dd20ca2276c7a62a80e1294fe0f12",
223 "ephemeral_public_hex": "04f32e19a10b4812c4b681abf4e0f695dfcd7c409de8bc3432f2678c6bba111cec0bcdd4499e5b0dbdf422e122ee3aa8de1bbbae9601cb8e724ff29d480c990da4",
224 "shared_secret_hex": "2c5a4aaf13ca4aceeeea13a4cb51992086b61d2a00fcd3c33e0c01baf69d9725",
225 "key_hex": "f7e866f04455d3ad3387fa20096c3d4a4762e16893390f7ce6b862c9857a34b9",
226 "account_id_hex": "b22c6a5eae1be9d6a773f474fd0532b0",
227 "object_type": "handoff",
228 "version": 1,
229 "nonce_hex": "f3d0c570acc6bb78bdb8f27b",
230 "aad_hex": "636f6e7472612f76312f6161640000000010b22c6a5eae1be9d6a773f474fd0532b00000000768616e646f66660000004104a3bd4385af0b7002d753e994b46b670b515961d7c937be9bd67bb32bfc195fbd00893a7972b680c821681c479e54bfc36b0bff3555883d36d836914bc942eef30000000000000001",
231 "plaintext_hex": "f60fb281e8c72f6725add4cbd40e7b08",
232 "ciphertext_hex": "37388e3ef836f43004b123b0322071d9",
233 "tag_hex": "e3855f79299f4270d9f5fb0572171be8"
234 },
235 "account_chain": {
236 "note": "the whole of PROTOCOL.md's 'The shape', end to end, so a new implementation can bisect where it diverges",
237 "passphrase_utf8": "contra-golden-vector-passphrase-do-not-use-8f3a1c",
238 "salt_pw_hex": "962c1e2ca2b4c0602e6ec706e76e3eac",
239 "account_key_hex": "f60fb281e8c72f6725add4cbd40e7b08",
240 "recovery_code_hex": "70da5ffc983510bba4672030946b9eed",
241 "prf_output_hex": "6f926e3f71aec7803ffeeef8598e91de4195a42067688c8f4e3fd24c00c50c49",
242 "cred_salt_hex": "ce414df9c26826e10c1c4f359823885eb5eb39f89ead15583cade016d317f276",
243 "s_pw_hex": "6bf83f20da63fb1c818ce0f12e93294ba999b4ad156a7e5ae680f9f38fdd493b",
244 "seed_login_hex": "4f2b905bcff9d01c15bbb82bb0a9d26a1267f35278928d1bd38e8c838ef68b8a",
245 "lk_pw_public_hex": "0465b117b08f92789048944fced0df2343d93b77e8c92448a3f2be170ea91755066a7f789fdf979c17ed782cf9f24cdec565ad8fe752e9f24e974e4c5270cb908f",
246 "seed_rc_login_hex": "46b18c0c2a54c5ef6baeeda49ab42fd24ae8401912020cf94c02a51f1436240b",
247 "lk_rc_public_hex": "048b58c6f080a5fe442a996ad8c7104fc2ecc23fac14d5bfb834fbf949640dae7a4ff41f793d4d7ae97103fe8d5d13faf99b46c52f46a36ce5416d9346b8fac90f",
248 "kek_pw_hex": "e70a2f643ee0dc6123d042ca574b44994135d7776016e3d181fc32f93db40d82",
249 "kek_rc_hex": "58c5e4bd32d767d48a63d3f77ed67bad6c1fb4017d90a2f098cb32e8b87ff27b",
250 "kek_prf_hex": "25a832e73062849b768e245a28a1139f3a0171d41a05a34ce8d2615e7ecacad9",
251 "rk_hex": "e3769479962198ef9dbcf21e4822b0e2d45f9918f1e7bf86aa6208fc3e3ad3c6"
252 }
253}
254