@quo-systems/quo 0.2.9 → 0.2.11

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.
Files changed (78) hide show
  1. package/README.md +19 -10
  2. package/SPEC.md +301 -110
  3. package/dist/being/being.d.ts +2 -2
  4. package/dist/being/being.js +34 -12
  5. package/dist/being/digest.js +26 -8
  6. package/dist/being/index.d.ts +2 -2
  7. package/dist/being/index.js +2 -2
  8. package/dist/being/silence.d.ts +2 -0
  9. package/dist/being/silence.js +12 -0
  10. package/dist/being/types.d.ts +4 -2
  11. package/dist/being/types.js +25 -0
  12. package/dist/conformance/assert.js +40 -6
  13. package/dist/conformance/beings.d.ts +48 -5
  14. package/dist/conformance/beings.js +39 -8
  15. package/dist/conformance/estate.js +110 -21
  16. package/dist/conformance/index.d.ts +5 -2
  17. package/dist/conformance/index.js +165 -7
  18. package/dist/harbor/core.d.ts +5 -2
  19. package/dist/harbor/core.js +195 -45
  20. package/dist/harbor/dial.js +32 -15
  21. package/dist/harbor/index.d.ts +1 -0
  22. package/dist/harbor/index.js +3 -0
  23. package/dist/harbor/memory.d.ts +3 -3
  24. package/dist/harbor/memory.js +7 -12
  25. package/dist/harbor/reach.js +42 -17
  26. package/dist/ward/allowance.js +15 -4
  27. package/dist/ward/arithmetic.d.ts +1 -0
  28. package/dist/ward/arithmetic.js +22 -6
  29. package/dist/ward/cells.d.ts +3 -1
  30. package/dist/ward/cells.js +79 -21
  31. package/dist/ward/door.d.ts +3 -2
  32. package/dist/ward/door.js +38 -10
  33. package/dist/ward/ground.d.ts +5 -1
  34. package/dist/ward/ground.js +38 -1
  35. package/dist/ward/heirs.d.ts +2 -3
  36. package/dist/ward/heirs.js +19 -13
  37. package/dist/ward/index.d.ts +1 -0
  38. package/dist/ward/index.js +3 -0
  39. package/dist/ward/owner.d.ts +6 -27
  40. package/dist/ward/owner.js +59 -33
  41. package/dist/ward/partition.d.ts +3 -0
  42. package/dist/ward/partition.js +109 -4
  43. package/dist/ward/seal.d.ts +1 -0
  44. package/dist/ward/seal.js +41 -13
  45. package/dist/ward/stance.d.ts +7 -3
  46. package/dist/ward/stance.js +156 -66
  47. package/dist/ward/ward.d.ts +10 -0
  48. package/dist/ward/ward.js +123 -51
  49. package/package.json +4 -2
  50. package/src/being/being.ts +33 -11
  51. package/src/being/digest.ts +28 -13
  52. package/src/being/index.ts +2 -2
  53. package/src/being/silence.ts +14 -0
  54. package/src/being/types.ts +39 -5
  55. package/src/conformance/assert.ts +37 -4
  56. package/src/conformance/beings.ts +41 -10
  57. package/src/conformance/estate.ts +107 -20
  58. package/src/conformance/index.ts +188 -13
  59. package/src/harbor/core.ts +203 -46
  60. package/src/harbor/dial.ts +46 -17
  61. package/src/harbor/index.ts +3 -0
  62. package/src/harbor/memory.ts +8 -13
  63. package/src/harbor/reach.ts +47 -21
  64. package/src/ward/allowance.ts +15 -4
  65. package/src/ward/arithmetic.ts +25 -8
  66. package/src/ward/cells.ts +76 -25
  67. package/src/ward/door.ts +38 -12
  68. package/src/ward/ground.ts +52 -3
  69. package/src/ward/heirs.ts +19 -13
  70. package/src/ward/index.ts +3 -0
  71. package/src/ward/owner.ts +65 -46
  72. package/src/ward/partition.ts +109 -5
  73. package/src/ward/seal.ts +41 -12
  74. package/src/ward/stance.ts +163 -64
  75. package/src/ward/ward.ts +124 -52
  76. package/vectors/arithmetic.json +7 -0
  77. package/vectors/framing.json +30 -15
  78. package/vectors/wire.json +4 -4
package/src/ward/ward.ts CHANGED
@@ -8,7 +8,7 @@ import { silence, isSilence, unreached, isWord, word } from '../being/silence.ts
8
8
  import { OWNER } from '../being/types.ts';
9
9
  import type { Asker, BeingLike, Cells, JsonObject, Reply, Stance, Wanted, Word } from '../being/types.ts';
10
10
  import type { Ground, WardPointers } from './ground.ts';
11
- import { at, drop, open, put, emptyBind, emptyCells, type Bind, type Partition, type StandingKeys } from './partition.ts';
11
+ import { at, drop, open, put, emptyBind, emptyCells, MINTED, type Bind, type Partition, type StandingKeys } from './partition.ts';
12
12
  import { Heirs } from './heirs.ts';
13
13
  import { makeDoor, type Door } from './door.ts';
14
14
  import { buildStance } from './stance.ts';
@@ -16,12 +16,13 @@ import { ownerAnswer } from './owner.ts';
16
16
  import { allow, within, LATE } from './allowance.ts';
17
17
  import { beingKey, openReply, sealAsk, wardKey, wardPadlock, wardSignPk, type ReplyPayload, type WardKey } from './seal.ts';
18
18
  import { unhex } from './arithmetic.ts';
19
- import { guardCells, cellFault } from './cells.ts';
19
+ import { guardCells, unguarded, cellFault } from './cells.ts';
20
20
 
