c2pa-text-binding 0.2.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.
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ <p align="center">
2
+ <h1 align="center">c2pa-text-binding</h1>
3
+ <p align="center">C2PA soft binding and content fingerprinting for text assets</p>
4
+ </p>
5
+
6
+ <p align="center">
7
+ <a href="https://github.com/writerslogic/c2pa-text-binding/actions/workflows/ci.yml"><img src="https://github.com/writerslogic/c2pa-text-binding/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
8
+ <a href="https://crates.io/crates/c2pa-text-binding"><img src="https://img.shields.io/crates/v/c2pa-text-binding.svg" alt="crates.io"></a>
9
+ <a href="https://docs.rs/c2pa-text-binding"><img src="https://docs.rs/c2pa-text-binding/badge.svg" alt="docs.rs"></a>
10
+ <a href="#license"><img src="https://img.shields.io/crates/l/c2pa-text-binding.svg" alt="License"></a>
11
+ </p>
12
+
13
+ ## Overview
14
+
15
+ A concrete family of text soft-binding algorithms compatible with the [C2PA Soft Binding](https://spec.c2pa.org/) framework, each registered in the [C2PA soft binding algorithm list](https://github.com/c2pa-org/softbinding-algorithm-list). A soft binding derives a content-keyed value that survives reformatting, re-encoding, excerpting, and light editing, so a manifest is recoverable when the hard binding — a byte-exact hash — has been broken.
16
+
17
+ | Module | Algorithm (list id) | Kind |
18
+ |---|---|---|
19
+ | `simhash` | `com.writerslogic.text-fingerprint.1` (41) | surface fingerprint |
20
+ | `stego` | `com.writerslogic.zwc-watermark.2` (42) | zero-width watermark |
21
+ | `structure` | `com.writerslogic.text-structure.1` (43) | structural fingerprint |
22
+ | `minhash` | `com.writerslogic.text-minhash.1` (44) | excerpt/quotation fingerprint |
23
+
24
+ This crate is the **perceptual/watermark recovery layer**. It is distinct from the Variation-Selector transport used elsewhere in WritersProof, which is a *hard* binding (a `c2pa.hash.data` over normalized text) and is not soft binding. Registration in the algorithm list is **not** C2PA conformance certification.
25
+
26
+ ## Quick Start
27
+
28
+ ```toml
29
+ [dependencies]
30
+ c2pa-text-binding = "0.1"
31
+ ```
32
+
33
+ ### Emit and sign a `c2pa.soft-binding` assertion
34
+
35
+ `soft_binding` builds the normative CBOR assertion (it round-trips through the
36
+ `c2pa-rs` reader — see `tests/c2pa_roundtrip.rs`); `manifest` signs it as a
37
+ COSE_Sign1 / EdDSA envelope.
38
+
39
+ ```rust
40
+ use c2pa_text_binding::{simhash::Fingerprint, soft_binding, sign_cose, SOFT_BINDING_LABEL};
41
+
42
+ let text = "…the document being bound…";
43
+ let secret_key = [7u8; 32]; // caller-supplied Ed25519 secret
44
+ let assertion = soft_binding::from_fingerprint(&Fingerprint::compute(text));
45
+ let cbor = assertion.to_cbor()?; // store under SOFT_BINDING_LABEL
46
+ let signed = sign_cose(&cbor, &secret_key)?; // detached-key COSE_Sign1
47
+ # Ok::<(), c2pa_text_binding::Error>(())
48
+ ```
49
+
50
+ ### Recover and classify a candidate
51
+
52
+ The verify path recomputes the fingerprint from the current text, compares it to
53
+ the stored value at the algorithm's registered threshold, and returns a
54
+ confidence tier. BOUND requires a *durable* fingerprint match (41/44, measured
55
+ zero false matches) plus the anti-transfer cross-check; a structural (43) match
56
+ or a watermark hit alone caps at LIKELY. Tier thresholds are grounded in
57
+ [`ROBUSTNESS.md`](ROBUSTNESS.md).
58
+
59
+ ```rust
60
+ use c2pa_text_binding::{simhash::Fingerprint, soft_binding::{self, SoftBinding}, verify, Confidence};
61
+
62
+ let text = "…the document being bound…";
63
+ let cbor = soft_binding::from_fingerprint(&Fingerprint::compute(text)).to_cbor()?;
64
+
65
+ let candidate = SoftBinding::from_cbor(&cbor)?;
66
+ let tier = verify(text, &candidate, /*watermark_verified=*/ false, /*crosscheck_ok=*/ true);
67
+ assert_eq!(tier, Confidence::Bound);
68
+ # Ok::<(), c2pa_text_binding::Error>(())
69
+ ```
70
+
71
+ ### Register with the Soft Binding Resolution API
72
+
73
+ These algorithms are registered in the [C2PA soft binding algorithm list](https://github.com/c2pa-org/softbinding-algorithm-list), so a `c2pa.soft-binding` assertion referencing them can drive [decentralized manifest recovery](https://spec.c2pa.org/).
74
+
75
+ ## Related Crates
76
+
77
+ | Crate | Description |
78
+ |---|---|
79
+ | [c2pa-structured-text](https://github.com/writerslogic/c2pa-structured-text) | Structured text embedding via ASCII armour delimiters |
80
+ | [c2pa-text](https://crates.io/crates/c2pa-text) | Unstructured text embedding via Unicode Variation Selectors |
81
+ | [c2pa-rs](https://crates.io/crates/c2pa) | Official C2PA SDK |
82
+
83
+ ## License
84
+
85
+ Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT License](LICENSE-MIT) at your option.
86
+
87
+ Built by [WritersLogic](https://writerslogic.com)
@@ -0,0 +1,145 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * SHA-256 of the canonical stream (the blind-recoverable content hash), hex.
6
+ */
7
+ export function content_hash(text: string): string;
8
+
9
+ /**
10
+ * Anti-transfer cross-check tag (hex): `HMAC(key, repo_id ‖ content_hash)`.
11
+ */
12
+ export function cross_check(key_hex: string, repo_id: string, content_hash_hex: string): string;
13
+
14
+ /**
15
+ * Embed a `zwc-watermark.2` carrying `pointer_hex`, bound to the content by
16
+ * `key_hex`. Returns the watermarked text.
17
+ */
18
+ export function embed_watermark(text: string, pointer_hex: string, key_hex: string): string;
19
+
20
+ /**
21
+ * Blind-extract and verify a `zwc-watermark.2`. Returns
22
+ * `{"pointer":"<hex>","verified":<bool>,"recovered":<n>}`.
23
+ */
24
+ export function extract_watermark(text: string, key_hex: string): string;
25
+
26
+ /**
27
+ * Hamming distance in bits between two 256-bit hex fingerprints.
28
+ */
29
+ export function hamming_hex(a: string, b: string): number;
30
+
31
+ /**
32
+ * The 32 LSH band hashes, comma-joined — index keys for discovery.
33
+ */
34
+ export function minhash_bands(text: string): string;
35
+
36
+ /**
37
+ * Estimated Jaccard from two comma-joined MinHash signatures.
38
+ */
39
+ export function minhash_jaccard(sig_a: string, sig_b: string): number;
40
+
41
+ /**
42
+ * `com.writerslogic.text-minhash.1` — 128 signature values, comma-joined.
43
+ */
44
+ export function minhash_signature(text: string): string;
45
+
46
+ /**
47
+ * Derive the Ed25519 public key (hex) from a 32-byte secret key (hex).
48
+ */
49
+ export function public_key(secret_hex: string): string;
50
+
51
+ /**
52
+ * Sign a payload (e.g. the soft-binding assertion JSON) as tagged
53
+ * COSE_Sign1 / EdDSA. Returns the envelope as hex.
54
+ */
55
+ export function sign(payload: string, secret_hex: string): string;
56
+
57
+ /**
58
+ * Build the `c2pa.soft-binding` assertion (list id 41, surface fingerprint)
59
+ * as CBOR, hex-encoded. Sign the result with [`sign`] and store it under the
60
+ * `c2pa.soft-binding` label. Includes per-window scoped blocks.
61
+ */
62
+ export function soft_binding_fingerprint(text: string): string;
63
+
64
+ /**
65
+ * Build the `c2pa.soft-binding` assertion (list id 44, MinHash) as CBOR hex.
66
+ */
67
+ export function soft_binding_minhash(text: string): string;
68
+
69
+ /**
70
+ * Build the `c2pa.soft-binding` assertion (list id 43, structural) as CBOR hex.
71
+ */
72
+ export function soft_binding_structure(text: string): string;
73
+
74
+ /**
75
+ * Build the `c2pa.soft-binding` assertion (list id 42, ZWC watermark) for a
76
+ * routing `pointer_hex`, as CBOR hex.
77
+ */
78
+ export function soft_binding_watermark(pointer_hex: string): string;
79
+
80
+ /**
81
+ * `com.writerslogic.text-fingerprint.1` — 256-bit surface SimHash, hex.
82
+ */
83
+ export function text_fingerprint(text: string): string;
84
+
85
+ /**
86
+ * `com.writerslogic.text-structure.1` — 256-bit structural SimHash, hex.
87
+ */
88
+ export function text_structure(text: string): string;
89
+
90
+ /**
91
+ * Verify a hex COSE_Sign1 envelope against a hex public key; returns the
92
+ * payload string on success, throws on failure.
93
+ */
94
+ export function verify(cose_hex: string, public_hex: string): string;
95
+
96
+ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
97
+
98
+ export interface InitOutput {
99
+ readonly memory: WebAssembly.Memory;
100
+ readonly content_hash: (a: number, b: number) => [number, number];
101
+ readonly cross_check: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number, number];
102
+ readonly embed_watermark: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number, number];
103
+ readonly extract_watermark: (a: number, b: number, c: number, d: number) => [number, number, number, number];
104
+ readonly hamming_hex: (a: number, b: number, c: number, d: number) => [number, number, number];
105
+ readonly minhash_bands: (a: number, b: number) => [number, number];
106
+ readonly minhash_jaccard: (a: number, b: number, c: number, d: number) => [number, number, number];
107
+ readonly minhash_signature: (a: number, b: number) => [number, number];
108
+ readonly public_key: (a: number, b: number) => [number, number, number, number];
109
+ readonly sign: (a: number, b: number, c: number, d: number) => [number, number, number, number];
110
+ readonly soft_binding_fingerprint: (a: number, b: number) => [number, number];
111
+ readonly soft_binding_minhash: (a: number, b: number) => [number, number];
112
+ readonly soft_binding_structure: (a: number, b: number) => [number, number];
113
+ readonly soft_binding_watermark: (a: number, b: number) => [number, number, number, number];
114
+ readonly text_fingerprint: (a: number, b: number) => [number, number];
115
+ readonly text_structure: (a: number, b: number) => [number, number];
116
+ readonly verify: (a: number, b: number, c: number, d: number) => [number, number, number, number];
117
+ readonly __wbindgen_externrefs: WebAssembly.Table;
118
+ readonly __wbindgen_malloc: (a: number, b: number) => number;
119
+ readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
120
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
121
+ readonly __externref_table_dealloc: (a: number) => void;
122
+ readonly __wbindgen_start: () => void;
123
+ }
124
+
125
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
126
+
127
+ /**
128
+ * Instantiates the given `module`, which can either be bytes or
129
+ * a precompiled `WebAssembly.Module`.
130
+ *
131
+ * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
132
+ *
133
+ * @returns {InitOutput}
134
+ */
135
+ export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
136
+
137
+ /**
138
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
139
+ * for everything else, calls `WebAssembly.instantiate` directly.
140
+ *
141
+ * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
142
+ *
143
+ * @returns {Promise<InitOutput>}
144
+ */
145
+ export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
@@ -0,0 +1,606 @@
1
+ /* @ts-self-types="./c2pa_text_binding.d.ts" */
2
+
3
+ /**
4
+ * SHA-256 of the canonical stream (the blind-recoverable content hash), hex.
5
+ * @param {string} text
6
+ * @returns {string}
7
+ */
8
+ export function content_hash(text) {
9
+ let deferred2_0;
10
+ let deferred2_1;
11
+ try {
12
+ const ptr0 = passStringToWasm0(text, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
13
+ const len0 = WASM_VECTOR_LEN;
14
+ const ret = wasm.content_hash(ptr0, len0);
15
+ deferred2_0 = ret[0];
16
+ deferred2_1 = ret[1];
17
+ return getStringFromWasm0(ret[0], ret[1]);
18
+ } finally {
19
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Anti-transfer cross-check tag (hex): `HMAC(key, repo_id ‖ content_hash)`.
25
+ * @param {string} key_hex
26
+ * @param {string} repo_id
27
+ * @param {string} content_hash_hex
28
+ * @returns {string}
29
+ */
30
+ export function cross_check(key_hex, repo_id, content_hash_hex) {
31
+ let deferred5_0;
32
+ let deferred5_1;
33
+ try {
34
+ const ptr0 = passStringToWasm0(key_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
35
+ const len0 = WASM_VECTOR_LEN;
36
+ const ptr1 = passStringToWasm0(repo_id, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
37
+ const len1 = WASM_VECTOR_LEN;
38
+ const ptr2 = passStringToWasm0(content_hash_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
39
+ const len2 = WASM_VECTOR_LEN;
40
+ const ret = wasm.cross_check(ptr0, len0, ptr1, len1, ptr2, len2);
41
+ var ptr4 = ret[0];
42
+ var len4 = ret[1];
43
+ if (ret[3]) {
44
+ ptr4 = 0; len4 = 0;
45
+ throw takeFromExternrefTable0(ret[2]);
46
+ }
47
+ deferred5_0 = ptr4;
48
+ deferred5_1 = len4;
49
+ return getStringFromWasm0(ptr4, len4);
50
+ } finally {
51
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Embed a `zwc-watermark.2` carrying `pointer_hex`, bound to the content by
57
+ * `key_hex`. Returns the watermarked text.
58
+ * @param {string} text
59
+ * @param {string} pointer_hex
60
+ * @param {string} key_hex
61
+ * @returns {string}
62
+ */
63
+ export function embed_watermark(text, pointer_hex, key_hex) {
64
+ let deferred5_0;
65
+ let deferred5_1;
66
+ try {
67
+ const ptr0 = passStringToWasm0(text, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
68
+ const len0 = WASM_VECTOR_LEN;
69
+ const ptr1 = passStringToWasm0(pointer_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
70
+ const len1 = WASM_VECTOR_LEN;
71
+ const ptr2 = passStringToWasm0(key_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
72
+ const len2 = WASM_VECTOR_LEN;
73
+ const ret = wasm.embed_watermark(ptr0, len0, ptr1, len1, ptr2, len2);
74
+ var ptr4 = ret[0];
75
+ var len4 = ret[1];
76
+ if (ret[3]) {
77
+ ptr4 = 0; len4 = 0;
78
+ throw takeFromExternrefTable0(ret[2]);
79
+ }
80
+ deferred5_0 = ptr4;
81
+ deferred5_1 = len4;
82
+ return getStringFromWasm0(ptr4, len4);
83
+ } finally {
84
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Blind-extract and verify a `zwc-watermark.2`. Returns
90
+ * `{"pointer":"<hex>","verified":<bool>,"recovered":<n>}`.
91
+ * @param {string} text
92
+ * @param {string} key_hex
93
+ * @returns {string}
94
+ */
95
+ export function extract_watermark(text, key_hex) {
96
+ let deferred4_0;
97
+ let deferred4_1;
98
+ try {
99
+ const ptr0 = passStringToWasm0(text, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
100
+ const len0 = WASM_VECTOR_LEN;
101
+ const ptr1 = passStringToWasm0(key_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
102
+ const len1 = WASM_VECTOR_LEN;
103
+ const ret = wasm.extract_watermark(ptr0, len0, ptr1, len1);
104
+ var ptr3 = ret[0];
105
+ var len3 = ret[1];
106
+ if (ret[3]) {
107
+ ptr3 = 0; len3 = 0;
108
+ throw takeFromExternrefTable0(ret[2]);
109
+ }
110
+ deferred4_0 = ptr3;
111
+ deferred4_1 = len3;
112
+ return getStringFromWasm0(ptr3, len3);
113
+ } finally {
114
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Hamming distance in bits between two 256-bit hex fingerprints.
120
+ * @param {string} a
121
+ * @param {string} b
122
+ * @returns {number}
123
+ */
124
+ export function hamming_hex(a, b) {
125
+ const ptr0 = passStringToWasm0(a, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
126
+ const len0 = WASM_VECTOR_LEN;
127
+ const ptr1 = passStringToWasm0(b, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
128
+ const len1 = WASM_VECTOR_LEN;
129
+ const ret = wasm.hamming_hex(ptr0, len0, ptr1, len1);
130
+ if (ret[2]) {
131
+ throw takeFromExternrefTable0(ret[1]);
132
+ }
133
+ return ret[0] >>> 0;
134
+ }
135
+
136
+ /**
137
+ * The 32 LSH band hashes, comma-joined — index keys for discovery.
138
+ * @param {string} text
139
+ * @returns {string}
140
+ */
141
+ export function minhash_bands(text) {
142
+ let deferred2_0;
143
+ let deferred2_1;
144
+ try {
145
+ const ptr0 = passStringToWasm0(text, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
146
+ const len0 = WASM_VECTOR_LEN;
147
+ const ret = wasm.minhash_bands(ptr0, len0);
148
+ deferred2_0 = ret[0];
149
+ deferred2_1 = ret[1];
150
+ return getStringFromWasm0(ret[0], ret[1]);
151
+ } finally {
152
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Estimated Jaccard from two comma-joined MinHash signatures.
158
+ * @param {string} sig_a
159
+ * @param {string} sig_b
160
+ * @returns {number}
161
+ */
162
+ export function minhash_jaccard(sig_a, sig_b) {
163
+ const ptr0 = passStringToWasm0(sig_a, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
164
+ const len0 = WASM_VECTOR_LEN;
165
+ const ptr1 = passStringToWasm0(sig_b, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
166
+ const len1 = WASM_VECTOR_LEN;
167
+ const ret = wasm.minhash_jaccard(ptr0, len0, ptr1, len1);
168
+ if (ret[2]) {
169
+ throw takeFromExternrefTable0(ret[1]);
170
+ }
171
+ return ret[0];
172
+ }
173
+
174
+ /**
175
+ * `com.writerslogic.text-minhash.1` — 128 signature values, comma-joined.
176
+ * @param {string} text
177
+ * @returns {string}
178
+ */
179
+ export function minhash_signature(text) {
180
+ let deferred2_0;
181
+ let deferred2_1;
182
+ try {
183
+ const ptr0 = passStringToWasm0(text, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
184
+ const len0 = WASM_VECTOR_LEN;
185
+ const ret = wasm.minhash_signature(ptr0, len0);
186
+ deferred2_0 = ret[0];
187
+ deferred2_1 = ret[1];
188
+ return getStringFromWasm0(ret[0], ret[1]);
189
+ } finally {
190
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Derive the Ed25519 public key (hex) from a 32-byte secret key (hex).
196
+ * @param {string} secret_hex
197
+ * @returns {string}
198
+ */
199
+ export function public_key(secret_hex) {
200
+ let deferred3_0;
201
+ let deferred3_1;
202
+ try {
203
+ const ptr0 = passStringToWasm0(secret_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
204
+ const len0 = WASM_VECTOR_LEN;
205
+ const ret = wasm.public_key(ptr0, len0);
206
+ var ptr2 = ret[0];
207
+ var len2 = ret[1];
208
+ if (ret[3]) {
209
+ ptr2 = 0; len2 = 0;
210
+ throw takeFromExternrefTable0(ret[2]);
211
+ }
212
+ deferred3_0 = ptr2;
213
+ deferred3_1 = len2;
214
+ return getStringFromWasm0(ptr2, len2);
215
+ } finally {
216
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Sign a payload (e.g. the soft-binding assertion JSON) as tagged
222
+ * COSE_Sign1 / EdDSA. Returns the envelope as hex.
223
+ * @param {string} payload
224
+ * @param {string} secret_hex
225
+ * @returns {string}
226
+ */
227
+ export function sign(payload, secret_hex) {
228
+ let deferred4_0;
229
+ let deferred4_1;
230
+ try {
231
+ const ptr0 = passStringToWasm0(payload, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
232
+ const len0 = WASM_VECTOR_LEN;
233
+ const ptr1 = passStringToWasm0(secret_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
234
+ const len1 = WASM_VECTOR_LEN;
235
+ const ret = wasm.sign(ptr0, len0, ptr1, len1);
236
+ var ptr3 = ret[0];
237
+ var len3 = ret[1];
238
+ if (ret[3]) {
239
+ ptr3 = 0; len3 = 0;
240
+ throw takeFromExternrefTable0(ret[2]);
241
+ }
242
+ deferred4_0 = ptr3;
243
+ deferred4_1 = len3;
244
+ return getStringFromWasm0(ptr3, len3);
245
+ } finally {
246
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Build the `c2pa.soft-binding` assertion (list id 41, surface fingerprint)
252
+ * as CBOR, hex-encoded. Sign the result with [`sign`] and store it under the
253
+ * `c2pa.soft-binding` label. Includes per-window scoped blocks.
254
+ * @param {string} text
255
+ * @returns {string}
256
+ */
257
+ export function soft_binding_fingerprint(text) {
258
+ let deferred2_0;
259
+ let deferred2_1;
260
+ try {
261
+ const ptr0 = passStringToWasm0(text, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
262
+ const len0 = WASM_VECTOR_LEN;
263
+ const ret = wasm.soft_binding_fingerprint(ptr0, len0);
264
+ deferred2_0 = ret[0];
265
+ deferred2_1 = ret[1];
266
+ return getStringFromWasm0(ret[0], ret[1]);
267
+ } finally {
268
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
269
+ }
270
+ }
271
+
272
+ /**
273
+ * Build the `c2pa.soft-binding` assertion (list id 44, MinHash) as CBOR hex.
274
+ * @param {string} text
275
+ * @returns {string}
276
+ */
277
+ export function soft_binding_minhash(text) {
278
+ let deferred2_0;
279
+ let deferred2_1;
280
+ try {
281
+ const ptr0 = passStringToWasm0(text, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
282
+ const len0 = WASM_VECTOR_LEN;
283
+ const ret = wasm.soft_binding_minhash(ptr0, len0);
284
+ deferred2_0 = ret[0];
285
+ deferred2_1 = ret[1];
286
+ return getStringFromWasm0(ret[0], ret[1]);
287
+ } finally {
288
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Build the `c2pa.soft-binding` assertion (list id 43, structural) as CBOR hex.
294
+ * @param {string} text
295
+ * @returns {string}
296
+ */
297
+ export function soft_binding_structure(text) {
298
+ let deferred2_0;
299
+ let deferred2_1;
300
+ try {
301
+ const ptr0 = passStringToWasm0(text, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
302
+ const len0 = WASM_VECTOR_LEN;
303
+ const ret = wasm.soft_binding_structure(ptr0, len0);
304
+ deferred2_0 = ret[0];
305
+ deferred2_1 = ret[1];
306
+ return getStringFromWasm0(ret[0], ret[1]);
307
+ } finally {
308
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Build the `c2pa.soft-binding` assertion (list id 42, ZWC watermark) for a
314
+ * routing `pointer_hex`, as CBOR hex.
315
+ * @param {string} pointer_hex
316
+ * @returns {string}
317
+ */
318
+ export function soft_binding_watermark(pointer_hex) {
319
+ let deferred3_0;
320
+ let deferred3_1;
321
+ try {
322
+ const ptr0 = passStringToWasm0(pointer_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
323
+ const len0 = WASM_VECTOR_LEN;
324
+ const ret = wasm.soft_binding_watermark(ptr0, len0);
325
+ var ptr2 = ret[0];
326
+ var len2 = ret[1];
327
+ if (ret[3]) {
328
+ ptr2 = 0; len2 = 0;
329
+ throw takeFromExternrefTable0(ret[2]);
330
+ }
331
+ deferred3_0 = ptr2;
332
+ deferred3_1 = len2;
333
+ return getStringFromWasm0(ptr2, len2);
334
+ } finally {
335
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
336
+ }
337
+ }
338
+
339
+ /**
340
+ * `com.writerslogic.text-fingerprint.1` — 256-bit surface SimHash, hex.
341
+ * @param {string} text
342
+ * @returns {string}
343
+ */
344
+ export function text_fingerprint(text) {
345
+ let deferred2_0;
346
+ let deferred2_1;
347
+ try {
348
+ const ptr0 = passStringToWasm0(text, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
349
+ const len0 = WASM_VECTOR_LEN;
350
+ const ret = wasm.text_fingerprint(ptr0, len0);
351
+ deferred2_0 = ret[0];
352
+ deferred2_1 = ret[1];
353
+ return getStringFromWasm0(ret[0], ret[1]);
354
+ } finally {
355
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
356
+ }
357
+ }
358
+
359
+ /**
360
+ * `com.writerslogic.text-structure.1` — 256-bit structural SimHash, hex.
361
+ * @param {string} text
362
+ * @returns {string}
363
+ */
364
+ export function text_structure(text) {
365
+ let deferred2_0;
366
+ let deferred2_1;
367
+ try {
368
+ const ptr0 = passStringToWasm0(text, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
369
+ const len0 = WASM_VECTOR_LEN;
370
+ const ret = wasm.text_structure(ptr0, len0);
371
+ deferred2_0 = ret[0];
372
+ deferred2_1 = ret[1];
373
+ return getStringFromWasm0(ret[0], ret[1]);
374
+ } finally {
375
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
376
+ }
377
+ }
378
+
379
+ /**
380
+ * Verify a hex COSE_Sign1 envelope against a hex public key; returns the
381
+ * payload string on success, throws on failure.
382
+ * @param {string} cose_hex
383
+ * @param {string} public_hex
384
+ * @returns {string}
385
+ */
386
+ export function verify(cose_hex, public_hex) {
387
+ let deferred4_0;
388
+ let deferred4_1;
389
+ try {
390
+ const ptr0 = passStringToWasm0(cose_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
391
+ const len0 = WASM_VECTOR_LEN;
392
+ const ptr1 = passStringToWasm0(public_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
393
+ const len1 = WASM_VECTOR_LEN;
394
+ const ret = wasm.verify(ptr0, len0, ptr1, len1);
395
+ var ptr3 = ret[0];
396
+ var len3 = ret[1];
397
+ if (ret[3]) {
398
+ ptr3 = 0; len3 = 0;
399
+ throw takeFromExternrefTable0(ret[2]);
400
+ }
401
+ deferred4_0 = ptr3;
402
+ deferred4_1 = len3;
403
+ return getStringFromWasm0(ptr3, len3);
404
+ } finally {
405
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
406
+ }
407
+ }
408
+ function __wbg_get_imports() {
409
+ const import0 = {
410
+ __proto__: null,
411
+ __wbg_Error_92b29b0548f8b746: function(arg0, arg1) {
412
+ const ret = Error(getStringFromWasm0(arg0, arg1));
413
+ return ret;
414
+ },
415
+ __wbindgen_init_externref_table: function() {
416
+ const table = wasm.__wbindgen_externrefs;
417
+ const offset = table.grow(4);
418
+ table.set(0, undefined);
419
+ table.set(offset + 0, undefined);
420
+ table.set(offset + 1, null);
421
+ table.set(offset + 2, true);
422
+ table.set(offset + 3, false);
423
+ },
424
+ };
425
+ return {
426
+ __proto__: null,
427
+ "./c2pa_text_binding_bg.js": import0,
428
+ };
429
+ }
430
+
431
+ function getStringFromWasm0(ptr, len) {
432
+ return decodeText(ptr >>> 0, len);
433
+ }
434
+
435
+ let cachedUint8ArrayMemory0 = null;
436
+ function getUint8ArrayMemory0() {
437
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
438
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
439
+ }
440
+ return cachedUint8ArrayMemory0;
441
+ }
442
+
443
+ function passStringToWasm0(arg, malloc, realloc) {
444
+ if (realloc === undefined) {
445
+ const buf = cachedTextEncoder.encode(arg);
446
+ const ptr = malloc(buf.length, 1) >>> 0;
447
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
448
+ WASM_VECTOR_LEN = buf.length;
449
+ return ptr;
450
+ }
451
+
452
+ let len = arg.length;
453
+ let ptr = malloc(len, 1) >>> 0;
454
+
455
+ const mem = getUint8ArrayMemory0();
456
+
457
+ let offset = 0;
458
+
459
+ for (; offset < len; offset++) {
460
+ const code = arg.charCodeAt(offset);
461
+ if (code > 0x7F) break;
462
+ mem[ptr + offset] = code;
463
+ }
464
+ if (offset !== len) {
465
+ if (offset !== 0) {
466
+ arg = arg.slice(offset);
467
+ }
468
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
469
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
470
+ const ret = cachedTextEncoder.encodeInto(arg, view);
471
+
472
+ offset += ret.written;
473
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
474
+ }
475
+
476
+ WASM_VECTOR_LEN = offset;
477
+ return ptr;
478
+ }
479
+
480
+ function takeFromExternrefTable0(idx) {
481
+ const value = wasm.__wbindgen_externrefs.get(idx);
482
+ wasm.__externref_table_dealloc(idx);
483
+ return value;
484
+ }
485
+
486
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
487
+ cachedTextDecoder.decode();
488
+ const MAX_SAFARI_DECODE_BYTES = 2146435072;
489
+ let numBytesDecoded = 0;
490
+ function decodeText(ptr, len) {
491
+ numBytesDecoded += len;
492
+ if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
493
+ cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
494
+ cachedTextDecoder.decode();
495
+ numBytesDecoded = len;
496
+ }
497
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
498
+ }
499
+
500
+ const cachedTextEncoder = new TextEncoder();
501
+
502
+ if (!('encodeInto' in cachedTextEncoder)) {
503
+ cachedTextEncoder.encodeInto = function (arg, view) {
504
+ const buf = cachedTextEncoder.encode(arg);
505
+ view.set(buf);
506
+ return {
507
+ read: arg.length,
508
+ written: buf.length
509
+ };
510
+ };
511
+ }
512
+
513
+ let WASM_VECTOR_LEN = 0;
514
+
515
+ let wasmModule, wasmInstance, wasm;
516
+ function __wbg_finalize_init(instance, module) {
517
+ wasmInstance = instance;
518
+ wasm = instance.exports;
519
+ wasmModule = module;
520
+ cachedUint8ArrayMemory0 = null;
521
+ wasm.__wbindgen_start();
522
+ return wasm;
523
+ }
524
+
525
+ async function __wbg_load(module, imports) {
526
+ if (typeof Response === 'function' && module instanceof Response) {
527
+ if (typeof WebAssembly.instantiateStreaming === 'function') {
528
+ try {
529
+ return await WebAssembly.instantiateStreaming(module, imports);
530
+ } catch (e) {
531
+ const validResponse = module.ok && expectedResponseType(module.type);
532
+
533
+ if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
534
+ console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
535
+
536
+ } else { throw e; }
537
+ }
538
+ }
539
+
540
+ const bytes = await module.arrayBuffer();
541
+ return await WebAssembly.instantiate(bytes, imports);
542
+ } else {
543
+ const instance = await WebAssembly.instantiate(module, imports);
544
+
545
+ if (instance instanceof WebAssembly.Instance) {
546
+ return { instance, module };
547
+ } else {
548
+ return instance;
549
+ }
550
+ }
551
+
552
+ function expectedResponseType(type) {
553
+ switch (type) {
554
+ case 'basic': case 'cors': case 'default': return true;
555
+ }
556
+ return false;
557
+ }
558
+ }
559
+
560
+ function initSync(module) {
561
+ if (wasm !== undefined) return wasm;
562
+
563
+
564
+ if (module !== undefined) {
565
+ if (Object.getPrototypeOf(module) === Object.prototype) {
566
+ ({module} = module)
567
+ } else {
568
+ console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
569
+ }
570
+ }
571
+
572
+ const imports = __wbg_get_imports();
573
+ if (!(module instanceof WebAssembly.Module)) {
574
+ module = new WebAssembly.Module(module);
575
+ }
576
+ const instance = new WebAssembly.Instance(module, imports);
577
+ return __wbg_finalize_init(instance, module);
578
+ }
579
+
580
+ async function __wbg_init(module_or_path) {
581
+ if (wasm !== undefined) return wasm;
582
+
583
+
584
+ if (module_or_path !== undefined) {
585
+ if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
586
+ ({module_or_path} = module_or_path)
587
+ } else {
588
+ console.warn('using deprecated parameters for the initialization function; pass a single object instead')
589
+ }
590
+ }
591
+
592
+ if (module_or_path === undefined) {
593
+ module_or_path = new URL('c2pa_text_binding_bg.wasm', import.meta.url);
594
+ }
595
+ const imports = __wbg_get_imports();
596
+
597
+ if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
598
+ module_or_path = fetch(module_or_path);
599
+ }
600
+
601
+ const { instance, module } = await __wbg_load(await module_or_path, imports);
602
+
603
+ return __wbg_finalize_init(instance, module);
604
+ }
605
+
606
+ export { initSync, __wbg_init as default };
Binary file
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "c2pa-text-binding",
3
+ "type": "module",
4
+ "description": "C2PA soft binding and content fingerprinting for text assets (watermark + fingerprint family)",
5
+ "version": "0.2.0",
6
+ "license": "MIT OR Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/writerslogic/c2pa-text-binding"
10
+ },
11
+ "files": [
12
+ "c2pa_text_binding_bg.wasm",
13
+ "c2pa_text_binding.js",
14
+ "c2pa_text_binding.d.ts"
15
+ ],
16
+ "main": "c2pa_text_binding.js",
17
+ "types": "c2pa_text_binding.d.ts",
18
+ "sideEffects": [
19
+ "./snippets/*"
20
+ ],
21
+ "keywords": [
22
+ "c2pa",
23
+ "provenance",
24
+ "text",
25
+ "fingerprint",
26
+ "soft-binding"
27
+ ]
28
+ }