# GeoProof Reference Standard — v1
### Proof of Presence

**Status:** Reference Standard v1.1 · **Date:** 2026-07 · **Verified against:** `@xyo-network` 7.0.11

> This is the first **GeoProof Reference Standard**: the artifact future products are
> *measured against*. The code in this package is **one conformant expression** of the
> standard — not the standard itself. GeoWallet, GeoJustice, GeoPresence, GeoAgora,
> GeoHackers, and GeoForge implement *against* this, rather than copying example code.
>
> Oxyon is the company. GeoProof is the protocol (see `../geoproof/SPEC.md`). This is
> the protocol's reference implementation.

## 1. Purpose

To establish a single, runnable, verified baseline for producing and verifying a
GeoProof event — so that every product in the ecosystem can be checked for conformance
against the same reference, instead of each re-deriving (and quietly diverging from)
how a proof is made.

## 2. The problem it solves

Without a reference, "supports GeoProof" means whatever each team decided it meant.
Schemas drift, signing differs, and two products that both claim to emit proofs can
produce events the other cannot verify. A reference standard fixes the meaning of
"conformant" to something executable.

## 3. Architectural overview

A GeoProof proof is produced in three steps, mapping to the philosophy:

```
Observe + Locate     createPresenceProof()   → a GeoProof event (XYO payload)
Verify (authorship)  signProof()             → a signed XYO bound witness
Verify (cryptographic) verifyProof()         → validation result ([] = valid)
```

- The **event** is an XYO payload under `oxyon.geoproof.presence.v1` (schema + fields),
  structurally validated by `@geo/geoproof`.
- The **bound witness** (`network.xyo.boundwitness`) carries `addresses`,
  `payload_hashes`, `payload_schemas`, `previous_hashes`, and `$signatures` — providing
  authorship and tamper-evidence.
- **Validation** is delegated to `@xyo-network/boundwitness-validator`. The standard
  does **not** reimplement XYO cryptography.

## 4. The reference implementation

[`src/presence.ts`](src/presence.ts) — three functions:

- `createPresenceProof(params)` → builds and structurally validates a `PresenceProof`.
- `signProof(proof, signer)` → binds it into a signed bound witness via
  `BoundWitnessBuilder().payload(proof).signer(account).build()`.
- `verifyProof(boundWitness)` → returns problems; `[]` means valid.

## 5. Runnable example

[`src/presence.example.ts`](src/presence.example.ts):

```bash
npm install          # pulls @xyo-network 7.0.x
npm run example
npm test
```

## 6. Expected inputs and outputs

**Input** — an observation with location and a signing account:

```ts
createPresenceProof({
  producer: 'geopresence',
  subject: account.address,
  location: { lat: 39.95, lon: -75.16, accuracyM: 8 },
  method: 'gps',
  observedAt: 1_750_000_000_000,
});
```

**Output** — a signed, valid bound witness (addresses/hash will differ per run and
key; structure and validity will not):

```json
{
  "signer": "ecc49fd644b41a8847a71a1c90780d500aa30814",
  "boundWitness": {
    "schema": "network.xyo.boundwitness",
    "addresses": ["ecc49fd644b41a8847a71a1c90780d500aa30814"],
    "payload_schemas": ["oxyon.geoproof.presence.v1"],
    "payload_hashes": ["e1710b74857e1cef006ba4c3071baa0a653db969d27b55f86b17b397d539f717"],
    "signatures": 1
  },
  "valid": true,
  "errors": []
}
```

## 7. Verification steps

A producer is conformant for Proof of Presence if, for a generated proof:

1. `payload_schemas[0] === 'oxyon.geoproof.presence.v1'` (canonical; legacy
   `winlew.geo.presence.*` accepted via `canonicalizeSchema`).
2. `addresses` contains the signer's address.
3. `$signatures.length >= 1`.
4. `BoundWitnessValidator(bw).validate()` returns `[]`.
5. The event passes `validateEventShape` (valid location, producer, subject, time).

## 8. Tests

[`src/presence.test.ts`](src/presence.test.ts) — runs under `node --test`:
- a presence proof binds, signs, and cryptographically validates (`[]`);
- a malformed event (out-of-range location) is rejected *before* signing.

