# Notarizing 59 Repositories with Dual RFC 3161 Timestamps: An Offline-Verifiable Supply-Chain Record and Its Limits

Author: yxpil

Suggested arXiv categories: **cs.CR** (primary), cross-lists **cs.SE** and **cs.DC**.

A compiled `main.pdf` is included for review; arXiv rebuilds it from the
source. The commands below reproduce it.

## Abstract

We present and measure a supply-chain record that binds 59 source repositories, 6,713 file entries in total, to two independently operated RFC 3161 timestamp authorities, and that a third party can check without network access and without trusting the tool that produced it. Each repository is described by a canonical, byte-sorted manifest; each timestamp token commits to the SHA-256 of one manifest's bytes; a master index records every manifest digest together with both tokens and is itself timestamped by both authorities. We audit all 59 committed records: every manifest digest matches its index row, every recorded commit matches the manifest header, and all 120 tokens verify offline against two committed trust anchors, with the token imprint equal to the SHA-256 of the signed file in all 120 cases. Negative controls confirm that a mutated manifest, a manifest belonging to another repository, and a wrong trust anchor are each rejected. The claim is deliberately narrow. The record shows that particular bytes existed before a time attested by two commercial authorities; it does not establish authorship, does not bind file contents unless the corresponding git objects are available, cannot show that either authority was honest at signing time, and does not conceal the names of three private repositories that it indexes. We state these limits, and the quantities our audit did not measure, explicitly.

## Files

| Path | What it is |
|---|---|
| `main.tex` | The paper: 9 sections, 4 tables, 3 figures, 14 references. |
| `refs.bib` | Bibliography (RFC 3161, RFC 5652, RFC 6962, FIPS 180-4, Merkle 1989, Crosby--Wallach 2009, Haber--Stornetta 1991, in-toto, TUF, Sigstore, SLSA, Lamb--Zacchiroli 2022, Stevens et al. 2017, OpenSSL). |
| `common.tex` | Copy of `../_shared/common.tex` (shared preamble). |
| `figures/fig_files_ecdf.pdf` | ECDF of file entries per repository. |
| `figures/fig_bytes.pdf` | Manifest bytes vs. file entries, with the corpus mean ratio. |
| `figures/fig_stamps.pdf` | The two TSA generation times for all 60 indexed objects. |
| `scripts/analyze.py` | The audit: recomputes digests, re-verifies every token with OpenSSL, runs `verify.sh` verbatim, executes five controls. |
| `scripts/notarization_stats.json` | The audit's output. Every quantitative claim in the paper traces here. |
| `scripts/make_figures.py` | Generates the three figures from the JSON (matplotlib, Agg, deterministic). |
| `README.md` | This file. |

## Build

```bash
pdflatex main
bibtex main
pdflatex main
pdflatex main
```

The result is `main.pdf`. The preamble uses only packages in a standard TeX Live
image: `times`, `amsmath`, `amssymb`, `amsthm`, `graphicx`, `booktabs`,
`multirow`, `array`, `algorithm`, `algpseudocode`, `listings`, `xcolor`,
`microtype`, `balance`, `geometry`, `hyperref`, plus `natbib`, which is loaded
by `main.tex` after `common.tex`.

## Packaging for arXiv

Minimal tarball (what arXiv needs to compile):

```bash
tar czf notarization-arxiv.tar.gz main.tex refs.bib common.tex figures/*.pdf
```

Full artifact tarball (adds the audit and figure scripts):

```bash
tar czf notarization-artifact.tar.gz main.tex refs.bib common.tex figures/*.pdf \
    scripts/analyze.py scripts/notarization_stats.json scripts/make_figures.py README.md
```

`common.tex` must stay byte-identical to the shared copy. Verify before
packaging:

```bash
cmp common.tex ../_shared/common.tex && echo identical
```

## Submission steps

1. Start a new arXiv submission at <https://arxiv.org/submit>.
2. Choose **cs.CR** as the primary category; add **cs.SE** and **cs.DC** as
   cross-lists.