21
- type Booted = Door & { bind: Bind; stance: Stance; cells: Cells & { class?: string } };
22
-
23
- // How many minted pks she keeps behind her. Enough to name the keys in play.
24
- const MINTED = 8;
21
+ // One being of the ward as the ward holds her: her door, her bind table, her
22
+ // stance and her cells. The owner's asks see this and nothing more. Not
23
+ // `Booted`, which is a harbor's word for a ward it started: this is a ward's
24
+ // word for a being living in it, and the two are one module apart.
25
+ export type Resident = Door & { bind: Bind; stance: Stance; cells: Cells & { class?: string } };
25
26
 
26
27
  // The ward. One call in, two pointers out. Async because keys are derived.
27
28
  export async function Ward(ground: Ground): Promise<WardPointers> {
@@ -35,7 +36,8 @@ class Self implements BeingLike {
35
36
  readonly g: Ground;
36
37
  readonly p: Partition;
37
38
  readonly heirs: Heirs;
38
- readonly doors = new Map<string, Booted>();
39
+ readonly doors = new Map<string, Resident>();
40
+ readonly #birthing = new Set<string>(); // keys whose constructor is running: taken, though no door and no row say so yet
39
41
  readonly door: WardPointers['door'];
40
42
  readonly ask: WardPointers['ask'];
41
43
 
@@ -47,23 +49,25 @@ class Self implements BeingLike {
47
49
  this.g = ground;
48
50
  this.key = key;
49
51
  this.pk = key.pk;
50
- this.p = open(ground.memory); // the partition IS the ward's cells
51
- this.heirs = new Heirs(this.p);
52
+ this.p = open(ground.memory); // the partition: the ward's own state, and every being's row
53
+ this.heirs = new Heirs(this.p, () => this.#wrote());
52
54
  this.door = makeDoor(key, this.heirs, this.doors, () => this.p.public, (n) => ground.random(n)); // pointer one
53
- this.#boot(this.pk, this); // the ward's ward is itself
55
+ this.#boot(this.pk, () => this); // the ward's ward is itself
54
56
  // a restart is silent: every being in the cells is constructed again, unasked.
55
- // A throw on a boot the owner asked for is that boot's answer: silence,
56
- // and nothing half-lives. This boot nobody asked for, and there is nobody
57
- // to hand a silence to. Any constructor may throw a default that is not
58
- // a value, an author's mistake, a shape she no longer recognises after an
59
- // upgrade — and let through here it is one being taking down the ward and
60
- // every other being in it, on a restart. She is absent instead: no door,
61
- // so silence at the door, and her cells sit untouched, waiting for the
62
- // run that can read them.
57
+ // A throw on a boot the owner asked for is that boot's error, and nothing
58
+ // half-lives. This boot nobody asked for, and there is nobody to hand an
59
+ // error to. Any constructor may throw, a default that is not a value, an
60
+ // author's mistake, a shape she does not recognise after an upgrade, and
61
+ // let through here it is one being taking down the ward and every other
62
+ // being in it, on a restart. She is absent instead: no door, so silence
63
+ // at the door, and her cells sit untouched, waiting for the run that can
64
+ // read them. Her row stays hers: nobody boots another class over it, the
65
+ // owner sees her as absent, and the owner may unboot her.
63
66
  for (const [k, c] of Object.entries(this.p.beings)) {
64
- if (k === this.pk || !c.class) continue;
67
+ const className = c.class;
68
+ if (k === this.pk || !className) continue;
65
69
  try {
66
- this.#instantiate(k, c.class);
70
+ this.#boot(k, (stance) => this.g.instantiate(className, stance));
67
71
  } catch {
68
72
  /* she is not here this run. the ward is, and so is everyone else. */
69
73
  }
@@ -84,15 +88,23 @@ class Self implements BeingLike {
84
88
  // can invite. A stranger cannot be a named asker here, because the door
85
89
  // names nobody the ward did not bind.
86
90
  async answer(asker: Asker, method?: string, args: JsonObject = {}): Promise<Reply> {
87
- if (asker.id === undefined) return { error: 'unknown ask' };
91
+ // Nobody is not an owner. The door names nobody the ward did not bind, so
92
+ // the only way here unnamed is a partition that says the ward is its own
93
+ // public being, which no owner ask will write. Silence, not an error
94
+ // object: an unnamed asker is a stranger, and a stranger hears one thing.
95
+ if (asker.id === undefined) return silence;
88
96
  return ownerAnswer(
89
97
  {
90
98
  pk: this.pk,
91
99
  doors: this.doors,
100
+ absent: () => this.#absent(),
92
101
  publicKey: () => this.p.public,
93
- instantiate: (key, className) => this.#instantiate(key, className),
102
+ instantiate: (className, key) => this.#instantiate(className, key),
94
103
  unboot: (key) => this.#unboot(key),
95
- setPublic: (key) => void (this.p.public = key),
104
+ setPublic: (key) => {
105
+ this.p.public = key;
106
+ this.#wrote();
107
+ },
96
108
  },
97
109
  asker,
98
110
  method,
@@ -101,11 +113,45 @@ class Self implements BeingLike {
101
113
  }
102
114
 
103
115
  // ---- ward functions. on the object. no stance reaches them.
104
- #instantiate(key: string, className: string): Booted | null {
105
- if (!key || this.doors.has(key)) return null;
106
- const door = this.#boot(key, className);
116
+
117
+ // The partition was written. The harbor is told, and nothing more: what it
118
+ // does with the word is its own, and the ward never learns.
119
+ #wrote(): void {
120
+ this.g.wrote?.();
121
+ }
122
+
123
+ // The rows no door holds this run: beings whose class threw at birth or
124
+ // is not the harbor's to give. Key to class.
125
+ #absent(): Record<string, string | null> {
126
+ const out: Record<string, string | null> = {};
127
+ for (const [k, c] of Object.entries(this.p.beings)) if (k !== this.pk && !this.doors.has(k)) put(out, k, c.class ?? null);
128
+ return out;
129
+ }
130
+
131
+ // A new being under a key nobody holds. A key with a row in the partition
132
+ // is booted, whether a door holds it this run or not: an absent being's
133
+ // row is hers, with every relation in it, and no class is booted over it.
134
+ // A throw at birth is that boot's refusal and nothing half-lives; the
135
+ // ward says which, since the owner hears objects.
136
+ #instantiate(className: string, key: string): Resident | 'threw' | null {
137
+ // The three refusals are read before the constructor runs, and the
138
+ // constructor can reach the stance and boot: a class that boots its own
139
+ // key from inside itself would pass all three, since neither its door nor
140
+ // its row exists yet, and the two objects would then share one row. A key
141
+ // being born is a key taken, for as long as the birth lasts.
142
+ if (typeof key !== 'string' || typeof className !== 'string' || !key || this.doors.has(key) || at(this.p.beings, key) || this.#birthing.has(key)) return null;
143
+ let door: Resident | null;
144
+ this.#birthing.add(key);
145
+ try {
146
+ door = this.#boot(key, (stance) => this.g.instantiate(className, stance));
147
+ } catch {
148
+ return 'threw';
149
+ } finally {
150
+ this.#birthing.delete(key);
151
+ }
107
152
  if (!door) return null;
108
- door.cells.class = className; // so a restart finds her
153
+ unguarded(door.cells).class = className; // so a restart finds her. the ward's key, written behind her guard
154
+ this.#wrote();
109
155
  return door;
110
156
  }
111
157
 
@@ -115,56 +161,77 @@ class Self implements BeingLike {
115
161
  // rather than meeting a being who is simply not there any more. What is
116
162
  // left after that is her cells and her bind table, and they go with her:
117
163
  // a row naming a being no door holds would be read on the next restart
118
- // and boot her again.
164
+ // and boot her again. An absent being leaves the same way: she has no
165
+ // stance to speak for her, so the ward closes her heirs itself.
119
166
  #unboot(key: string): string[] | null {
167
+ if (key === this.pk) return null;
120
168
  const door = this.doors.get(key);
121
- if (!door || key === this.pk) return null;
122
- const occupants = Object.keys(door.cells.occupants),
123
- standings = Object.keys(door.cells.standings);
124
- for (const id of occupants) door.stance.occupants.remove(id);
125
- for (const id of standings) door.stance.standings.remove(id);
169
+ const cells = door?.cells ?? at(this.p.beings, key);
170
+ if (!cells) return null;
171
+ const ids = (r: unknown) => (r !== null && typeof r === 'object' ? Object.keys(r) : []);
172
+ const occupants = ids(cells.occupants),
173
+ standings = ids(cells.standings);
174
+ if (door) {
175
+ for (const id of occupants) door.stance.occupants.remove(id);
176
+ for (const id of standings) door.stance.standings.remove(id);
177
+ } else {
178
+ const bind = at(this.p.bind, key);
179
+ for (const heir of Object.values(bind?.occupants ?? {})) this.heirs.close(heir);
180
+ }
126
181
  // A ward whose public being is gone answers arrivals for no heir with
127
182
  // silence, as a ward that never had one does.
128
183
  if (this.p.public === key) this.p.public = null;
129
184
  drop(this.p.beings, key);
130
185
  drop(this.p.bind, key);
131
186
  this.doors.delete(key);
187
+ this.#wrote();
132
188
  return [...occupants, ...standings];
133
189
  }
134
190
 
135
191
  // Nothing is written until there is somebody to write it for: a class the
136
192
  // harbor does not know makes no being, and a boot that made nobody must
137
193
  // leave the partition as it found it.
138
- #boot(key: string, classNameOrSelf: string | Self): Booted | null {
139
- const cells = guardCells(at(this.p.beings, key) ?? emptyCells());
194
+ //
195
+ // `make` is who to build with the stance this raises. Two callers and two
196
+ // makers: the ground's `instantiate` for a being of the ward, and the ward
197
+ // itself, which is the first being in its own map and is already made.
198
+ #boot(key: string, make: (stance: Stance) => BeingLike | null): Resident | null {
199
+ const cells = guardCells(at(this.p.beings, key) ?? emptyCells(), () => this.#wrote());
140
200
  const bind = at(this.p.bind, key) ?? emptyBind();
141
201
  const stance = buildStance(
142
202
  {
143
203
  pk: this.pk,
204
+ // This stance, not merely this key: unboot and boot again under the
205
+ // same key makes a new being, and the old stance is not hers.
206
+ live: () => this.doors.get(key)?.stance === stance,
144
207
  mintKey: (b) => this.#mintKey(b),
145
208
  openHeir: (heir, being, id) => this.heirs.open(heir, being, id),
146
209
  closeHeir: (heir) => this.heirs.close(heir),
147
- send: (b, keys, announce, method, args, wanted) => this.#send(b, keys, announce, method, args, wanted),
210
+ send: (b, keys, method, args, wanted) => this.#send(b, keys, method, args, wanted),
148
211
  // A throw at birth is null to her, not a throw in her method: she asked
149
212
  // for a being and got none, and her own answer is still hers to give.
150
- instantiate: (k, className) => {
151
- try {
152
- return this.#instantiate(k, className)?.key ?? null;
153
- } catch {
154
- return null;
155
- }
213
+ instantiate: (className, k) => {
214
+ const made = this.#instantiate(className, k);
215
+ return made && made !== 'threw' ? made.key : null;
156
216
  },
217
+ // The two halves of a maker's way back, each the ward's own call: the
218
+ // being made mints an occupant for her maker, and a relation that
219
+ // never came about takes her out again.
220
+ relate: async (k, id) => (await this.doors.get(k)?.stance.occupants.invite(id)) ?? null,
221
+ unmake: (k) => void this.#unboot(k),
222
+ wrote: () => this.#wrote(),
157
223
  },
158
224
  key,
159
225
  cells,
160
226
  bind,
161
227
  );
162
- const being = classNameOrSelf === this ? this : this.g.instantiate(classNameOrSelf as string, stance);
163
- if (!being) return null;
228
+ const being = make(stance);
229
+ if (!being || typeof being.answer !== 'function') return null; // a being is anything with an answer, and nothing without one
164
230
  put(this.p.beings, key, cells);
165
231
  put(this.p.bind, key, bind);
166
- const door: Booted = { key, cells, bind, stance, being };
232
+ const door: Resident = { key, cells, bind, stance, being };
167
233
  this.doors.set(key, door);
234
+ this.#wrote();
168
235
  return door;
169
236
  }
170
237
 
@@ -176,6 +243,7 @@ class Self implements BeingLike {
176
243
  // but the keys of the moment.
177
244
  bind.minted.push(k.pk);
178
245
  if (bind.minted.length > MINTED) bind.minted.splice(0, bind.minted.length - MINTED);
246
+ this.#wrote();
179
247
  return k;
180
248
  }
181
249
 
@@ -184,7 +252,7 @@ class Self implements BeingLike {
184
252
  // next, seals to the far ward, opens the reply with the ephemeral secret,
185
253
  // and rotates to the announced key once the far door has answered under
186
254
  // the current one.
187
- async #send(bind: Bind, keys: StandingKeys, announce: boolean, method: string | undefined, args: JsonObject, wanted?: Wanted): Promise<ReplyPayload | typeof silence | Word> {
255
+ async #send(bind: Bind, keys: StandingKeys, method: string | undefined, args: JsonObject, wanted?: Wanted): Promise<ReplyPayload | typeof silence | Word> {
188
256
  // What she asked for, held to what this ward allows. Asking for nothing is
189
257
  // the default, and asking for more than the ceiling is the ceiling: budget
190
258
  // is granted by a ward, never minted by a being.
@@ -192,8 +260,9 @@ class Self implements BeingLike {
192
260
  const by = (await beingKey(unhex(keys.current))).pk;
193
261
  // A public being is reached without a heir, and the door keeps nothing for
194
262
  // whoever asked: no key it vouched for, so nothing to announce and nothing
195
- // to rotate to. A standing on her signs with one key for life.
196
- if (announce && keys.next === null && keys.heir !== null) keys.next = (await this.#mintKey(bind)).seed;
263
+ // to rotate to. A standing on her signs with one key for life. Every other
264
+ // ask announces its next: there is no send that does not.
265
+ if (keys.next === null && keys.heir !== null) keys.next = (await this.#mintKey(bind)).seed;
197
266
  const next = keys.next === null ? null : (await beingKey(unhex(keys.next))).pk;
198
267
  // Her count for this relation, one higher every call and never reused. The
199
268
  // far door honours each number once. One relation sends one at a time, so
@@ -202,10 +271,12 @@ class Self implements BeingLike {
202
271
  // Args that will not go through the seal are args that never left. A
203
272
  // being holds three answers and a throw is not one of them, so an ask
204
273
  // that cannot be sealed is told what is true of it: no door was reached.
205
- // Values only, by the same rule her cells keep: a Date would arrive as a
206
- // string, a function would not arrive at all, and she would never know
207
- // the far being was asked something other than what she said.
208
- if (cellFault(args, 'args') !== null) return unreached();
274
+ // One object of values, by the rule her cells keep and the far door
275
+ // reads: a Date would arrive as a string, a function would not arrive at
276
+ // all, a list or a string would be refused as a stranger's bytes, and
277
+ // she would never know the far being was asked something other than
278
+ // what she said.
279
+ if (args === null || typeof args !== 'object' || Array.isArray(args) || cellFault(args, 'args') !== null) return unreached();
209
280
  let sealed;
210
281
  try {
211
282
  sealed = await sealAsk(keys.heir, { by, next, seq, time: budget.time, method, args }, unhex(keys.current), wardPadlock(keys.ward), this.g.random(32));
@@ -237,6 +308,7 @@ class Self implements BeingLike {
237
308
  keys.current = keys.next; // the far door holds `next` as announced. move to it.
238
309
  keys.next = null;
239
310
  }
311
+ this.#wrote(); // the count moved, and the keys may have
240
312
  return reply;
241
313
  }
242
314
  }
@@ -65,6 +65,13 @@
65
65
  "signature": "60aa62f7129c8fdeba710872fa10016dae1aa12df0f31969a6baabf60b2ebc3d0822cc9a8b1eb12246076b2eea69d381a03c2f581c05ba6bcca3b4ba80c2f504",
66
66
  "refuses": true
67
67
  },
68
+ {
69
+ "name": "a zero signature under a non-canonical small-order public key, y equal to p, is silence",
70
+ "voice": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
71
+ "message": "62792077686f736520617574686f72697479",
72
+ "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
73
+ "refuses": true
74
+ },
68
75
  {
69
76
  "name": "an X25519 agreement",
70
77
  "secret": "fcfabee71b7a33993cca5579e6a273ffd1c62cc1749cbf1c9049f599e44f6477",
@@ -2,14 +2,14 @@
2
2
  "corpus": "@quo-systems/quo",
3
3
  "encoding": "hex",
4
4
  "area": "framing",
5
- "note": "The formats a second kit must reproduce byte for byte: the ward pk, the digest, the signed ask body, the sealed ask, the sealed reply, the invitation and the knock. Every random input is fixed here, so every output is fixed. The ask body is JSON.stringify of the payload, which is not canonical: these vectors pin the key order sealAsk writes, to, by, next, seq, time, method, args; hops is in no vector, because nothing sets it. A kit that emits another order still interoperates, because a door verifies the bytes it received, but it will not reproduce these vectors. An invitation is JSON too, ward, heir, secret, and a heir secret is the seed of a being key. A knock is an ask whose by is the heir pk, signed with the heir secret, whose next is the knocker's own key, and whose to is the heir; its answer is an ordinary reply, and the heir is spent by it. A reply is one of three shapes: an object with its digest, silence, or the ward's word to a key the door has bound, { quo: word }, where word is one of removed, absent, unannounced, repeated, threw. The ward here is the one from the ward pk vector, and the heir secret is the first entropy it draws, so the invitation it mints and the knock its door binds are these bytes.",
5
+ "note": "The formats a second kit must reproduce byte for byte: the ward pk, the digest, the signed ask body, the sealed ask, the sealed reply, the invitation and the knock. Every random input is fixed here, so every output is fixed. The ask body is JSON.stringify of the payload with the heir it is for in front, which is not canonical: these vectors pin the key order sealAsk writes, to, by, next, seq, time, method, args, and to is signed with the rest, null for nobody; hops is in no vector, because nothing sets it. The two signed bodies are the bytes inside the two sealed asks. A kit that emits another order still interoperates, because a door verifies the bytes it received, but it will not reproduce these vectors. An invitation is JSON too, ward, heir, secret, and a heir secret is the seed of a being key. A knock is an ask whose by is the heir pk, signed with the heir secret, whose next is the knocker's own key, and whose to is the heir; its answer is an ordinary reply, and the heir is spent by it. A reply is one of three shapes: an object with its digest, silence, or the ward's word to a key the door has bound, { quo: word }, where word is one of removed, absent, unannounced, repeated, threw. The ward here is the one from the ward pk vector, and the heir secret is the first entropy it draws, so the invitation it mints and the knock its door binds are these bytes.",
6
6
  "vectors": [
7
7
  {
8
8
  "name": "a ward pk from a fixed seed",
9
9
  "seed": "1111111111111111111111111111111111111111111111111111111111111111",
10
- "pk": "d04ab232742bb4ab3a1368bd4615e4e6d0224ab71a016baf8520a332c97787377b4e909bbe7ffe44c465a220037d608ee35897d31ef972f07f74892cb0f73f13",
11
- "signPk": "d04ab232742bb4ab3a1368bd4615e4e6d0224ab71a016baf8520a332c9778737",
12
- "padlockPk": "7b4e909bbe7ffe44c465a220037d608ee35897d31ef972f07f74892cb0f73f13"
10
+ "pk": "6d773f8156c80eb9f34d0734e889d824a0d0515f527b853771208ef1ed3feb281fc3da3532de3b20deafd145e30c3de979917e96c22f6c3113a731379eeb3200",
11
+ "signPk": "6d773f8156c80eb9f34d0734e889d824a0d0515f527b853771208ef1ed3feb28",
12
+ "padlockPk": "1fc3da3532de3b20deafd145e30c3de979917e96c22f6c3113a731379eeb3200"
13
13
  },
14
14
  {
15
15
  "name": "a being key from a fixed secret",
@@ -23,47 +23,62 @@
23
23
  "digest": "269c9e90f39f6fcae9deab916e3a4148788dec5ba0d06023edc8e52180c773db"
24
24
  },
25
25
  {
26
- "name": "the signed ask body, and its signature",
27
- "payload": "{\"by\":\"a09aa5f47a6759802ff955f8dc2d2a14a5c99d23be97f864127ff9383455a4f0\",\"next\":null,\"seq\":1,\"time\":30000,\"method\":\"hello\",\"args\":{\"name\":\"quo\"}}",
28
- "body": "7b226279223a2261303961613566343761363735393830326666393535663864633264326131346135633939643233626539376638363431323766663933383334353561346630222c226e657874223a6e756c6c2c22736571223a312c2274696d65223a33303030302c226d6574686f64223a2268656c6c6f222c2261726773223a7b226e616d65223a2271756f227d7d",
26
+ "name": "the digest where JCS is hard: UTF-16 key order and ES numbers",
27
+ "blueprint": "{\"asks\":[],\"notes\":{\"1\":\"One\",\"\u20ac\":\"Euro Sign\",\"\\r\":\"Carriage Return\",\"\ufb33\":\"Hebrew Letter Dalet With Dagesh\",\"\ud83d\ude00\":\"Emoji: Grinning Face\",\"\u0080\":\"Control\",\"\u00f6\":\"Latin Small Letter O With Diaeresis\"},\"numbers\":[1e+21,0,0.1,1e-7,9007199254740992,0.3333333333333333]}",
28
+ "canonical": "{\"asks\":[],\"notes\":{\"\\r\":\"Carriage Return\",\"1\":\"One\",\"\u0080\":\"Control\",\"\u00f6\":\"Latin Small Letter O With Diaeresis\",\"\u20ac\":\"Euro Sign\",\"\ud83d\ude00\":\"Emoji: Grinning Face\",\"\ufb33\":\"Hebrew Letter Dalet With Dagesh\"},\"numbers\":[1e+21,0,0.1,1e-7,9007199254740992,0.3333333333333333]}",
29
+ "digest": "dc5306089d6bf46d9f91d25290b770c0f18955f1192525b51389fd4c23e02089"
30
+ },
31
+ {
32
+ "name": "the signed ask body for nobody, and its signature: to is inside, first",
33
+ "to": "",
34
+ "payload": "{\"to\":null,\"by\":\"a09aa5f47a6759802ff955f8dc2d2a14a5c99d23be97f864127ff9383455a4f0\",\"next\":null,\"seq\":1,\"time\":30000,\"method\":\"hello\",\"args\":{\"name\":\"quo\"}}",
35
+ "body": "7b22746f223a6e756c6c2c226279223a2261303961613566343761363735393830326666393535663864633264326131346135633939643233626539376638363431323766663933383334353561346630222c226e657874223a6e756c6c2c22736571223a312c2274696d65223a33303030302c226d6574686f64223a2268656c6c6f222c2261726773223a7b226e616d65223a2271756f227d7d",
36
+ "secret": "2222222222222222222222222222222222222222222222222222222222222222",
37
+ "signature": "535c50354632d607fc5b68d081a0191ebf85c296b6c7e67b7b0dcc6030d569673dfe35f164b6b2eb3558c4454c32aabc5586bd82e305401a82fda7a166b91906"
38
+ },
39
+ {
40
+ "name": "the signed ask body to a heir, and its signature: the same payload, to named",
41
+ "to": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
42
+ "payload": "{\"to\":\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"by\":\"a09aa5f47a6759802ff955f8dc2d2a14a5c99d23be97f864127ff9383455a4f0\",\"next\":null,\"seq\":1,\"time\":30000,\"method\":\"hello\",\"args\":{\"name\":\"quo\"}}",
43
+ "body": "7b22746f223a2261616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161222c226279223a2261303961613566343761363735393830326666393535663864633264326131346135633939643233626539376638363431323766663933383334353561346630222c226e657874223a6e756c6c2c22736571223a312c2274696d65223a33303030302c226d6574686f64223a2268656c6c6f222c2261726773223a7b226e616d65223a2271756f227d7d",
29
44
  "secret": "2222222222222222222222222222222222222222222222222222222222222222",
30
- "signature": "21fae42dc81de4a1983ac9dd457338043e3e69ba76331cb5616f3106e007de228fee0f19c49035b90789799667bc7de4d4212618790b2b449e5a26c299134c0b"
45
+ "signature": "1f0e63f365dd09bff2c070091ea209d14eefec1026bf210dba87a4a18135fd90107c9879177695f0b4a899e67777b75d6001229e0875657cfc9a2cd197880500"
31
46
  },
32
47
  {
33
48
  "name": "a sealed ask to a heir: the ephemeral pk, then the box, and nothing outside it",
34
49
  "to": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
35
50
  "ephemeralSeed": "3333333333333333333333333333333333333333333333333333333333333333",
36
- "bytes": "7b0d47d93427f8311160781c7c733fd89f88970aef490d8aa0ee19a4cb8a1b14ed97840c789fc01f8b362dff17c11793d230bc13c4f56401abbbd7c4d26ac0379164fc07794e29b8c9330328f8ae2b3b6280d1fb1ced6ef44c54478381be4834444d3c7c4c7258d7653f481e9bc5cc78394fc9d6742edef6a13e3273f24ab212205f83ca25640d301110062940e3bf2cde21dd1707111e240a6de0674a98ef941decb3e0112bcb444576485a180437b1d2ddb5e0773a527c12d781bc669572bafe8d0f1c31396b5e25e354309d9cd8584c8eaa7c6b0ffc97ca3963a997a289254e498dc597b196720a0a70860815f474c56aee9e0d6a1bd2949d314819e9ea7565e379f8d4d8f60bc4243b117ba9b39ab74ef949f7c916843da444c5387118697317ab720ffd10e9954db6e766664e4e7f9e9e09f05df2dc1ff7f47a4fbd419964db60f395043f6a3a"
51
+ "bytes": "7b0d47d93427f8311160781c7c733fd89f88970aef490d8aa0ee19a4cb8a1b140f393feeee5faf9a2707cd3e47c06e7edfd9f5b705ea3ee1a2a2a25b591b37a0af5a068c6455d3cc2dc2948615faf29b182a81ea3d73c166e68f4bb1578c3fbaf22f1dea223d9b84e7e5b90f65139bba894cee2bf68ced2192e548c174bc593dd16d124eb21d3bbde81169bab147676bb11869e08dedb2b15a782d6236ff2ae6b9fa578be8008707ca238f28d39f5029a0340b2e5299e97e44ce9140f8a40ad038d28c931d7872bcfa06f1e29ec964491d4b4ee425ab55b3a09a501a50b6c36f159962247650ec31c42b0c711d97dfc832086366e7c856d332e5bccce04c44c7b67be20bb35d52cccf3a4bf1055fa2a38246c61adc2114da603bd419885b79eb9e3f429d4e26e808beb562d5c60e635649acda8170834f68aee612b56416d369cc72edc8ac1b6204e7"
37
52
  },
38
53
  {
39
54
  "name": "a sealed ask for nobody: the same shape, with to null inside",
40
55
  "to": "",
41
56
  "ephemeralSeed": "3333333333333333333333333333333333333333333333333333333333333333",
42
- "bytes": "7b0d47d93427f8311160781c7c733fd89f88970aef490d8aa0ee19a4cb8a1b14ed97840c789f8c0b863b60bc14d954c89130ed4bc4f53006feedd793843e986ec037fb00211a7dbf9036017bfdfd2b6b378085f944b56ba71e5743dbd7b91163111d6f2a4b7500c6712e1e528c9eda7f395484952f2d92b5e2326b33a71eae02355ccbdd2a331976064b0f7e03e8b87ddb72d402414e4832073bb323488cb3c043b7baa4043a920516305f01574069f2939af9bf2d3f05295edf908316e73499bd7932d14673cfb6e89f68b52b6e7edebb44f36a03b7f4c87b723eb601f2142d97d94ad2ae07b44d1a9ab7f1e0c91bf2e210d66d85a298c9509b39a652868391296be1e21fcc909f97305b"
57
+ "bytes": "7b0d47d93427f8311160781c7c733fd89f88970aef490d8aa0ee19a4cb8a1b140f393feeee5fe38e2a0a807d44d82d259cd9a4ef05ea6ae6f7f4a20c0f4f6ff9fe09018b3c0187cb74c796d510a9f2cb4d2ad5e8652bc435b48c4fe9018b66eda77f4ebc253ac395f3f4ef4372488dbd8957a368ad8fa162d1e9118121e8452dc46e5a59bd4a2ffbff4a60edf24c603ab44b60f5cbb2e4a7572e7e2634eb76b2e7a15ecffd11de46996598739cdb0e6ae1734771089cbe2b08c6807f88d64cf37b26b15e6a32d654377acd67283bc2cfea8117f24d135dec11d10d05c6e65e67cc09a5334fe6ce0ed4bbcb06f54b304e15725b956f00d5c8f6e3b48e4b634b743c581e15f86f7b17b52a96"
43
58
  },
44
59
  {
45
60
  "name": "the sealed silence reply",
46
61
  "reply": "{\"silence\":true}",
47
62
  "replySeed": "4444444444444444444444444444444444444444444444444444444444444444",
48
- "bytes": "ff2ee45601ec1b67310c7790404585ae697331eee1c1f8cf2419731c1fff3e6b76ec8fe27c6573176a8974f1235379842eeabe08f92c8aae00e383195ff41cbb2124de81119eb83326fbb9b8ab00a149ce41ea21f6c056a324333cc76b82c93ac93fbcc3fc74f57a1bff4a07a0c7824ed5516b7fb8a14006a25f6c28d95e4e64"
63
+ "bytes": "ff2ee45601ec1b67310c7790404585ae697331eee1c1f8cf2419731c1fff3e6b76ec8fe27c6573176a8974f123537984bdd8baea7cbd4e9b81f38db22c5917e9674bc082183e532adba06227f7e023955f16afcb723ca826a579fc08af3306824c8f8012687532ad79d81b77a7c84a429d151cc593b81312bc44433571a0b4aa"
49
64
  },
50
65
  {
51
66
  "name": "a sealed object reply",
52
67
  "reply": "{\"object\":{\"hi\":\"quo\"},\"seen\":null}",
53
68
  "replySeed": "4444444444444444444444444444444444444444444444444444444444444444",
54
- "bytes": "ff2ee45601ec1b67310c7790404585ae697331eee1c1f8cf2419731c1fff3e6b76ec93e97a657e002d9135a7394f3ec33bcd723c9d8947909f4cc659d8dfeed743f5b64bfa87b4ac79074219c1032037de444400b509f31559331b7995f9dfbadbe7fb0f6d46db2257db70f248b7739b3baa2ca79b07b66b29ea680faf79340f2309163c9e3c65fcdb33297c419d1cd8517647"
69
+ "bytes": "ff2ee45601ec1b67310c7790404585ae697331eee1c1f8cf2419731c1fff3e6b76ec93e97a657e002d9135a7394f3ec33bcd723c9d8947909f4cc659d8dfeed743f5b6012ed80af39f9d1bc16c995f69944a0c94244e349308704f2070a98b59a5a4f3e9b1e2a1bfe2e7bcba2446de1fbf84dc15cc5fa5ac03a175cce7d2eaa07b0e1148416580932306d41dc961f145fa7141"
55
70
  },
56
71
  {
57
72
  "name": "a sealed word reply: the ward's word to a key it has bound",
58
73
  "reply": "{\"quo\":\"removed\"}",
59
74
  "replySeed": "4444444444444444444444444444444444444444444444444444444444444444",
60
- "bytes": "ff2ee45601ec1b67310c7790404585ae697331eee1c1f8cf2419731c1fff3e6b76ec8dfe7f2227567dce23ea274378db64eb74efed5c91135d62d89db62db7d8ffbd54cf3e82e3272d0b26d59130020755b442a16340798d3eec60bc3a3875020da9276d5e72d712ac3dad7ef287d3c153a0588bf4951b9d3540b1142bd54875a3"
75
+ "bytes": "ff2ee45601ec1b67310c7790404585ae697331eee1c1f8cf2419731c1fff3e6b76ec8dfe7f2227567dce23ea274378db6487fe336070ff4780aec6e6cb89197c05df879e39252f523fc910bf2268ded0d2f323f395a4e2352a5004424b828c43f3163595c67c120e5ea029cfecec4abe575fb4327449cd6003634f30b3cc056a54"
61
76
  },
62
77
  {
63
78
  "name": "an invitation for a heir: the ward pk, the heir pk, the heir secret, and nothing else",
64
79
  "wardSeed": "1111111111111111111111111111111111111111111111111111111111111111",
65
80
  "heirSecret": "4444444444444444444444444444444444444444444444444444444444444444",
66
- "invitation": "{\"ward\":\"d04ab232742bb4ab3a1368bd4615e4e6d0224ab71a016baf8520a332c97787377b4e909bbe7ffe44c465a220037d608ee35897d31ef972f07f74892cb0f73f13\",\"heir\":\"d759793bbc13a2819a827c76adb6fba8a49aee007f49f2d0992d99b825ad2c48\",\"secret\":\"4444444444444444444444444444444444444444444444444444444444444444\"}"
81
+ "invitation": "{\"ward\":\"6d773f8156c80eb9f34d0734e889d824a0d0515f527b853771208ef1ed3feb281fc3da3532de3b20deafd145e30c3de979917e96c22f6c3113a731379eeb3200\",\"heir\":\"d759793bbc13a2819a827c76adb6fba8a49aee007f49f2d0992d99b825ad2c48\",\"secret\":\"4444444444444444444444444444444444444444444444444444444444444444\"}"
67
82
  },
68
83
  {
69
84
  "name": "a sealed knock: the first ask under a heir, by the heir, announcing her own key, to the heir",
@@ -71,7 +86,7 @@
71
86
  "ownSecret": "5555555555555555555555555555555555555555555555555555555555555555",
72
87
  "ephemeralSeed": "6666666666666666666666666666666666666666666666666666666666666666",
73
88
  "payload": "{\"to\":\"d759793bbc13a2819a827c76adb6fba8a49aee007f49f2d0992d99b825ad2c48\",\"by\":\"d759793bbc13a2819a827c76adb6fba8a49aee007f49f2d0992d99b825ad2c48\",\"next\":\"c6822637c7d310ec57627be00ba259d253749f4aaf644470cffbe53a35f73242\",\"seq\":1,\"time\":30000,\"method\":\"hello\",\"args\":{\"name\":\"quo\"}}",
74
- "bytes": "219e4d800da968d2a5fcb009c784f4746c7138edb9ee4844b739e830b05cf424263fd9388d350e13808f15e9297f753dd517db9f8eeca10de0708fd81a3b3c1b5444da304de91ae98fa4b94a62dae0673bdc0a7c6d97e445f8e08c5c3094b9facda3fa828caced7992ed8989f85a05dbe67da08c06b47b4e56174fe60e8169fc56c78d0966281c47c9b5300cca473e57d43e954b9d424ceb5a49eba9a4a79cd8b5973d21cdeb70f35b988314f68dcb5736003eb1a56c9be4087005fb5ae7d719eb39860ffb4220871161b76395054ab09ee5a323b6eea9a01f31d436b2a12983d5c32d887377e9d9ea845ecd4690660336e5e3e34d1c46f7e648e5a0d81f7a28ae2a52cc3021d10fe29de5c67b9f487b42f34a3e0149856ce8ee8cc8a90860daf624e0ffc758cd3600f069218abe5abdaa3041783add308fa4110899d216831e0016f5357a194344eb3551e48f0cb70f86b51fa68815c51660615034d2abdf3078c649bcca47fd769001b31928108e3ec9f0c1108e6ceec9a32c5ddd542c4543a1b8260936b3e5"
89
+ "bytes": "219e4d800da968d2a5fcb009c784f4746c7138edb9ee4844b739e830b05cf424e0590708caeb7c3c01e2ae8a2fa26a18bc504b84e06e80b104eab60c233b6ab42709b03434573a932c55e1977311a6358713251329e652d3d4bf212e4fe2062629f886a825315d8338de702e40457e2371eb4cd3b6633e0e986ea724fe6128a664bc61c7113106858540f20df784583e3ede4f125841a5d359cc94784bcee04d303b26b1008392420ae8f0930650c6aeefa3ed6138ab791a92870cb4f4d2d8e634e216cfdec86e8b3ceeef0b4f8a49477e95c04423808150ef381f7ef5390f3182f825a7be03e48edd981d66c3131ed9cca37c6348ef7f8dccc01018ff8417e09c6958b77ea269c58a47683f2b369ca13a434117d38f2f726b8a422e5004db32613ddc300d6f90805597d96ed51ef22bdd6353507857ab50edc2a3719e9081491a4722728275e263c9f6c286a1b39ab7cbd755805f2610410073ece392af0b3b960e68b0143a05674398927a57e2d99396b577ef7d1c618d32c9af619a79954ad413d7b5fe4cf3"
75
90
  }
76
91
  ]
77
92
  }
package/vectors/wire.json CHANGED
@@ -7,9 +7,9 @@
7
7
  {
8
8
  "name": "an ask frame: kind, id, pk, bytes",
9
9
  "id": 1,
10
- "pk": "d04ab232742bb4ab3a1368bd4615e4e6d0224ab71a016baf8520a332c97787377b4e909bbe7ffe44c465a220037d608ee35897d31ef972f07f74892cb0f73f13",
10
+ "pk": "6d773f8156c80eb9f34d0734e889d824a0d0515f527b853771208ef1ed3feb281fc3da3532de3b20deafd145e30c3de979917e96c22f6c3113a731379eeb3200",
11
11
  "bytes": "010203",
12
- "frame": "0000000001d04ab232742bb4ab3a1368bd4615e4e6d0224ab71a016baf8520a332c97787377b4e909bbe7ffe44c465a220037d608ee35897d31ef972f07f74892cb0f73f13010203"
12
+ "frame": "00000000016d773f8156c80eb9f34d0734e889d824a0d0515f527b853771208ef1ed3feb281fc3da3532de3b20deafd145e30c3de979917e96c22f6c3113a731379eeb3200010203"
13
13
  },
14
14
  {
15
15
  "name": "a reply frame: kind, id, bytes",
@@ -25,9 +25,9 @@
25
25
  {
26
26
  "name": "the announce frame, text",
27
27
  "pks": [
28
- "d04ab232742bb4ab3a1368bd4615e4e6d0224ab71a016baf8520a332c97787377b4e909bbe7ffe44c465a220037d608ee35897d31ef972f07f74892cb0f73f13"
28
+ "6d773f8156c80eb9f34d0734e889d824a0d0515f527b853771208ef1ed3feb281fc3da3532de3b20deafd145e30c3de979917e96c22f6c3113a731379eeb3200"
29
29
  ],
30
- "frame": "{\"announce\":[\"d04ab232742bb4ab3a1368bd4615e4e6d0224ab71a016baf8520a332c97787377b4e909bbe7ffe44c465a220037d608ee35897d31ef972f07f74892cb0f73f13\"],\"suite\":1}",
30
+ "frame": "{\"announce\":[\"6d773f8156c80eb9f34d0734e889d824a0d0515f527b853771208ef1ed3feb281fc3da3532de3b20deafd145e30c3de979917e96c22f6c3113a731379eeb3200\"],\"suite\":1}",
31
31
  "suite": 1
32
32
  },
33
33
  {