Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
224 commits
Select commit Hold shift + click to select a range
7735057
feat(views): refuse merges that argue against themselves
bc1cindy Sep 3, 2026
44f7597
feat(scale): memory-bounded multi-epoch clustering and chunked collec…
bc1cindy Sep 3, 2026
665bcb8
feat(graph): cross-view matching, seed identification and link predic…
bc1cindy Sep 3, 2026
3924721
feat(amount): read per-coin ambiguity off the link matrix
bc1cindy Sep 3, 2026
78aa446
fix(path-count): weight path-count anonymity by link probability alone
bc1cindy Sep 3, 2026
4ce008b
feat(reproducibility): source manifests and a separability test with …
bc1cindy Sep 3, 2026
dccb2e5
feat(baselines): implement exact subtransaction mappings
bc1cindy Sep 3, 2026
d595476
feat(intersection): implement candidate-set narrowing baseline
bc1cindy Sep 3, 2026
36f1d34
feat(deanonymization): implement seeded link-prediction baseline
bc1cindy Sep 3, 2026
b70becc
feat(baselines): audit approximations against exact mappings
bc1cindy Sep 3, 2026
9c34241
feat(linkage): implement Fellegi-Sunter scoring
bc1cindy Sep 3, 2026
ec2ae6d
feat(linkage): evaluate temporal generalization
bc1cindy Sep 3, 2026
ee74b96
feat(linkage): evaluate feature ablations
bc1cindy Sep 3, 2026
fe2fd8b
feat(lumen): stream and validate fingerprint exports
bc1cindy Sep 3, 2026
85c5613
feat(deanonymization): measure N-S on Bitcoin views
bc1cindy Sep 3, 2026
68e9161
refactor(core): separate attack models and preserve compatibility
bc1cindy Sep 3, 2026
c9f23b2
feat(baselines): measure explicit fee allocation on real transactions
bc1cindy Sep 3, 2026
0e61537
feat(baselines): align Maurer and Goldfeder reference kernels
bc1cindy Sep 3, 2026
4fe33a4
docs(research): pin primary-source fidelity gaps
bc1cindy Sep 3, 2026
f8515da
feat(baselines): reproduce Boltzmann linkability traversal
bc1cindy Sep 3, 2026
1e2503c
feat(baselines): implement NS 2011 prediction combiner
bc1cindy Sep 3, 2026
cb35682
feat(baselines): add NS 2011 similarity stages
bc1cindy Sep 3, 2026
300ad47
feat(baselines): implement defined NS 2011 annealing domain
bc1cindy Sep 3, 2026
a97030e
feat(baselines): add NS 2011 two-stage driver
bc1cindy Sep 3, 2026
e305b4c
feat(ancestry): add Kelen-Seres expected absorption steps
bc1cindy Sep 3, 2026
fa55f72
feat(baselines): add Kelen-Seres account graph transforms
bc1cindy Sep 3, 2026
ee83234
feat(baselines): materialize Kelen-Seres source chain
bc1cindy Sep 3, 2026
89038c3
feat(baselines): reproduce Boltzmann merge-fees mode
bc1cindy Sep 3, 2026
6861627
feat(baselines): reproduce Boltzmann input merging
bc1cindy Sep 3, 2026
a050a4c
feat(catalog): register CTP sources and claims
bc1cindy Sep 3, 2026
a391c16
feat(data): define verified dataset catalog
bc1cindy Sep 3, 2026
3c090c2
feat(results): verify canonical artifacts
bc1cindy Sep 3, 2026
21b5072
feat(reproduction): reproduce exact oracle audit
bc1cindy Sep 3, 2026
9734723
feat(data): add content-addressed evidence bundles
bc1cindy Sep 3, 2026
fe8aefa
feat(data): expose verified dataset materialization
bc1cindy Sep 3, 2026
8a3ea49
feat(reproduction): bootstrap and audit evidence bundles
bc1cindy Sep 4, 2026
823a6a2
feat(reproduction): reproduce exact DSS audit offline
bc1cindy Sep 4, 2026
10b2c8a
docs: state bundle reproduction limits
bc1cindy Sep 4, 2026
d57e400
feat(domain): distinguish evidence and analysis outcomes
bc1cindy Sep 4, 2026
d0759da
feat(adaptations): type cluster refinement reports
bc1cindy Sep 4, 2026
41e7927
feat(domain): preserve attack evidence channels
bc1cindy Sep 4, 2026
71ae176
feat(cluster): expose typed channel decisions
bc1cindy Sep 4, 2026
b13d296
feat(intersection): expose typed evaluation states
bc1cindy Sep 4, 2026
e6d621c
feat(ancestry): distinguish bounded walk states
bc1cindy Sep 4, 2026
7997bc8
feat(provenance): bind intersections to ancestry reports
bc1cindy Sep 4, 2026
8f70a28
refactor(intersection): consume atomic ancestry reports
bc1cindy Sep 4, 2026
ea350fc
feat(reproduction): reproduce intersection fixture offline
bc1cindy Sep 4, 2026
e02add1
feat(reproduction): reproduce candidate-set intersection
bc1cindy Sep 4, 2026
820d7ba
feat(boltzmann): add precheck and intrafee bounds
bc1cindy Sep 4, 2026
0f97019
feat(reproduction): reproduce consolidation intersection offline
bc1cindy Sep 4, 2026
30779a0
feat(reproduction): reproduce change consolidation offline
bc1cindy Sep 4, 2026
cbfe2d0
feat(reproduction): reproduce Eve-Alice-Eve narrowing offline
bc1cindy Sep 4, 2026
556207f
feat(reproduction): reproduce provenance decay modes offline
bc1cindy Sep 4, 2026
26b08fb
feat(results): classify legacy result provenance
bc1cindy Sep 4, 2026
92f651f
feat(reproduction): reproduce planted link prediction offline
bc1cindy Sep 4, 2026
c411456
feat(reproduction): reproduce temporal Fellegi-Sunter evaluation offline
bc1cindy Sep 4, 2026
284b0fa
feat(reproduction): reproduce Fellegi-Sunter ablation offline
bc1cindy Sep 4, 2026
686dae0
feat(reproduction): reproduce N-S Bitcoin views offline
bc1cindy Sep 4, 2026
74dd8bb
feat(reproduction): reproduce Boltzmann fee audit offline
bc1cindy Sep 4, 2026
500713f
feat(data): preserve amount-channel survey snapshot
bc1cindy Sep 4, 2026
b14a626
feat(reproduction): reproduce local amount channels offline
bc1cindy Sep 4, 2026
684bfec
feat(reproduction): reproduce subset-sum diagnostics offline
bc1cindy Sep 4, 2026
a71de34
feat(reproduction): reproduce per-coin amount diagnostics offline
bc1cindy Sep 4, 2026
11a6179
feat(reproduction): reproduce DSS mapping diagnostics offline
bc1cindy Sep 4, 2026
1a56d3e
feat(reproduction): reproduce DSS pairwise diagnostics offline
bc1cindy Sep 4, 2026
7a28839
feat(reproduction): reproduce amount-channel survey offline
bc1cindy Sep 4, 2026
115b4e5
feat(reproduction): reproduce counting-router audit offline
bc1cindy Sep 4, 2026
e6effd1
feat(reproduction): reproduce counting fee sensitivity offline
bc1cindy Sep 4, 2026
1982e13
feat(reproduction): reproduce counting-method observations offline
bc1cindy Sep 4, 2026
9a78c33
docs(graph): correct path robustness to edge disjointness
bc1cindy Sep 4, 2026
6349106
feat(reproduction): reproduce path-count contract offline
bc1cindy Sep 4, 2026
e325ed1
refactor(graph): name provenance route accumulation explicitly
bc1cindy Sep 4, 2026
d6be48d
feat(reproduction): reproduce analysis facade contract offline
bc1cindy Sep 4, 2026
a3592fb
docs(graph): distinguish route accumulation from robustness
bc1cindy Sep 4, 2026
ffc706d
feat(reproduction): reproduce ancestry model contract offline
bc1cindy Sep 4, 2026
5205816
docs(provenance): limit DSS entropy claims
bc1cindy Sep 4, 2026
7a6b411
feat(reproduction): reproduce ancestry sparsity offline
bc1cindy Sep 4, 2026
6f66751
docs(results): bound ancestry sparsity claims
bc1cindy Sep 4, 2026
2752182
feat(reproduction): reproduce conservation observation offline
bc1cindy Sep 4, 2026
6ab8f52
fix(results): inventory markdown aliases exactly
bc1cindy Sep 4, 2026
5854b95
feat(reproduction): reproduce entity graph controls offline
bc1cindy Sep 4, 2026
f95ef84
feat(reproduction): reproduce ancestry record linkage offline
bc1cindy Sep 4, 2026
f09e0f4
feat(reproduction): reproduce slice-channel diagnostics offline
bc1cindy Sep 4, 2026
aa132c5
fix(results): inventory slice channel alias exactly
bc1cindy Sep 4, 2026
7ef2995
feat(reproduction): reproduce fingerprint pair separation offline
bc1cindy Sep 4, 2026
1465000
feat(reproduction): reproduce fingerprint regime sensitivity offline
bc1cindy Sep 4, 2026
75fb22b
feat(reproduction): reproduce fingerprint class sizes offline
bc1cindy Sep 4, 2026
6b385f2
feat(reproduction): reproduce projected attribute drift offline
bc1cindy Sep 4, 2026
43a6c7b
feat(reproduction): reproduce excluded-axis ablation offline
bc1cindy Sep 4, 2026
08d1f5f
feat(reproduction): reproduce Bayesian linkage comparison offline
bc1cindy Sep 4, 2026
6aa6f42
feat(reproduction): reproduce EM parameter diagnostics offline
bc1cindy Sep 4, 2026
bc0fa4a
feat(reproduction): reproduce weight sensitivity offline
bc1cindy Sep 4, 2026
efc5f0f
feat(reproduction): reproduce subtransaction de-mixing offline
bc1cindy Sep 4, 2026
add263d
feat(reproduction): reproduce entropy insufficiency offline
bc1cindy Sep 4, 2026
cbf67da
ci: separate offline and reproduction gates
bc1cindy Sep 4, 2026
d1e1aec
docs(evidence): qualify model-relative claims
bc1cindy Sep 4, 2026
0472ac8
feat(reproduction): reproduce statistical disclosure offline
bc1cindy Sep 4, 2026
97d092d
feat(reproduction): reproduce perfect-matching disclosure offline
bc1cindy Sep 4, 2026
2120a2a
feat(reproduction): reproduce denomination preparation offline
bc1cindy Sep 4, 2026
b570b54
feat(reproduction): reproduce pseudonym graph contraction offline
bc1cindy Sep 4, 2026
3275b3b
feat(reproduction): reproduce collaborative CIOH false merges offline
bc1cindy Sep 4, 2026
4b3c875
feat(reproduction): reproduce deterministic partitions offline
bc1cindy Sep 4, 2026
44c521f
fix(results): bind catalog axes to its canonical run
bc1cindy Sep 5, 2026
a3e8cb8
feat(baselines): add fee-aware unnecessary-input analysis
bc1cindy Sep 5, 2026
050b5b0
feat(failure-modes): make UIH interpretation inconclusive
bc1cindy Sep 5, 2026
fc58e58
feat(failure-modes): cover collaborative UIH limits
bc1cindy Sep 5, 2026
d4e5bcf
refactor(amount): gate rankings by transaction model
bc1cindy Sep 5, 2026
5af21a3
feat(evidence): model collaborative observer knowledge
bc1cindy Sep 5, 2026
92725e4
feat(reproduction): reproduce unnecessary-input diagnostics offline
bc1cindy Sep 5, 2026
f865ddf
feat(ns): add conservative mapping revisitation
bc1cindy Sep 5, 2026
64eb283
feat(ns): expose 2011 pipeline coverage
bc1cindy Sep 5, 2026
7c6a4a3
feat(reproduction): publish N-S 2011 coverage offline
bc1cindy Sep 5, 2026
6f15837
feat(reproduction): reproduce CoinJoin Sudoku offline
bc1cindy Sep 5, 2026
cb07fab
feat(reproduction): reproduce collaborative observer forms offline
bc1cindy Sep 5, 2026
768345c
docs(data): authorize fixture redistribution
bc1cindy Sep 5, 2026
ab4abaa
build(reproduction): refresh source provenance
bc1cindy Sep 5, 2026
100ce3f
fix(uih): restore Ghesmati's uncategorized outcome
bc1cindy Sep 5, 2026
8140df0
fix(cluster): take change eligibility in sample order under staging
bc1cindy Sep 5, 2026
11f31e9
fix(baselines): reject non-integer coin values and null txos
bc1cindy Sep 5, 2026
b27938a
fix(ns): implement the dummy zero convention and both eccentricity re…
bc1cindy Sep 5, 2026
d50acc0
fix(intersect): drop the unsourced shrink-law attribution
bc1cindy Sep 5, 2026
9d97ec8
feat(fingerprint): expose decorrelated and construction-only scorers
bc1cindy Sep 5, 2026
705ac4f
feat(ns1r): derive the receiver's change read-off
bc1cindy Sep 5, 2026
2cf773a
fix(amount): refuse radix diagnostics at the guarantee gate
bc1cindy Sep 5, 2026
faeee69
docs(references): record the metric and disclosure obligations
bc1cindy Sep 5, 2026
10223a6
build(evidence): regenerate the runs the radix fix moves
bc1cindy Sep 5, 2026
d584e9c
docs(paper): resync the manuscript with the canonical artifacts
bc1cindy Sep 5, 2026
81dd38f
docs(results): correct stale rules, attributions and magnitudes
bc1cindy Sep 5, 2026
3863f83
fix(extractors): refuse non-integer amounts instead of ranking them
bc1cindy Sep 5, 2026
a79c039
build(reproduction): rebuild the runtime snapshot from git
bc1cindy Sep 6, 2026
a3a4a3d
feat(partition): make the refinement lattice a first-class object
bc1cindy Sep 6, 2026
bf8774e
feat(declustering): cut an inherited partition on evidence against th…
bc1cindy Sep 6, 2026
dd789c1
feat(results): measure the descending pass against the ascending one
bc1cindy Sep 6, 2026
6263f12
fix(releases): repoint bundles at the run manifests they ship
bc1cindy Sep 6, 2026
5e42460
docs(cluster): say which direction the engine travels
bc1cindy Sep 6, 2026
2a94f36
fix(fetch): keep live block fetches out of the published slice
bc1cindy Sep 6, 2026
c0d2444
docs(decluster): name the two lattice directions in the package contract
bc1cindy Sep 6, 2026
20094f9
test(dss): skip the tests that need the optional extension instead of…
bc1cindy Sep 6, 2026
d9db803
build: declare the optional extensions and the real minimum Python
bc1cindy Sep 6, 2026
911a8ea
fix(provenance): declare the revision each bundle actually runs
bc1cindy Sep 6, 2026
7ab8fa0
docs: correct claims the tree contradicts
bc1cindy Sep 6, 2026
9404687
refactor(oracle-audit): drop the unused refinement wrapper
bc1cindy Sep 6, 2026
a0956e4
fix(extractors): abstain where the export does not say
bc1cindy Sep 6, 2026
ae30603
build(reproduction): reissue the runtime snapshot for the extractor fix
bc1cindy Sep 6, 2026
264ddc7
fix(claims): point three claims at what the code actually does
bc1cindy Sep 6, 2026
540a134
test(paper): pin every path a published document sends a reader to
bc1cindy Sep 6, 2026
47c66bd
feat(bundle): synchronise indexes, store and tree in one command
bc1cindy Sep 6, 2026
2c7f003
test(bundle): gate the tree against store and index drift
bc1cindy Sep 6, 2026
b272f40
test(manifests): compare the legacy invariants against the canonical …
bc1cindy Sep 6, 2026
78eabb8
test(paper): declare the unsplit monthly export the gate found
bc1cindy Sep 6, 2026
2710c67
feat(ns1r): publish the receiver-side change read-off as a canonical run
bc1cindy Sep 7, 2026
05a1744
build(reproduction): reissue the runtime snapshot for the read-off run
bc1cindy Sep 7, 2026
ae701c9
feat(fingerprint): publish the three axis families as a canonical run
bc1cindy Sep 7, 2026
a8a1f79
build(reproduction): reissue the runtime snapshot for the axis-family…
bc1cindy Sep 7, 2026
0384202
feat(declustering): cut the heavy tail the exact search cannot reach
bc1cindy Sep 7, 2026
8cf36a4
fix(bundle): bring run manifest outputs into sync too, and before the…
bc1cindy Sep 7, 2026
bb81c6b
fix(graph-deanon): make the seeded run reproducible, and publish its …
bc1cindy Sep 7, 2026
d890492
build(reproduction): reissue the runtime snapshot for the graph-deano…
bc1cindy Sep 7, 2026
edcc12c
feat(boltzmann): publish what the amounts settle about co-spent inputs
bc1cindy Sep 7, 2026
c3dee6e
feat(reproduction): move every record with the runtime archive in one…
bc1cindy Sep 7, 2026
107d58e
build(reproduction): reissue the runtime snapshot
bc1cindy Sep 7, 2026
a455d6f
feat(library): measure the shipped calibration against the population…
bc1cindy Sep 7, 2026
dd8c6b1
build(reproduction): reissue the runtime snapshot for the calibration…
bc1cindy Sep 7, 2026
31887e2
feat(anchor): make the edge PAPER argues from reproducible offline
bc1cindy Sep 7, 2026
a358d0b
feat(catalog): register the anchor fixture as a verified dataset
bc1cindy Sep 7, 2026
92ec141
build(reproduction): reissue the runtime snapshot for the anchor run
bc1cindy Sep 7, 2026
727db71
docs(results): name the frozen baselines the canonical runs are held …
bc1cindy Sep 7, 2026
aa6dd64
fix(releases): bundle the descent-versus-ascent run
bc1cindy Sep 7, 2026
a521c00
build(reproduction): reissue the runtime snapshot
bc1cindy Sep 7, 2026
5ad466c
fix(views): generalise every partition scheme to n views
bc1cindy Sep 7, 2026
d02546e
feat(partition): reproduce the cut comparison on data a reader has
bc1cindy Sep 7, 2026
eb76d13
build(reproduction): reissue the runtime snapshot for the partition-s…
bc1cindy Sep 7, 2026
25edc67
feat(partition): commit the prefix the cut comparison was measured on
bc1cindy Sep 7, 2026
c1c4304
build(reproduction): reissue the runtime snapshot
bc1cindy Sep 7, 2026
728de25
docs: say what the labels are instead of what they are not
bc1cindy Sep 7, 2026
365f990
build(reproduction): reissue the runtime snapshot
bc1cindy Sep 7, 2026
29a9c5a
build(reproduction): reissue the runtime snapshot
bc1cindy Sep 7, 2026
c818b9c
fix(claims): cite the clustering baselines the CIOH claim already covers
bc1cindy Sep 7, 2026
6417165
docs: state the limit instead of calling it honest
bc1cindy Sep 7, 2026
aab9b2a
refactor(combiner): drop the alias named after a model it never fitted
bc1cindy Sep 7, 2026
124f4e6
test(experiments): compare the whole artifact, not only the named rows
bc1cindy Sep 7, 2026
20030f4
test(paper): resolve every measurement to an artifact or declare it
bc1cindy Sep 7, 2026
aaf8b39
fix(weight-sensitivity): read the dip against what the sample resolves
bc1cindy Sep 7, 2026
ba5923c
build(reproduction): reissue the runtime snapshot
bc1cindy Sep 7, 2026
74f8931
test(claims): tie each claim to code that exists and a run that exerc…
bc1cindy Sep 7, 2026
265e36d
docs: let bold mark a claim rather than a term
bc1cindy Sep 7, 2026
faa4b0c
feat(results): generate the index the directory never had
bc1cindy Sep 7, 2026
1e88ded
test(paper): resolve a cited generated document where it lives
bc1cindy Sep 7, 2026
b465b51
fix(releases): declare only the locations that serve the pinned bytes
bc1cindy Sep 7, 2026
8585ef8
build(dss): move every pin to the amended dependency revision
bc1cindy Sep 7, 2026
e9b43f6
build(reproduction): reissue the runtime snapshot
bc1cindy Sep 7, 2026
ebe9e7e
fix(reproduction): pin the wheel the bundles actually ship
bc1cindy Sep 7, 2026
db41c96
build(reproduction): refresh source provenance
bc1cindy Sep 7, 2026
31a043f
fix(paper): resolve a rate against the fraction an artifact stores
bc1cindy Sep 7, 2026
4382c4c
refactor(views): split the module into the three things it was doing
bc1cindy Sep 7, 2026
86736a5
build(reproduction): refresh source provenance
bc1cindy Sep 7, 2026
421c475
feat(results): make every document state what backs it
bc1cindy Sep 7, 2026
bf964d9
build(reproduction): refresh source provenance
bc1cindy Sep 7, 2026
1926e7c
feat(results): pin two state-3 claims and file the rest against the p…
bc1cindy Sep 7, 2026
95d473f
build(reproduction): refresh source provenance
bc1cindy Sep 7, 2026
002a6be
docs: unbold the terms bold was never meant to mark
bc1cindy Sep 7, 2026
1c6923d
build(reproduction): refresh source provenance
bc1cindy Sep 7, 2026
edabe6e
chore: ignore the planning notes instead of relying on a local exclude
bc1cindy Sep 8, 2026
ebd2dcb
feat(engine): publish what the fusion adds over co-spend alone
bc1cindy Sep 8, 2026
5890be0
build(reproduction): refresh source provenance
bc1cindy Sep 8, 2026
a532458
feat(data): commit the 2016 address graph the export was too large to…
bc1cindy Sep 8, 2026
16ca53d
fix(data): number every window from one address namespace
bc1cindy Sep 8, 2026
0792676
feat(results): measure the rejoin again, on data a reader has
bc1cindy Sep 8, 2026
7f47ccc
docs(baselines): name the work each reimplementation is measured against
bc1cindy Sep 8, 2026
3924de0
feat(results): state what the contracted view's shape says about the …
bc1cindy Sep 8, 2026
ef2de74
build(reproduction): refresh source provenance
bc1cindy Sep 8, 2026
f268744
docs: remove three results whose data cannot be recovered
bc1cindy Sep 8, 2026
c10e802
fix(examples): keep the era-bits mechanism the document did not carry
bc1cindy Sep 8, 2026
ccde167
feat(routes): measure the cut the framework states robust connectivit…
bc1cindy Sep 8, 2026
f2d5ee6
feat(routes): prune a route that could not have carried the coin
bc1cindy Sep 8, 2026
43700c6
build(reproduction): refresh source provenance
bc1cindy Sep 8, 2026
b4161f3
feat(claims): let a claim's status say which kind of claim it is
bc1cindy Sep 8, 2026
07435bb
feat(results): strengthen empirical controls and evidence
bc1cindy Sep 9, 2026
a673ed0
build(reproduction): refresh source provenance
bc1cindy Sep 9, 2026
b40fa37
test(pipeline): remove implicit network dependency
bc1cindy Sep 9, 2026
b484be7
build(reproduction): refresh source provenance
bc1cindy Sep 9, 2026
bcd9a3e
fix(reproduction): bundle numpy for graph experiments
bc1cindy Sep 9, 2026
7a806ba
build(reproduction): refresh source provenance
bc1cindy Sep 9, 2026
3efafea
docs(paper): align route capacity claims
bc1cindy Sep 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
64 changes: 64 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: CI

