@orangecheck/stamp-ots 0.1.1 → 0.2.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/README.md +17 -19
- package/dist/index.d.mts +66 -4
- package/dist/index.d.ts +66 -4
- package/dist/index.js +373 -106
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +363 -107
- package/dist/index.mjs.map +1 -1
- package/package.json +60 -64
- package/src/anchor.test.ts +72 -0
- package/src/anchor.ts +78 -135
- package/src/calendar.test.ts +37 -0
- package/src/calendar.ts +8 -9
- package/src/index.ts +19 -2
- package/src/ots-fixture.test-helper.ts +24 -0
- package/src/ots.test.ts +34 -0
- package/src/ots.ts +320 -0
- package/src/submit.test.ts +0 -17
- package/src/types.ts +7 -6
- package/src/upgrade.test.ts +110 -0
- package/src/upgrade.ts +72 -67
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# @orangecheck/stamp-ots
|
|
2
2
|
|
|
3
|
+
> **Full reference:** [docs.ochk.io/sdk/stamp-ots](https://docs.ochk.io/sdk/stamp-ots) — auto-generated from the TypeScript source on every release.
|
|
4
|
+
> Hand-written prose below is the high-level overview; the docs site is the source of truth for every export, type, and signature.
|
|
5
|
+
|
|
6
|
+
|
|
3
7
|
OpenTimestamps calendar client, proof helpers, and anchor-verification hooks for [OC Stamp](https://github.com/orangecheck/oc-stamp-protocol) envelopes.
|
|
4
8
|
|
|
5
9
|
## Install
|
|
@@ -13,31 +17,24 @@ npm i @orangecheck/stamp-core @orangecheck/stamp-ots
|
|
|
13
17
|
OC Stamp envelopes carry an optional `ots` field that anchors the envelope `id` to a Bitcoin block via the [OpenTimestamps](https://opentimestamps.org) protocol. This package provides the thin client-side glue:
|
|
14
18
|
|
|
15
19
|
- **`submitToCalendars(id, opts)`** — POST the envelope's 32-byte digest to one or more OTS calendars. Returns a pending `OtsProof` you can fold into the envelope's `ots` field.
|
|
16
|
-
- **`upgradeProof(proof, id,
|
|
17
|
-
- **`createCalendarClient(url)`** — low-level HTTP client implementing the minimal OTS calendar API (`POST /digest`, `GET /timestamp/<hex>`).
|
|
18
|
-
- **`makeAnchorVerifier({
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
- **`upgradeProof(proof, id, { headerSource })`** — ask each calendar for the continuation of its pending attestation (calendars index upgrades by that commitment) and graft it on. Returns a confirmed `OtsProof` once the proof reaches a Bitcoin block whose header checks out.
|
|
21
|
+
- **`createCalendarClient(url)`** — low-level HTTP client implementing the minimal OTS calendar API (`POST /digest`, `GET /timestamp/<hex(commitment)>`).
|
|
22
|
+
- **`makeAnchorVerifier({ headerSource })`** — the `verifyOtsAnchor` hook for `verify()` from `@orangecheck/stamp-core`. It walks the proof with the built-in OTS parser and requires that the proof commits to the envelope id, attests at the declared height, and that the header at that height has the proof's Merkle root and hashes to the declared block hash.
|
|
23
|
+
- **`mempoolHeaderSource(opts)`** — block headers from an Esplora-compatible API (default `https://mempool.space/api`). Each header is checked against the declared block hash, so this source is trusted only to say which block sits at a height. Supply your own node or headers snapshot to remove that trust.
|
|
24
|
+
- **`parseProof` / `parseDetached` / `serializeTimestamp` / `bitcoinAnchors` / `pendingCommitments`** — the OTS proof format, accepting both the bare timestamp carried in `ots.proof` and detached `.ots` files.
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
Consumers who want fully-offline verification should combine:
|
|
26
|
+
## Verify an anchor
|
|
25
27
|
|
|
26
28
|
```ts
|
|
27
29
|
import { verify } from '@orangecheck/stamp-core';
|
|
28
|
-
import { makeAnchorVerifier,
|
|
29
|
-
import { myOtsParser, myHeaderSource } from './your-adapters';
|
|
30
|
-
|
|
31
|
-
const anchor = makeAnchorVerifier({
|
|
32
|
-
walkProof: myOtsParser,
|
|
33
|
-
headerSource: myHeaderSource,
|
|
34
|
-
});
|
|
30
|
+
import { makeAnchorVerifier, mempoolHeaderSource } from '@orangecheck/stamp-ots';
|
|
35
31
|
|
|
36
32
|
const result = await verify({
|
|
37
33
|
envelope: env,
|
|
38
|
-
verifyOtsAnchor:
|
|
34
|
+
verifyOtsAnchor: makeAnchorVerifier({ headerSource: mempoolHeaderSource() }),
|
|
39
35
|
verifyBip322: myBip322Verifier,
|
|
40
36
|
});
|
|
37
|
+
// result.anchor.verified is true only when the proof checked out.
|
|
41
38
|
```
|
|
42
39
|
|
|
43
40
|
## Usage
|
|
@@ -57,11 +54,11 @@ const envWithOts = { ...env, ots: toStampOts(proof) };
|
|
|
57
54
|
### Upgrade later
|
|
58
55
|
|
|
59
56
|
```ts
|
|
60
|
-
import {
|
|
57
|
+
import { fromStampOts, mempoolHeaderSource, toStampOts, upgradeProof } from '@orangecheck/stamp-ots';
|
|
61
58
|
|
|
62
59
|
const current = fromStampOts(envWithOts.ots!);
|
|
63
60
|
const upgraded = await upgradeProof(current, envWithOts.id, {
|
|
64
|
-
|
|
61
|
+
headerSource: mempoolHeaderSource(),
|
|
65
62
|
});
|
|
66
63
|
const envUpgraded = { ...envWithOts, ots: toStampOts(upgraded) };
|
|
67
64
|
```
|
|
@@ -70,7 +67,8 @@ const envUpgraded = { ...envWithOts, ots: toStampOts(upgraded) };
|
|
|
70
67
|
|
|
71
68
|
- `submitToCalendars(id, opts)` / `upgradeProof(proof, id, opts)`
|
|
72
69
|
- `createCalendarClient(url, opts)` / `DEFAULT_CALENDARS`
|
|
73
|
-
- `makeAnchorVerifier(config)` / `
|
|
70
|
+
- `makeAnchorVerifier(config)` / `makeDefaultAnchorVerifier(config)` / `mempoolHeaderSource(opts)` / `walkOtsProof(input)` / `blockHashOf(header)`
|
|
71
|
+
- `parseProof` / `parseDetached` / `parseTimestamp` / `serializeTimestamp` / `bitcoinAnchors` / `pendingCommitments` / `mergeAt` / `attestations`
|
|
74
72
|
- `toStampOts(proof)` / `fromStampOts(stampOts)` — shape adapters
|
|
75
73
|
- `base64Encode` / `base64Decode` / `hexEncode` / `hexDecode`
|
|
76
74
|
- Types: `OtsProof`, `CalendarClient`, `AnchorVerifier`, `BlockHeaderSource`, etc.
|
package/dist/index.d.mts
CHANGED
|
@@ -12,7 +12,7 @@ interface OtsProof {
|
|
|
12
12
|
interface CalendarClient {
|
|
13
13
|
readonly url: string;
|
|
14
14
|
submit(digest: Uint8Array, signal?: AbortSignal): Promise<Uint8Array>;
|
|
15
|
-
fetchProof(
|
|
15
|
+
fetchProof(commitment: Uint8Array, signal?: AbortSignal): Promise<Uint8Array | null>;
|
|
16
16
|
}
|
|
17
17
|
interface AnchorVerificationInput {
|
|
18
18
|
proofBytes: Uint8Array;
|
|
@@ -57,7 +57,8 @@ interface SubmitOptions {
|
|
|
57
57
|
declare function submitToCalendars(idHex: string, opts?: SubmitOptions): Promise<OtsProof>;
|
|
58
58
|
|
|
59
59
|
interface UpgradeOptions {
|
|
60
|
-
|
|
60
|
+
headerSource?: BlockHeaderSource;
|
|
61
|
+
parseAnchor?: (proofBytes: Uint8Array) => Promise<{
|
|
61
62
|
blockHeight: number;
|
|
62
63
|
blockHash: string;
|
|
63
64
|
} | null>;
|
|
@@ -68,18 +69,79 @@ interface UpgradeOptions {
|
|
|
68
69
|
declare function upgradeProof(current: OtsProof, idHex: string, opts: UpgradeOptions): Promise<OtsProof>;
|
|
69
70
|
|
|
70
71
|
interface AnchorVerifierConfig {
|
|
71
|
-
walkProof
|
|
72
|
+
walkProof?: (input: {
|
|
72
73
|
proofBytes: Uint8Array;
|
|
73
74
|
digest: Uint8Array;
|
|
75
|
+
blockHeight?: number;
|
|
74
76
|
}) => Promise<{
|
|
75
77
|
merkleRoot: Uint8Array;
|
|
76
78
|
blockHeight: number;
|
|
77
79
|
} | null>;
|
|
78
80
|
headerSource: BlockHeaderSource;
|
|
79
81
|
}
|
|
82
|
+
declare function walkOtsProof(input: {
|
|
83
|
+
proofBytes: Uint8Array;
|
|
84
|
+
digest: Uint8Array;
|
|
85
|
+
blockHeight?: number;
|
|
86
|
+
}): Promise<{
|
|
87
|
+
merkleRoot: Uint8Array;
|
|
88
|
+
blockHeight: number;
|
|
89
|
+
} | null>;
|
|
90
|
+
declare function blockHashOf(header: Uint8Array): string;
|
|
80
91
|
declare function makeAnchorVerifier(cfg: AnchorVerifierConfig): (proofB64: string, blockHeight: number, blockHash: string, envelopeId: string) => Promise<boolean>;
|
|
81
92
|
declare function makeDefaultAnchorVerifier(opts: {
|
|
82
93
|
headerSource: BlockHeaderSource;
|
|
83
94
|
}): Promise<(proofB64: string, blockHeight: number, blockHash: string, envelopeId: string) => Promise<boolean>>;
|
|
95
|
+
interface MempoolHeaderSourceOptions {
|
|
96
|
+
baseUrl?: string;
|
|
97
|
+
fetch?: typeof fetch;
|
|
98
|
+
}
|
|
99
|
+
declare function mempoolHeaderSource(opts?: MempoolHeaderSourceOptions): BlockHeaderSource;
|
|
100
|
+
|
|
101
|
+
type OtsOp = {
|
|
102
|
+
kind: 'sha256' | 'ripemd160' | 'sha1' | 'keccak256' | 'reverse' | 'hexlify';
|
|
103
|
+
} | {
|
|
104
|
+
kind: 'append' | 'prepend';
|
|
105
|
+
arg: Uint8Array;
|
|
106
|
+
};
|
|
107
|
+
type OtsAttestation = {
|
|
108
|
+
kind: 'bitcoin';
|
|
109
|
+
height: number;
|
|
110
|
+
} | {
|
|
111
|
+
kind: 'pending';
|
|
112
|
+
uri: string;
|
|
113
|
+
} | {
|
|
114
|
+
kind: 'unknown';
|
|
115
|
+
tag: string;
|
|
116
|
+
payload: Uint8Array;
|
|
117
|
+
};
|
|
118
|
+
interface OtsTimestamp {
|
|
119
|
+
msg: Uint8Array;
|
|
120
|
+
attestations: OtsAttestation[];
|
|
121
|
+
ops: {
|
|
122
|
+
op: OtsOp;
|
|
123
|
+
child: OtsTimestamp;
|
|
124
|
+
}[];
|
|
125
|
+
}
|
|
126
|
+
declare function parseTimestamp(bytes: Uint8Array, digest: Uint8Array): OtsTimestamp;
|
|
127
|
+
declare function parseDetached(bytes: Uint8Array): {
|
|
128
|
+
digest: Uint8Array;
|
|
129
|
+
timestamp: OtsTimestamp;
|
|
130
|
+
};
|
|
131
|
+
declare function parseProof(bytes: Uint8Array, digest: Uint8Array): OtsTimestamp;
|
|
132
|
+
declare function attestations(ts: OtsTimestamp): {
|
|
133
|
+
msg: Uint8Array;
|
|
134
|
+
attestation: OtsAttestation;
|
|
135
|
+
}[];
|
|
136
|
+
declare function bitcoinAnchors(ts: OtsTimestamp): {
|
|
137
|
+
blockHeight: number;
|
|
138
|
+
merkleRoot: Uint8Array;
|
|
139
|
+
}[];
|
|
140
|
+
declare function pendingCommitments(ts: OtsTimestamp): {
|
|
141
|
+
uri: string;
|
|
142
|
+
commitment: Uint8Array;
|
|
143
|
+
}[];
|
|
144
|
+
declare function mergeAt(ts: OtsTimestamp, upgrade: OtsTimestamp): boolean;
|
|
145
|
+
declare function serializeTimestamp(ts: OtsTimestamp): Uint8Array;
|
|
84
146
|
|
|
85
|
-
export { type AnchorVerificationInput, type AnchorVerificationResult, type AnchorVerifier, type AnchorVerifierConfig, type BlockHeaderSource, type CalendarClient, DEFAULT_CALENDARS, type HttpCalendarOptions, type OtsProof, type OtsProofStatus, type SubmitOptions, type UpgradeOptions, base64Decode, base64Encode, createCalendarClient, fromStampOts, hexDecode, hexEncode, makeAnchorVerifier, makeDefaultAnchorVerifier, submitToCalendars, toStampOts, upgradeProof };
|
|
147
|
+
export { type AnchorVerificationInput, type AnchorVerificationResult, type AnchorVerifier, type AnchorVerifierConfig, type BlockHeaderSource, type CalendarClient, DEFAULT_CALENDARS, type HttpCalendarOptions, type MempoolHeaderSourceOptions, type OtsAttestation, type OtsOp, type OtsProof, type OtsProofStatus, type OtsTimestamp, type SubmitOptions, type UpgradeOptions, attestations, base64Decode, base64Encode, bitcoinAnchors, blockHashOf, createCalendarClient, fromStampOts, hexDecode, hexEncode, makeAnchorVerifier, makeDefaultAnchorVerifier, mempoolHeaderSource, mergeAt, parseDetached, parseProof, parseTimestamp, pendingCommitments, serializeTimestamp, submitToCalendars, toStampOts, upgradeProof, walkOtsProof };
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ interface OtsProof {
|
|
|
12
12
|
interface CalendarClient {
|
|
13
13
|
readonly url: string;
|
|
14
14
|
submit(digest: Uint8Array, signal?: AbortSignal): Promise<Uint8Array>;
|
|
15
|
-
fetchProof(
|
|
15
|
+
fetchProof(commitment: Uint8Array, signal?: AbortSignal): Promise<Uint8Array | null>;
|
|
16
16
|
}
|
|
17
17
|
interface AnchorVerificationInput {
|
|
18
18
|
proofBytes: Uint8Array;
|
|
@@ -57,7 +57,8 @@ interface SubmitOptions {
|
|
|
57
57
|
declare function submitToCalendars(idHex: string, opts?: SubmitOptions): Promise<OtsProof>;
|
|
58
58
|
|
|
59
59
|
interface UpgradeOptions {
|
|
60
|
-
|
|
60
|
+
headerSource?: BlockHeaderSource;
|
|
61
|
+
parseAnchor?: (proofBytes: Uint8Array) => Promise<{
|
|
61
62
|
blockHeight: number;
|
|
62
63
|
blockHash: string;
|
|
63
64
|
} | null>;
|
|
@@ -68,18 +69,79 @@ interface UpgradeOptions {
|
|
|
68
69
|
declare function upgradeProof(current: OtsProof, idHex: string, opts: UpgradeOptions): Promise<OtsProof>;
|
|
69
70
|
|
|
70
71
|
interface AnchorVerifierConfig {
|
|
71
|
-
walkProof
|
|
72
|
+
walkProof?: (input: {
|
|
72
73
|
proofBytes: Uint8Array;
|
|
73
74
|
digest: Uint8Array;
|
|
75
|
+
blockHeight?: number;
|
|
74
76
|
}) => Promise<{
|
|
75
77
|
merkleRoot: Uint8Array;
|
|
76
78
|
blockHeight: number;
|
|
77
79
|
} | null>;
|
|
78
80
|
headerSource: BlockHeaderSource;
|
|
79
81
|
}
|
|
82
|
+
declare function walkOtsProof(input: {
|
|
83
|
+
proofBytes: Uint8Array;
|
|
84
|
+
digest: Uint8Array;
|
|
85
|
+
blockHeight?: number;
|
|
86
|
+
}): Promise<{
|
|
87
|
+
merkleRoot: Uint8Array;
|
|
88
|
+
blockHeight: number;
|
|
89
|
+
} | null>;
|
|
90
|
+
declare function blockHashOf(header: Uint8Array): string;
|
|
80
91
|
declare function makeAnchorVerifier(cfg: AnchorVerifierConfig): (proofB64: string, blockHeight: number, blockHash: string, envelopeId: string) => Promise<boolean>;
|
|
81
92
|
declare function makeDefaultAnchorVerifier(opts: {
|
|
82
93
|
headerSource: BlockHeaderSource;
|
|
83
94
|
}): Promise<(proofB64: string, blockHeight: number, blockHash: string, envelopeId: string) => Promise<boolean>>;
|
|
95
|
+
interface MempoolHeaderSourceOptions {
|
|
96
|
+
baseUrl?: string;
|
|
97
|
+
fetch?: typeof fetch;
|
|
98
|
+
}
|
|
99
|
+
declare function mempoolHeaderSource(opts?: MempoolHeaderSourceOptions): BlockHeaderSource;
|
|
100
|
+
|
|
101
|
+
type OtsOp = {
|
|
102
|
+
kind: 'sha256' | 'ripemd160' | 'sha1' | 'keccak256' | 'reverse' | 'hexlify';
|
|
103
|
+
} | {
|
|
104
|
+
kind: 'append' | 'prepend';
|
|
105
|
+
arg: Uint8Array;
|
|
106
|
+
};
|
|
107
|
+
type OtsAttestation = {
|
|
108
|
+
kind: 'bitcoin';
|
|
109
|
+
height: number;
|
|
110
|
+
} | {
|
|
111
|
+
kind: 'pending';
|
|
112
|
+
uri: string;
|
|
113
|
+
} | {
|
|
114
|
+
kind: 'unknown';
|
|
115
|
+
tag: string;
|
|
116
|
+
payload: Uint8Array;
|
|
117
|
+
};
|
|
118
|
+
interface OtsTimestamp {
|
|
119
|
+
msg: Uint8Array;
|
|
120
|
+
attestations: OtsAttestation[];
|
|
121
|
+
ops: {
|
|
122
|
+
op: OtsOp;
|
|
123
|
+
child: OtsTimestamp;
|
|
124
|
+
}[];
|
|
125
|
+
}
|
|
126
|
+
declare function parseTimestamp(bytes: Uint8Array, digest: Uint8Array): OtsTimestamp;
|
|
127
|
+
declare function parseDetached(bytes: Uint8Array): {
|
|
128
|
+
digest: Uint8Array;
|
|
129
|
+
timestamp: OtsTimestamp;
|
|
130
|
+
};
|
|
131
|
+
declare function parseProof(bytes: Uint8Array, digest: Uint8Array): OtsTimestamp;
|
|
132
|
+
declare function attestations(ts: OtsTimestamp): {
|
|
133
|
+
msg: Uint8Array;
|
|
134
|
+
attestation: OtsAttestation;
|
|
135
|
+
}[];
|
|
136
|
+
declare function bitcoinAnchors(ts: OtsTimestamp): {
|
|
137
|
+
blockHeight: number;
|
|
138
|
+
merkleRoot: Uint8Array;
|
|
139
|
+
}[];
|
|
140
|
+
declare function pendingCommitments(ts: OtsTimestamp): {
|
|
141
|
+
uri: string;
|
|
142
|
+
commitment: Uint8Array;
|
|
143
|
+
}[];
|
|
144
|
+
declare function mergeAt(ts: OtsTimestamp, upgrade: OtsTimestamp): boolean;
|
|
145
|
+
declare function serializeTimestamp(ts: OtsTimestamp): Uint8Array;
|
|
84
146
|
|
|
85
|
-
export { type AnchorVerificationInput, type AnchorVerificationResult, type AnchorVerifier, type AnchorVerifierConfig, type BlockHeaderSource, type CalendarClient, DEFAULT_CALENDARS, type HttpCalendarOptions, type OtsProof, type OtsProofStatus, type SubmitOptions, type UpgradeOptions, base64Decode, base64Encode, createCalendarClient, fromStampOts, hexDecode, hexEncode, makeAnchorVerifier, makeDefaultAnchorVerifier, submitToCalendars, toStampOts, upgradeProof };
|
|
147
|
+
export { type AnchorVerificationInput, type AnchorVerificationResult, type AnchorVerifier, type AnchorVerifierConfig, type BlockHeaderSource, type CalendarClient, DEFAULT_CALENDARS, type HttpCalendarOptions, type MempoolHeaderSourceOptions, type OtsAttestation, type OtsOp, type OtsProof, type OtsProofStatus, type OtsTimestamp, type SubmitOptions, type UpgradeOptions, attestations, base64Decode, base64Encode, bitcoinAnchors, blockHashOf, createCalendarClient, fromStampOts, hexDecode, hexEncode, makeAnchorVerifier, makeDefaultAnchorVerifier, mempoolHeaderSource, mergeAt, parseDetached, parseProof, parseTimestamp, pendingCommitments, serializeTimestamp, submitToCalendars, toStampOts, upgradeProof, walkOtsProof };
|