@bitspark/archon-sdk 0.14.0 → 0.15.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.
@@ -4,6 +4,7 @@ export * from "./envelope.js";
4
4
  export * from "./login.js";
5
5
  export * from "./login-audience.js";
6
6
  export * from "./login-display.js";
7
+ export * from "./login-fingerprint.js";
7
8
  export * from "./enroll.js";
8
9
  export * from "./enroll-token.js";
9
10
  export * from "./request.js";
package/dist/src/index.js CHANGED
@@ -22,6 +22,7 @@ export * from "./envelope.js";
22
22
  export * from "./login.js";
23
23
  export * from "./login-audience.js";
24
24
  export * from "./login-display.js";
25
+ export * from "./login-fingerprint.js";
25
26
  export * from "./enroll.js";
26
27
  export * from "./enroll-token.js";
27
28
  export * from "./request.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,EAAE;AACF,uFAAuF;AACvF,wEAAwE;AACxE,EAAE;AACF,qFAAqF;AACrF,kEAAkE;AAClE,gFAAgF;AAChF,EAAE;AACF,6FAA6F;AAC7F,8FAA8F;AAC9F,wBAAwB;AACxB,EAAE;AACF,+EAA+E;AAC/E,yFAAyF;AACzF,sFAAsF;AACtF,uFAAuF;AACvF,+CAA+C;AAC/C,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,EAAE;AACF,uFAAuF;AACvF,wEAAwE;AACxE,EAAE;AACF,qFAAqF;AACrF,kEAAkE;AAClE,gFAAgF;AAChF,EAAE;AACF,6FAA6F;AAC7F,8FAA8F;AAC9F,wBAAwB;AACxB,EAAE;AACF,+EAA+E;AAC/E,yFAAyF;AACzF,sFAAsF;AACtF,uFAAuF;AACvF,+CAA+C;AAC/C,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { type LoginRequest } from "./login.js";