on:
pull_request:
push:
branches: [master]

permissions:
contents: read

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
python:
name: Python ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.13"]
steps:
- name: Check out source
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: ${{ matrix.python-version }}
cache: pip
- name: Install test dependencies
run: python -m pip install --disable-pip-version-check ".[test,data]"
- name: Run offline gate
run: python -m pytest -m "not live and not reproduction"

dss:
name: Python 3.13 with pinned DSS
runs-on: ubuntu-latest
steps:
- name: Check out source
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Check out DSS
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
repository: bc1cindy/dense-subset-sum
ref: d8099bc540c9de7d0f3c9f095e8b2aad8f9d8c8d
path: .ci/dense-subset-sum
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.13"
cache: pip
- name: Select DSS minimum Rust toolchain
run: |
rustup toolchain install 1.88.0 --profile minimal
rustup default 1.88.0
- name: Install project and DSS
run: |
python -m pip install --disable-pip-version-check ".[test,data]"
python -m pip install --disable-pip-version-check .ci/dense-subset-sum
- name: Verify DSS revision
run: python -c 'import dss; assert dss.__rev__ == "d8099bc540c9de7d0f3c9f095e8b2aad8f9d8c8d"'
- name: Run offline gate with DSS
run: python -m pytest -m "not live and not reproduction"
33 changes: 33 additions & 0 deletions .github/workflows/reproduction.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Evidence reproduction