**Verified in-repo on Node 24 with `@xyo-network` 7.0.11: 9/9 lifecycle tests passing (v1.1).**

## 9. Phase 1 Protocol Completions (v1.1)

The following lifecycle functions were added in v1.1 to complete the protocol
for production use:

### 9.1 Supersession (`supersede`)
```ts
const { supersession, boundWitness } = await supersede(oldReceiptBw, issuerAccount, {
  reason: 'New sensor calibration invalidated the original reading.',
  replacementBw: newReceiptBw,  // optional
});
```
Adds a new node to the DAG saying "given what we now know, the conclusion has
changed." The superseded record is NOT deleted — it still validates; you can
still replay it. The supersession is the chain's way of saying "don't stop there."
`reason` is required — silent supersession is a protocol violation.

### 9.2 Revocation (`revoke`)
```ts
const { revocation, boundWitness } = await revoke(statementBw, issuerAccount, {
  reason: 'GPS data fabricated — fraud confirmed.',
});
```
Full withdrawal with no replacement. History stays intact; this is a terminus
node, not an erasure. `reason` is required.

### 9.3 Key Rotation (`rotateKey`)
```ts
const { rotation, boundWitness } = await rotateKey(oldKey, newKey, {
  reason: 'Scheduled quarterly rotation.',
});
// verify: both addresses in bw.addresses; BW validates; payload in payload_hashes
const problems = await verifyRotation(boundWitness, rotation);
```
The dual-signer bound witness IS the endorsement. Both old and new keys must be
present as signers. A verifier confirms both: (a) both signatures valid, (b) both
addresses in `bw.addresses`, (c) rotation payload in `bw.payload_hashes`, (d) not
superseded or revoked. To complete rotation: update `GEOPROOF_MCP_SEED_FILE` to
the new seed and archive the old one.

### 9.4 Chained Attestations (`previous_hashes`)
When the same account builds consecutive bound witnesses, the XYO SDK auto-populates
`previous_hashes[0]` with `PayloadBuilder.dataHash(priorBw)`. This creates a
per-identity transparency log where any gap or reordering is detectable.
Applications issuing multiple receipts through the same verifier account get chaining
for free — no application code required.

**Confirmed via probe: `previous_hashes[0]` == `PayloadBuilder.dataHash(bw1)`, NOT
`PayloadBuilder.hash(bw1)`. Use `dataHash` for conformance vectors, not `hash`.**

### 9.5 Conformance Vectors
`packages/geoproof/vectors/v1.json` contains 7 deterministic GeoProof payloads
and their canonical XYO `dataHash` values. Run:
```
node packages/geoproof/src/vectors.test.ts
```
All 7 pass deterministically. These are the test vectors for cross-language
implementations.

## 10. Known limitations

- **Single signer.** This reference covers one-party authorship. Multi-party
  co-signed proofs (escrow/atomic-exchange shapes) are a future standard.
- **No on-chain anchoring here.** Binding + verification only; XL1 anchoring
  (`oxyon.geoproof.anchor.batch`) and indexing are separate references.
- **Version-pinned.** Verified against `@xyo-network` 7.0.11; re-verify when bumping —
  the XYO API has changed across major lines.
- **Schema import.** The reference imports the canonical schema from the sibling
  `@geo/geoproof` source by relative path so it runs without workspace wiring; a
  published product uses `import … from '@geo/geoproof'`.

## 10. Extension points for future products

- **Other event types** — `attestation`, `receipt`, `anchor.batch` follow the same
  three-step shape with their own schema and fields.
- **GeoJustice** — consumes `verifyProof` output and adds semantic/trust scoring,
  emitting an `oxyon.geoproof.receipt` linked to the proof via `$sources`.
- **GeoWallet** — owns the signing account; `signProof` is its core operation.
- **Multi-signer** — `BoundWitnessBuilder().signers([...])` for co-authored proofs.
- **Anchoring/indexing** — batch `payload_hashes` into `oxyon.geoproof.anchor.batch`
  and replay with the indexer (floor block + atomic checkpoints).
