Skip to main content
Research Preview — Under active development.

Verify Module

The Verify module provides evidence-based verification of location claims. It enables collecting location evidence on client devices, bundling evidence into proofs, and verifying those proofs server-side.
import { AstralSDK } from '@decentralized-geo/astral-sdk';

const astral = new AstralSDK({
  chainId: 84532,
  signer: wallet,
  apiUrl: 'https://api.astral.global'
});

// Evidence collection (client-side)
astral.stamps.collect(pluginOptions);
astral.stamps.create(pluginOptions, signals);
astral.stamps.sign(unsigned, signer);

// Proof construction
astral.proofs.create(claim, stamps);

// Verification (server-side)
astral.verify.stamp(stamp);
astral.verify.proof(proof, options);
For conceptual background, see Location Proofs.

Evidence Collection

Methods for collecting and packaging location evidence on the client.

stamps.collect()

Collect raw signals from the environment using a plugin.
astral.stamps.collect(
  pluginOptions: PluginOptions
): Promise<RawSignals>

Parameters

ParameterTypeRequiredDescription
pluginOptions.namestringYesPlugin name: "proofmode" or "witnesschain"
pluginOptions.versionstringYesPlugin version (semver)
pluginOptions.configobjectNoPlugin-specific configuration

Example

const signals = await astral.stamps.collect({
  name: 'proofmode',
  version: '0.1.0',
  config: { timeout: 5000 }
});

stamps.create()

Process raw signals into an unsigned stamp.
astral.stamps.create(
  pluginOptions: PluginOptions,
  signals: RawSignals
): Promise<UnsignedStamp>

Parameters

ParameterTypeRequiredDescription
pluginOptionsPluginOptionsYesPlugin name and version
signalsRawSignalsYesOutput from collect()

Example

const unsigned = await astral.stamps.create(pluginOptions, signals);

console.log(unsigned.location);           // Observed location (LP format)
console.log(unsigned.temporalFootprint);  // { start, end }

stamps.sign()

Sign an unsigned stamp with a key.
astral.stamps.sign(
  unsigned: UnsignedStamp,
  signer: Signer
): Promise<LocationStamp>

Parameters

ParameterTypeRequiredDescription
unsignedUnsignedStampYesOutput from create()
signerSignerYesSigning key (ethers Signer or compatible)

Example

const stamp = await astral.stamps.sign(unsigned, deviceSigner);
// stamp is now ready to include in a proof

Proof Construction

proofs.create()

Bundle a claim with stamps into a location proof.
astral.proofs.create(
  claim: LocationClaim,
  stamps: LocationStamp[]
): LocationProof

Parameters

ParameterTypeRequiredDescription
claimLocationClaimYesThe location claim
stampsLocationStamp[]YesOne or more signed stamps

Example

const claim = {
  lpVersion: '0.2',
  locationType: 'geojson-point',
  location: { type: 'Point', coordinates: [-122.4194, 37.7749] },
  srs: 'http://www.opengis.net/def/crs/OGC/1.3/CRS84',
  subject: { scheme: 'eth-address', value: '0x...' },
  radius: 100,
  time: { start: Date.now() / 1000 - 60, end: Date.now() / 1000 }
};

const proof = astral.proofs.create(claim, [stamp]);

Verification Operations

Methods for verifying location proofs. These run server-side in a TEE.

verify.stamp()

Verify a stamp’s internal validity (no claim assessment).
astral.verify.stamp(
  stamp: LocationStamp
): Promise<StampVerificationResult>

Parameters

ParameterTypeRequiredDescription
stampLocationStampYesThe stamp to verify

Example

const result = await astral.verify.stamp(stamp);

console.log(result.valid);             // true
console.log(result.signaturesValid);   // true
console.log(result.structureValid);    // true
console.log(result.signalsConsistent); // true

verify.proof()

Full verification of a location proof against its claim.
astral.verify.proof(
  proof: LocationProof,
  options?: VerifyOptions
): Promise<VerifiedLocationProof>

Parameters

ParameterTypeRequiredDescription
proofLocationProofYesThe proof to verify
options.chainIdnumberNoChain for attestation signing
options.submitOnchainbooleanNoSubmit attestation onchain (default: false)

Example

const result = await astral.verify.proof(proof, { chainId: 84532 });

console.log(result.credibility.confidence);  // 0.85
console.log(result.uid);                     // 0xabc123...

if (result.credibility.confidence > 0.8) {
  console.log('High confidence location proof');
}
Confidence is not probability. A confidence of 0.85 does NOT mean “85% probability the claim is true.” It means “the evidence is reasonably strong.” Calibrating to true probability is future work.

Return Types

StampVerificationResult

interface StampVerificationResult {
  valid: boolean;
  signaturesValid: boolean;
  structureValid: boolean;
  signalsConsistent: boolean;
  pluginResult: Record<string, unknown>;
}

VerifiedLocationProof

interface VerifiedLocationProof {
  proof: LocationProof;
  credibility: CredibilityAssessment;
  uid: string;
  attester: string;
  timestamp: number;
  chainId?: number;
}

CredibilityAssessment