on:
workflow_dispatch:
schedule:
- cron: "17 4 * * 1"

permissions:
contents: read

concurrency:
group: evidence-reproduction
cancel-in-progress: false

jobs:
bundles:
name: Reproduce committed bundles
runs-on: macos-14
timeout-minutes: 120
steps:
- name: Check out source
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.13.7"
cache: pip
- name: Install test dependencies
run: python -m pip install --disable-pip-version-check ".[test,data]"
- name: Verify committed bundle contents
run: python -m pytest tests/test_committed_bundles.py::test_every_committed_bundle_is_complete_and_content_verified
- name: Reproduce all committed bundles
run: python -m pytest -m reproduction tests/test_committed_bundles.py
15 changes: 15 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,25 @@ __pycache__/
*.pyc
.cache/
.blkcache/
.blkcache-live/
*.ndjson
!catalog/entities.example.ndjson
slice*.json
!catalog/runs/slice-*.json
!results/artifacts/slice-*.json
!releases/slice-*.bundle.json
slice*.err
!catalog/datasets/slice-a-channels-2016-v1.json
day-*.json
day-*.err
decluster.egg-info/

# logs de coleta/análise (efêmeros)
*.log
*.done

# épocas comprimidas da coleta multi-epoch (dados locais grandes)
epoch_*.ndjson.gz
data/epochs_*/
# Planning notes and specs: working material, not part of the published record.
docs/superpowers/
835 changes: 591 additions & 244 deletions PAPER.md