2
+ /**
3
+ * The label the transaction fingerprint's digest is computed under (docs/login.md §5.3). It is
4
+ * not an RFC 8032 context: nothing is signed with it, and no login proof's bytes are ever a
5
+ * fingerprint's input or the other way round.
6
+ */
7
+ export declare const FINGERPRINT_DOMAIN = "archon-login-fingerprint/1";
8
+ /**
9
+ * The login's transaction fingerprint (docs/login.md §5.3), what a person compares before
10
+ * approving: the page that began the login computes it from its own K and the begin response,
11
+ * the CLI from the exact request it is about to sign, and the two agree only if every field the
12
+ * login proof binds — audience, K, id, scope, validity — and the nonce are the same on both
13
+ * sides. It is the first 16 bytes (128 bits) of
14
+ *
15
+ * SHA-256( u16be(len domain) ‖ domain ‖ u16be(len nonce) ‖ nonce ‖ loginBinding(LOGIN_ROLE_LOGIN, audience, req) )
16
+ *
17
+ * with domain `FINGERPRINT_DOMAIN` — an encoding of its own beside the proof's, pinned by
18
+ * vectors/login.json's login_fingerprint family. Throws for everything
19
+ * `loginBinding(LOGIN_ROLE_LOGIN, …)` throws for, and for a nonce shorter than `MIN_NONCE_SIZE`
20
+ * or longer than the u16 prefix allows.
21
+ */
22
+ export declare function fingerprint(audience: string, req: LoginRequest): Uint8Array;
23
+ /**
24
+ * `fp` as a person reads and compares it (docs/login.md §5.3): its 32 lowercase hex digits in
25
+ * eight groups of four, separated by single ASCII spaces — `7a91 b2c3 d4e5 f607 1829 3a4b 5c6d
26
+ * 7e8f`. The three lanes spell it identically, so the page's rendering and the CLI's can be
27
+ * compared character by character. Throws unless `fp` is exactly 16 bytes.
28
+ */
29
+ export declare function formatFingerprint(fp: Uint8Array): string;
@@ -0,0 +1,63 @@
1
+ // The transaction fingerprint a person compares before approving a login (docs/login.md §5.3).
2
+ //
3
+ // The page that began the login computes it from its own K and the begin response, in the
4
+ // browser; the CLI computes it from the exact request it is about to sign. So this module runs
5
+ // anywhere the package does: SHA-256 is @noble/hashes (as in request.ts), never node:crypto.
6
+ import { sha256 } from "@noble/hashes/sha2.js";
7
+ import { LOGIN_MAX_FIELD_SIZE, LOGIN_ROLE_LOGIN, loginBinding } from "./login.js";
8
+ import { MIN_NONCE_SIZE } from "./possession.js";
9
+ /**
10
+ * The label the transaction fingerprint's digest is computed under (docs/login.md §5.3). It is
11
+ * not an RFC 8032 context: nothing is signed with it, and no login proof's bytes are ever a
12
+ * fingerprint's input or the other way round.
13
+ */
14
+ export const FINGERPRINT_DOMAIN = "archon-login-fingerprint/1";
15
+ const DOMAIN_BYTES = new TextEncoder().encode(FINGERPRINT_DOMAIN);
16
+ /**
17
+ * The login's transaction fingerprint (docs/login.md §5.3), what a person compares before
18
+ * approving: the page that began the login computes it from its own K and the begin response,
19
+ * the CLI from the exact request it is about to sign, and the two agree only if every field the
20
+ * login proof binds — audience, K, id, scope, validity — and the nonce are the same on both
21
+ * sides. It is the first 16 bytes (128 bits) of
22
+ *
23
+ * SHA-256( u16be(len domain) ‖ domain ‖ u16be(len nonce) ‖ nonce ‖ loginBinding(LOGIN_ROLE_LOGIN, audience, req) )
24
+ *
25
+ * with domain `FINGERPRINT_DOMAIN` — an encoding of its own beside the proof's, pinned by
26
+ * vectors/login.json's login_fingerprint family. Throws for everything
27
+ * `loginBinding(LOGIN_ROLE_LOGIN, …)` throws for, and for a nonce shorter than `MIN_NONCE_SIZE`
28
+ * or longer than the u16 prefix allows.
29
+ */
30
+ export function fingerprint(audience, req) {
31
+ const binding = loginBinding(LOGIN_ROLE_LOGIN, audience, req);
32
+ if (req.nonce.length < MIN_NONCE_SIZE || req.nonce.length > LOGIN_MAX_FIELD_SIZE) {
33
+ throw new Error(`login: nonce is ${req.nonce.length} bytes, want ${MIN_NONCE_SIZE}..=${LOGIN_MAX_FIELD_SIZE}`);
34
+ }
35
+ const input = new Uint8Array(2 + DOMAIN_BYTES.length + 2 + req.nonce.length + binding.length);
36
+ let at = putField(input, 0, DOMAIN_BYTES);
37
+ at = putField(input, at, req.nonce);
38
+ input.set(binding, at);
39
+ return sha256(input).slice(0, 16);
40
+ }
41
+ /**
42
+ * `fp` as a person reads and compares it (docs/login.md §5.3): its 32 lowercase hex digits in
43
+ * eight groups of four, separated by single ASCII spaces — `7a91 b2c3 d4e5 f607 1829 3a4b 5c6d
44
+ * 7e8f`. The three lanes spell it identically, so the page's rendering and the CLI's can be
45
+ * compared character by character. Throws unless `fp` is exactly 16 bytes.
46
+ */
47
+ export function formatFingerprint(fp) {
48
+ if (fp.length !== 16)
49
+ throw new Error(`login: fingerprint is ${fp.length} bytes, want 16`);
50
+ const groups = [];
51
+ for (let i = 0; i < 16; i += 2) {
52
+ groups.push(fp[i].toString(16).padStart(2, "0") + fp[i + 1].toString(16).padStart(2, "0"));
53
+ }
54
+ return groups.join(" ");
55
+ }
56
+ /** Writes u16be(len field) ‖ field at `at`; returns the new offset. */
57
+ function putField(out, at, field) {
58
+ out[at++] = (field.length >> 8) & 0xff;
59
+ out[at++] = field.length & 0xff;
60
+ out.set(field, at);
61
+ return at + field.length;
62
+ }
63
+ //# sourceMappingURL=login-fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-fingerprint.js","sourceRoot":"","sources":["../../src/login-fingerprint.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,EAAE;AACF,0FAA0F;AAC1F,+FAA+F;AAC/F,6FAA6F;AAC7F,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAE/C,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,YAAY,EAAqB,MAAM,YAAY,CAAC;AACrG,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,4BAA4B,CAAC;AAE/D,MAAM,YAAY,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;AAElE;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,GAAiB;IAC7D,MAAM,OAAO,GAAG,YAAY,CAAC,gBAAgB,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC9D,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,cAAc,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,oBAAoB,EAAE,CAAC;QACjF,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,CAAC,KAAK,CAAC,MAAM,gBAAgB,cAAc,MAAM,oBAAoB,EAAE,CAAC,CAAC;IACjH,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,CAAC,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9F,IAAI,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;IAC1C,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IACpC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACvB,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACpC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAAc;IAC9C,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,EAAE,CAAC,MAAM,iBAAiB,CAAC,CAAC;IAC3F,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC/F,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,uEAAuE;AACvE,SAAS,QAAQ,CAAC,GAAe,EAAE,EAAU,EAAE,KAAiB;IAC9D,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;IACvC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IAChC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACnB,OAAO,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC;AAC3B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitspark/archon-sdk",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "archon-sdk: proof of possession and the signed envelope, one layer above the identity floor. Deterministic given its inputs; no RNG, no clock, no socket.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -22,7 +22,7 @@
22
22
  "test": "tsc -p tsconfig.json && node --test dist/test/*.test.js"
23
23
  },
24
24
  "dependencies": {
25
- "@bitspark/archon": "^0.14.0",
25
+ "@bitspark/archon": "^0.15.0",
26
26
  "@noble/hashes": "^2.2.0"
27
27
  },
28
28
  "devDependencies": {