interface CredibilityAssessment {
  confidence: number;                   // 0-1 (NOT calibrated probability)
  stampResults: StampResult[];
  correlation?: CorrelationAssessment;
  dimensions?: Record<string, number>;
}

interface StampResult {
  stampIndex: number;
  plugin: string;
  signaturesValid: boolean;
  structureValid: boolean;
  signalsConsistent: boolean;
  supportsClaim: boolean;
  claimSupportScore: number;
  pluginResult: Record<string, unknown>;
}

interface CorrelationAssessment {
  independence: number;    // 0-1
  agreement: number;       // 0-1
  notes: string[];
}

Input Types

PluginOptions

interface PluginOptions {
  name: string;                         // "proofmode" | "witnesschain"
  version: string;                      // Semantic version
  config?: Record<string, unknown>;     // Plugin-specific config
}

LocationClaim

Extends Location Protocol v0.2 with verification-specific fields.
interface LocationClaim {
  // Location Protocol fields
  lpVersion: string;
  locationType: string;
  location: LocationData;
  srs: string;

  // Verification fields
  subject: SubjectIdentifier;
  radius: number;                       // Required — meters
  time: { start: number; end: number }; // Unix timestamps (seconds)
  eventType?: string;
}

SubjectIdentifier

Follows DID pattern.
interface SubjectIdentifier {
  scheme: string;   // "eth-address" | "device-pubkey" | "did:web"
  value: string;
}

// Examples:
// { scheme: "eth-address", value: "0x1234..." }
// { scheme: "device-pubkey", value: "0xabcd..." }

LocationStamp

Evidence conforming to Location Protocol for its location data.
interface LocationStamp {
  // Location (LP v0.2) — observed location
  lpVersion: string;
  locationType: string;
  location: LocationData;
  srs: string;

  // Temporal
  temporalFootprint: { start: number; end: number };

  // Plugin
  plugin: string;
  pluginVersion: string;
  signals: Record<string, unknown>;
  signatures: Signature[];
}

LocationProof

interface LocationProof {
  claim: LocationClaim;
  stamps: LocationStamp[];
}

Plugins

Available Plugins

PluginEnvironmentsEvidence Type
proofmodeiOS, Android, React NativeHardware attestation, sensor fusion
witnesschainNode.js serverNetwork latency, challenger attestations

Plugin-Specific Config

ProofMode:
const signals = await astral.stamps.collect({
  name: 'proofmode',
  version: '0.1.0',
  config: {
    timeout: 5000,
    sensors: ['accelerometer', 'gyroscope']
  }
});
WitnessChain:
const signals = await astral.stamps.collect({
  name: 'witnesschain',
  version: '0.1.0',
  config: {
    timeout: 10000,
    minChallengers: 3
  }
});

Complete Example

import { AstralSDK } from '@decentralized-geo/astral-sdk';
import { ethers } from 'ethers';

// Setup
const provider = new ethers.JsonRpcProvider('https://sepolia.base.org');
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

const astral = new AstralSDK({
  chainId: 84532,
  signer: wallet,
  apiUrl: 'https://api.astral.global'
});

// 1. Collect evidence on device
const pluginOptions = { name: 'proofmode', version: '0.1.0' };
const signals = await astral.stamps.collect(pluginOptions);
const unsigned = await astral.stamps.create(pluginOptions, signals);
const stamp = await astral.stamps.sign(unsigned, wallet);

// 2. Create claim
const claim = {
  lpVersion: '0.2',
  locationType: 'geojson-point',
  location: { type: 'Point', coordinates: [-122.4194, 37.7749] },
  srs: 'http://www.opengis.net/def/crs/OGC/1.3/CRS84',
  subject: { scheme: 'eth-address', value: wallet.address },
  radius: 100,
  time: { start: Date.now() / 1000 - 60, end: Date.now() / 1000 }
};

// 3. Bundle into proof
const proof = astral.proofs.create(claim, [stamp]);

// 4. Verify
const result = await astral.verify.proof(proof, { chainId: 84532 });

console.log('Confidence:', result.credibility.confidence);
console.log('Attestation UID:', result.uid);

// Check confidence threshold
if (result.credibility.confidence > 0.8) {
  console.log('High confidence - proof accepted');
}

Multi-Stamp Example

// Collect from multiple independent plugins
const proofmodeStamp = await collectAndSign({ name: 'proofmode', version: '0.1.0' });
const witnessStamp = await collectAndSign({ name: 'witnesschain', version: '0.1.0' });

// Bundle into proof with multiple stamps
const proof = astral.proofs.create(claim, [proofmodeStamp, witnessStamp]);

// Verify — cross-correlation increases confidence
const result = await astral.verify.proof(proof);

console.log('Confidence:', result.credibility.confidence);           // Higher
console.log('Independence:', result.credibility.correlation.independence);  // 0.95
console.log('Agreement:', result.credibility.correlation.agreement);        // 0.88
Key principle: Independent, corroborating evidence increases confidence. Redundant stamps from the same system don’t add confidence — but they don’t subtract either.

API Reference: Verify

View the HTTP API documentation