Large diffs are not rendered by default.

98 changes: 79 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# decluster

Evidence-weighted **de-anonymization of Bitcoin transactions**. It reads how each
transaction was built (wallet fingerprints) and how its amounts partition (subtransaction
structure), scores every signal as **bits of evidence**, and clusters coins by owner.
An adversarial laboratory for testing **de-anonymization failure modes in Bitcoin
transactions**. It keeps construction fingerprints, amount models, graph structure,
attribution and provenance as distinct evidence channels, including explicit abstention and
cannot-link outcomes. Those channels are model-relative and do not establish true ownership or
a general privacy score.

Two coins spent in the same transaction are normally assumed to share an owner. Because the
evidence here is *signed*, the clustering can instead **keep them apart** when their
Expand All @@ -14,17 +16,27 @@ two people into one).
how it constructs a transaction — nSequence values, script types, signature grinding, and
more. Do those quirks actually identify the wallet? Taking address reuse as the same-owner
label (two transactions spending the same address are the same wallet), the measured
fingerprint bits rank a *same-wallet* pair of transactions above a *random* pair **93.3%
of the time** (AUC 0.933) on 166k real mainnet transactions. Shuffle the labels and it
drops to 0.50 (a coin flip) — so the 0.933 is real signal, not an artifact.
fingerprint bits rank a *same-wallet* pair of transactions above a *random* pair **94.6%
of the time** on the committed 600-transaction fixture (AUC 0.9459, the manifest-backed run)
and **92.4%** on the preserved 22,112-transaction cache (AUC 0.9244). Shuffle the labels and
both drop to ~0.50 (a coin flip) — so the separation is real signal, not an artifact. An
earlier figure of 0.933 over a 166k-transaction cache is a historical record: that cache was
not preserved and the number is not recomputable. Two caveats travel with these: the
preserved cache is Taproot-era only (heights 800,000–965,220), and on that cache 0.024 of
the AUC is the address-reuse label restating itself — dropping the five axes the shared
input address fixes outright takes 0.9244 to 0.9003.

