Skip to main content

c2pa_text_binding/
lib.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! Reference implementation of the WritersLogic C2PA text soft-binding family.
4//!
5//! Each algorithm links text content to its C2PA manifest without a byte-exact
6//! hash, so provenance is recoverable after copying, reformatting, excerpting,
7//! or light editing. All algorithms are registered in the C2PA Soft Binding
8//! Algorithm List and referenced from a `c2pa.soft-binding` assertion.
9//!
10//! | Module | Algorithm | Kind |
11//! | --- | --- | --- |
12//! | [`stego`] | `com.writerslogic.zwc-watermark.2` | watermark (embedded) |
13//! | [`simhash`] | `com.writerslogic.text-fingerprint.1` | fingerprint (surface) |
14//! | [`minhash`] | `com.writerslogic.text-minhash.1` | fingerprint (excerpt) |
15//! | [`structure`] | `com.writerslogic.text-structure.1` | fingerprint (structural) |
16//!
17//! [`normalize`] is the shared canonical stream; [`soft_binding`] emits the
18//! `c2pa.soft-binding` assertion (CBOR that round-trips through the c2pa-rs
19//! reader); [`crosscheck`] recomputes a candidate's fingerprint from the current
20//! text and classifies it into a BOUND / LIKELY / REVIEW confidence tier, whose
21//! boundaries are grounded in the measured false-match rates in
22//! `examples/threshold_sweep.rs`.
23//!
24//! Everything here compiles to `wasm32-unknown-unknown`. All cryptography is
25//! pure Rust with no C bindings (sha2, hmac, blake2, ed25519-dalek, coset); the
26//! soft-binding assertion is CBOR via ciborium, and reed-solomon-erasure backs
27//! watermark recovery. Registration in the C2PA algorithm list is not the same
28//! as C2PA conformance certification, which is a separate program this crate
29//! makes no claim to.
30
31pub mod crosscheck;
32pub mod error;
33pub mod manifest;
34pub mod minhash;
35pub mod normalize;
36pub mod simhash;
37pub mod soft_binding;
38pub mod stego;
39pub mod structure;
40pub mod tag;
41pub mod zwbin;
42
43/// The A.8 variation-selector transport, re-exported from
44/// [`c2pa-unstructured-text`](https://crates.io/crates/c2pa-unstructured-text).
45///
46/// This was previously a module of this crate. It is a *hard-binding* carrier,
47/// which never belonged alongside the soft-binding family here, so it now lives
48/// in the crate that owns A.8. The re-export keeps it reachable for the
49/// survivability comparison in `examples/transport_survivability.rs`, which
50/// measures the hard-binding carrier against the soft-binding ones.
51///
52/// The API changed with the move: extraction returns `Result<Wrapper, Error>`
53/// rather than a `Decoded` enum, since a wrapper now carries its byte range as
54/// well as its payload.
55pub use c2pa_unstructured_text::wrapper as vs;
56
57/// The byte-level selector codec, re-exported alongside [`vs`].
58pub use c2pa_unstructured_text::vs as vs_codec;
59
60/// SHA-256 for the v2 wrapper checksum, over this crate's existing `sha2`.
61///
62/// The transport crate injects its digest rather than depending on one, so
63/// supplying it here keeps that crate's contribution to this dependency tree at
64/// zero: everything it needs is already present for the soft-binding family.
65#[derive(Debug, Default, Clone, Copy)]
66pub struct Sha256Hasher;
67
68impl c2pa_unstructured_text::hardbinding::Hasher for Sha256Hasher {
69    fn digest(&self, alg: c2pa_unstructured_text::hardbinding::Algorithm, data: &[u8]) -> Vec<u8> {
70        use c2pa_unstructured_text::hardbinding::Algorithm;
71        use sha2::Digest;
72        // Honour the requested algorithm rather than always answering SHA-256:
73        // the v2 checksum only asks for SHA-256, but the trait contract is
74        // wider and a silently wrong digest would be worse than a missing one.
75        match alg {
76            Algorithm::Sha256 => sha2::Sha256::digest(data).to_vec(),
77            Algorithm::Sha384 => sha2::Sha384::digest(data).to_vec(),
78            Algorithm::Sha512 => sha2::Sha512::digest(data).to_vec(),
79        }
80    }
81}
82
83#[cfg(target_arch = "wasm32")]
84mod wasm;
85
86#[cfg(feature = "python")]
87mod python;
88
89pub use crosscheck::{
90    classify, crosscheck_tag, fingerprint_evidence, verify, Confidence, Evidence,
91};
92pub use error::Error;
93pub use manifest::{public_key, sign_cose, verify_cose};
94pub use minhash::MinHash;
95pub use simhash::{Fingerprint, Hash256};
96pub use soft_binding::{SoftBinding, SOFT_BINDING_LABEL};
97pub use stego::{embed, extract, Recovered};