3. Paste the title and the abstract exactly as above; author `yxpil`.
4. Upload `notarization-arxiv.tar.gz`. arXiv detects `main.tex` and runs
   `pdflatex` + `bibtex` itself.
5. Inspect the auto-built PDF: 3 figures, 4 tables, references rendered by
   `abbrvnat`, no overfull boxes that push text into the margin.
6. Select a license and submit. A first submission to cs.CR may require an
   endorsement; arrange it before uploading.
7. Keep `notarization-artifact.tar.gz` for the ancillary-files slot or for a
   companion repository; the paper refers to the audit JSON, not to a public URL.

## Reproduction

Requirements: Python 3, OpenSSL 3.5.x, `git`, `bash` (Git Bash on Windows is
sufficient), and matplotlib for the figures. The audit resolves the source
repository by default to `../../_repos/notarization` relative to this directory;
pass `--repo` to point elsewhere.

```bash
# 1. Re-run the audit and rewrite the JSON (about two minutes: 120 OpenSSL
#    verifications, 59 digests, one verify.sh run, one git re-derivation).
python scripts/analyze.py --repo ../../_repos/notarization \
    --out scripts/notarization_stats.json

# 2. Regenerate the figures from that JSON.
python scripts/make_figures.py

# 3. Spot-check one token by hand (offline; no network).
cd ../../_repos/notarization
openssl ts -verify -data manifests/SM4Kit.manifest.txt \
    -in proofs/SM4Kit.sectigo.tsr \
    -CAfile authorities/usertrust-rsa-root.pem \
    -untrusted authorities/chain-sectigo.pem
# expected: "Verification: OK"
```

Expected audit output: `index rows: 59 | manifests: 59 | file entries: 6713 |
tokens: 120 | verified ok: 120 | verify.sh exit: 0`. The JSON also records the
per-repository manifest digests, the two stamp windows, the median skew between
the authorities, and the five controls reported in Table 4 of the paper.

### Provenance of the audit numbers

`scripts/notarization_stats.json` is generated output, not a hand-edited file.
Before the final run, three routing defects in the audit harness were corrected:
DigiCert tokens were being verified against the Sectigo anchor, the two index
tokens were being verified against a manifest path that does not exist, and the
message-imprint parser did not match OpenSSL's hexdump layout. The earlier run
therefore reported 61 rejections; the corrected run accepts 120 of 120 tokens and
matches 120 of 120 imprints. Manifest, index, and `verify.sh` numbers were
unaffected by the correction. The paper reports the corrected run.

## What the paper does not claim

- It does not introduce RFC 3161, CMS, SHA-256, Merkle trees, or transparency
  logs; those are used unchanged and cited as prior art.
- It does not claim a transparency-log anchor or any public witness. The
  repository's Rekor attempt failed and is reported as a gap, not a feature.
- It does not claim authorship, identity, originality, or legal notarization.
  The tokens carry no submitter identity.
- It does not claim that file contents are in the record. Manifests list paths,
  git blob identifiers, and sizes; contents are reachable only through the git
  objects.
- It does not claim that the 59 manifests were re-derived from their
  repositories. Only the notarization repository itself (316 entries) was
  re-derived from git.
- It does not claim that the TSA certificates chain to a publicly audited root
  without local trust decisions. The two anchors are committed files whose
  fingerprints a verifier must check; revocation is not checked offline.
- It does not claim that the TSA was honest, or that its clock was accurate, at
  signing time.
- It does not claim freshness: verification accepts tokens of any age (negative
  control NC5).
- It does not claim that the three private repositories are hidden; their names
  are in `index/index.tsv` and in the audit JSON, and their manifests contain
  complete file listings.
- It does not report timing, throughput, or a performance comparison. No timing
  was measured; the paper says so.
- It does not claim that the record survives deletion of the repository that
  holds it, unless copies exist elsewhere.