- **The shape of the payment graph reveals owners too.** Independently of who-spent-with-whom,
the *structure* of the graph (who pays whom) betrays common ownership — the same effect
that de-anonymized social networks (Narayanan–Shmatikov). Across five eras (2012–2024),
- **The shape of the payment graph provides another model-relative signal.** Independently of
who-spent-with-whom, recurring counterparty structure can support linkage. The local
common-neighbour experiment is not the seeded cross-view Narayanan–Shmatikov attack. Across five eras (2012–2024),
payment-graph structure *alone* predicts whether two addresses share an owner, ranking
same-owner pairs correctly **0.95–0.97 of the time at one hop on the clean eras**, and
**0.97–1.00 across all five eras by four hops** (1.0 = perfect, 0.5 = chance; the churny
2013 slice starts near chance at one hop and needs the deeper hops).
2013 slice starts near chance at one hop and needs the deeper hops). That is a *pairwise
ranking* score, and it is the premise the attack needs rather than the attack: run to
completion on two real Bitcoin views, the faithful 2009 propagation kernel reaches
**0.41%–1.28% precision**, against a shuffled-seed control that gets nothing right
(`results/RESULTS-ns-bitcoin.md`).

- **It survives a transaction built to fool it.** On a real transaction deliberately
constructed to merge two owners into one (the false link from above), the method keeps
Expand All @@ -34,16 +46,64 @@ two people into one).

## Layout

- `decluster/` — the attacker (the measurement half that runs): extractors, library, combiner, cluster (engine: `cluster_refined`), propagate (entity-level N-S seed-and-propagate via provenance signatures; synthetic evaluation), graph_deanon
- the construction/cost half (deferred — PAPER §9): `cost` (leak / amount-cut / topology leaf terms + the deferred `construction_cost`), `ancestry` (the absorber-model provenance target; feeds propagate), `report` (fuses the terms on a real tx), `subsetsum`/`coinjoin_demix` (the amount de-mix channel); consumes the `dense-subset-sum` engine (build: `maturin develop`); `cluster_refined` optionally refuses links when provenance and fingerprints diverge
- chain-analysis channels that select what to ask and read the answer, all outside the engine:
`conservation` (what the other participants could not have funded — arithmetic on one transaction,
no client model), `provenance` (which inputs descend from known transactions), `monitor` (watches
tracked coins for the co-spend an intersection argument needs), `intersect` (the N-ary origin
intersection, handed to `cluster_refined` to score rather than asserted)
- `PAPER.md` — the manuscript; `results/` — reproducible outputs; `catalog/`, `bigquery/`
**The package.** `decluster/` holds the measurement half. Modules are named for the evidence channel
they carry — `extractors`/`library`/`combiner` for construction fingerprints, `subsetsum`/`counting`/
`subtransaction` for amounts, `ancestry`/`provenance`/`intersect` for provenance, `views`/
`view_partition`/`contraction` for the coin graph — and they converge on two objects that travel in
opposite directions across the partition lattice: `cluster.cluster_refined` ascends, declining a
co-spend the merge-only heuristic would take, and `declustering.decluster` descends, cutting a
partition it did not build. `decluster/baselines/` reimplements published algorithms against their papers,
`decluster/experiments/` holds one module per canonical run, and `decluster/adaptations/` holds the pieces that are
named adaptations rather than reproductions.

**The evidence chain.** Every published number travels the same path, and each step is checkable:

```
catalog/datasets/ the data, pinned by digest
decluster/experiments/ one module per run
catalog/runs/ the manifest: command, parameters, environment, claim ids, verification
results/artifacts/ the machine-written result
results/generated/ the document rendered from it, never edited by hand
releases/ the evidence bundle, listing every blob by name, size and digest
artifacts/sha256/ the content-addressed store holding those bytes
```

`reproduction/` carries one environment and lockfile per bundle, and `sources/` a deterministic
archive of the code at the revision a run names. `decluster-bundle sync` keeps tree, index and store
in step; a gate fails if they drift. A run's `verify` recomputes its artifact and compares it byte
for byte.

**The prose.** `PAPER.md` is the manuscript. `results/` holds both halves of the record: documents
generated from artifacts, and hand-written `RESULTS-*.md` reports that predate the chain.
`results/REPRODUCIBILITY.md` files every one of them under an evidence state, and each document
carries a footer naming its state or saying plainly that none has been assigned.

**The rest.** `bigquery/` holds the extraction recipes, including the ones for collections the
policy names as still missing. `catalog/ctp-claims.json` and `ctp-sources.json` bind each claim to
the literature and to the code that implements it. `tests/` is written as gates rather than
coverage: each file pins a property that has broken once, and says which in its docstring.

Installable (`pip install -e .`), so a protocol-specific client model can consume these primitives
from above without this repository knowing the protocol exists.

Every number is reproducible. MIT — see `LICENSE`.
Reproducibility is tracked per result. Every canonical run is bitwise reproducible from the committed store; the exact-oracle audit was the first, and bootstrapping any bundle looks the same:

```console
decluster-bundle --index releases/exact-oracle-evidence-v1.bundle.json \
--store artifacts --root /tmp/decluster-bundle bootstrap
decluster-bundle --index releases/exact-oracle-evidence-v1.bundle.json \
--root /tmp/decluster-bundle --work /tmp/decluster-run reproduce
```

That environment currently requires CPython 3.13 on macOS arm64. The committed content-addressed
store makes local cold-start execution possible. Public bootstrap remains pending until every blob
has a canonical HTTPS location and an independent mirror. Other results retain the guarantees and
limitations declared in `results/REPRODUCIBILITY.md` and their manifests.

MIT. See `LICENSE`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# N-S 2011 executable coverage

Generated from the canonical experiment artifact. Do not edit manually.

| component | status | limitation |
|---|---|---|
| `algorithm1_similarity` | `implemented` | — |
| `algorithm2_positive_weights` | `implemented` | — |
| `algorithm2_dummy_weights` | `implemented` | a dummy-incident node term is fixed at zero; the paper states this in prose, not in the printed formula |
| `annealing` | `partial` | iteration budget, RNG and best-state return are explicit local controls |
| `two_stage_mapping` | `implemented` | the paper picks an arbitrary unmapped node and stage 1 feeds back, so the ``repr`` order this driver imposes is a result-bearing local choice; injectivity comes from Algorithm 3's 1-1 mapping, not from the propagation section |
| `confidence_pruning` | `not_reproduced` | an implementation-complete pruning policy is not available |
| `accepted_mapping_correction` | `not_reproduced` | schedule and conflict resolution are not specified sufficiently |
| `algorithm3_cascade` | `implemented` | — |
| `learned_25_feature_model` | `not_reproduced` | the caller supplies an ML score; the published feature producer is absent |

Every non-implemented component is exercised through the refusal gate. The implemented components pass that gate, but the end-to-end paper pipeline remains unreproduced.

This deterministic contract does not reproduce the Flickr/Kaggle corpus, reported metrics, dummy-node convention, pruning policy, correction schedule, or learned model.
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
{
"schema_version": 1,
"id": "amount-channel-survey-v1",
"claim_ids": [
"ctp.payjoin.unnecessary_input",
"ctp.amount.subtransaction_ambiguity"
],
"code": {
"revision": "bcd9a3e511860b1b0ff5f3ee6338a2df29ecbfbf",
"dirty": false
},
"command": {
"argv": [
"python",
"-m",
"decluster.experiments.amount_channel_summary",
"reproduce",
"--artifact",
"results/artifacts/amount-channel-survey-v1.json",
"--markdown",
"results/generated/amount-channel-survey-v1.md"
]
},
"environment": {
"python": "3.13.7",
"lock_digest": "e0d6a8cada5d383c0aca2bd2a37f28c15721392469c94084128d369c29c5544d",
"platform": "macOS-26.6.2-arm64-arm-64bit-Mach-O",
"dependencies": []
},
"datasets": [],
"parameters": {
"composition": "identity-checked upstream artifacts only",
"components": {
"amount-local-channels-v1": "210ecb06ecaa32cc4cabe03ced8b85b0882a824dca2c361bd2c5dede7dcccf02",
"amount-subset-sum-v1": "240592b5af814fbcd28b06221805b934424170119da5e62e9da0281944377a9d",
"amount-per-coin-v1": "7be46858e221d0c942e7fa3ccc93b5eba28cf3a494fd00f07c2d50f2caa473df",
"amount-mapping-family-v1": "11f0ec645ea1be334dc7d24fbfc31047b234f335f48b5a514960472c7444b7d6",
"amount-pairwise-family-v1": "83f6a9e8501ee4df45f08b8c8ffc2f7265d40bf9add6d3f5093d712657c9dbf5"
}
},
"rng": {
"algorithm": null,
"seeds": []
},
"outputs": [
{
"path": "results/artifacts/amount-channel-survey-v1.json",
"bytes": 2589,
"sha256": "fcd4ad596d735b7c5a8dba43bc96481946ce5e78c3806932b60c10c865d1dcf8"
},
{
"path": "results/generated/amount-channel-survey-v1.md",
"bytes": 1082,
"sha256": "2f74b40fb24558a23f162d09da46a5f76a4434c170a78e0deb75eabba5d2ca28"
}
],
"reproducibility": {
"level": "bitwise_reproducible",
"availability": "complete"
},
"verification": {
"mode": "exact",
"argv": [
"python",
"-m",
"decluster.experiments.amount_channel_summary",
"verify",
"--artifact",
"results/artifacts/amount-channel-survey-v1.json",
"--markdown",
"results/generated/amount-channel-survey-v1.md"
],
"tests": [
"tests/test_amount_channel_summary_experiment.py"
],
"properties": [
"all five component identities are checked before composition",
"the summary performs no mechanism calculation",
"channels remain separate rather than becoming a scalar score",
"DSS claims retain their restricted-family qualification",
"the generated Markdown equals the canonical rendering"
],
"tolerance": null
},
"limitations": [
"this artifact composes upstream results and performs no mechanism calculation",
"component SHA-256 identities are mandatory",
"the five components measure different objects and are not combined into one score",
"DSS mapping and pairwise claims remain restricted to DSS's mapping family",
"the Bitcoin snapshot covers one 137-block interval from 2023",
"this summary is not a privacy certificate or CoinScore"
]
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"schema_version": 1,
"python": {
"implementation": "cpython",
"version": "3.13",
"system": "Darwin",
"machine": "arm64"
},
"source_archive": "sources/decluster-bcd9a3e-runtime.tar",
"project_root": "decluster",
"requirements": "reproduction/deterministic-partition/requirements.lock",
"dependency_directory": "reproduction/deterministic-partition"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"schema_version": 1,
"python": {
"implementation": "cpython",
"version": "3.13",
"system": "Darwin",
"machine": "arm64"
},
"source_archive": "sources/decluster-bcd9a3e-runtime.tar",
"project_root": "decluster",
"requirements": "reproduction/partition-schemes/requirements.lock",
"dependency_directory": "reproduction/partition-schemes"
}
Loading
Loading