Skip to content

shady-2004/contributor-identity-prototype

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

85 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Decentralized Contributor Verification

A proof-of-concept implementation of decentralized contributor identity verification for open source workflows. This prototype anchors GPG commit authorship to a Hedera DID via a challenge-response handshake, enabling cryptographically verifiable Pull Request status checks on GitHub.


πŸ“– Research Foundation

This project is the technical implementation of the concepts discussed in my Medium research. I recommend reading the article to understand the "Why" before diving into the "How":

πŸ”— The Future of Contributor Trust: Linking DIDs and VCs to the Pull Request Workflow β€” Medium


πŸš€ Live Demo & Validation

Running Demo https://contributor-identity-prototype.vercel.app/
Demo Video full onboarding + PR verification cycle walkthrough
Test Repository repository used to validate real-world GitHub webhook triggers

πŸ“‚ Repository Structure

This repository is organized in two phases, progressing from isolated cryptographic proof to a full-stack integration:

/research-logic β€” Phase 1: Cryptographic Simulation

A self-contained Node.js/TypeScript environment used to validate the core architecture before building the full prototype. Contains:

  • The challenge-response handshake simulation
  • DID registry mock and resolution logic
  • GPG ↔ Ed25519 binding proof-of-concept
  • Dockerized test environment for isolated runs

/contributor-identity-prototype β€” Phase 2: Full-Stack Prototype

The production-grade POC. A React/NestJS application that bridges GitHub contributions with the Hedera Hashgraph network. This is the implementation described in the rest of this document.


🧭 Problem Statement

Current GitHub contribution workflows rely on email-based identity and platform accounts for attribution β€” both of which are trivially spoofable. Commit author metadata can be forged, GPG keys can be registered under any identity, and there is no on-chain binding between a developer's real-world key material and their contributions.

This becomes a supply chain risk, particularly in the context of agentic AI systems capable of flooding open source repositories with impersonating or low-quality contributions at scale.

This prototype addresses this by implementing a cryptographic triangulation model β€” binding three independent identity factors:

Factor Mechanism What It Proves
Social GitHub OAuth Control of the GitHub account
Code Authorship GPG Signature Authorship of the specific git commit
Decentralized Ed25519 / Hedera DID Control of the Web3 identity

A PR status check passes only when all three are independently verifiable.


πŸ—οΈ Architecture

The system is composed of three logical layers:

1. Frontend Vault (Non-Custodial Edge Wallet)

The React/Vite frontend acts as a browser-based edge wallet. It follows a strictly non-custodial model:

  • Keypair generation: Ed25519 keypairs are generated client-side using @noble/ed25519.
  • Key storage: The private key is encrypted at rest in localStorage using AES-256-GCM with a key derived via PBKDF2 (100,000 iterations, SHA-256, random 16-byte salt).
  • Signing: The private key is decrypted only into volatile memory during active signing sessions. The backend never sees the private key at any point.
  • VP construction: Verifiable Presentations are assembled and signed entirely in the browser before transmission.

2. Backend Orchestrator (NestJS, Zero-Trust)

The backend coordinates verification without ever holding user secrets:

  • Challenge issuance: Generates single-use nonces per PR verification task to prevent replay attacks.
  • GPG verification: Cross-references the GPG key ID extracted from PR commits against the key registered during onboarding.
  • DLT resolution: When verifying a VP, the backend ignores any public key provided in the API payload and independently resolves the user's DID on Hedera to fetch the canonical public key.
  • GitHub integration: Listens to pull_request webhooks and writes status checks back to the PR based on verification outcome.

3. Hedera Hashgraph (Global Root of Trust)

DID Documents and Ed25519 public keys are anchored on Hedera, providing an immutable, independently resolvable source of truth.


πŸ“‹ Credential Formats

Verifiable Credential (issued during onboarding)

{
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://w3id.org/security/suites/ed25519-2020/v1"
  ],
  "type": ["VerifiableCredential", "GpgVerificationCredential"],
  "issuer": "<ISSUER_DID>",
  "issuanceDate": "<ISO_TIMESTAMP>",
  "credentialSubject": { "...": "..." },
  "proof": {
    "type": "Ed25519Signature2018",
    "proofPurpose": "assertionMethod",
    "verificationMethod": "<ISSUER_DID>#key-1",
    "signatureValue": "<BASE64_SIG>"
  }
}

Verifiable Presentation (submitted per PR verification)

{
  "@context": ["https://www.w3.org/2018/credentials/v1"],
  "type": ["VerifiablePresentation"],
  "holder": "<USER_DID>",
  "verifiableCredential": ["<VC_OBJECT>"],
  "proof": {
    "type": "Ed25519Signature2020",
    "proofPurpose": "authentication",
    "verificationMethod": "<USER_DID>#key-1",
    "challenge": "<SERVER_NONCE>",
    "signatureValue": "<BASE64_SIG>"
  }
}

The challenge field in the VP proof binds each presentation to a specific server-issued nonce, making intercepted VPs non-replayable.


πŸ”„ Process Flows

Flow A: Onboarding & Identity Anchoring

sequenceDiagram
    actor User
    participant FE as Frontend Vault
    participant BE as Backend API
    participant GH as GitHub
    participant Hedera as Hedera DLT

    User->>GH: Authenticates via OAuth
    GH-->>BE: Returns OAuth Profile & Token
    BE-->>FE: Issues JWT Session Token

    User->>FE: Creates Vault Password
    FE->>FE: Generates Ed25519 Keypair (Noble)
    FE->>FE: Encrypts PrivKey (AES-256-GCM / PBKDF2)
    FE->>BE: Request Challenge Nonce
    BE-->>FE: Returns Nonce

    User->>FE: Signs Nonce with local GPG Key
    FE->>BE: Submit GPG Sig + Ed25519 PubKey
    BE->>BE: Verify GPG Signature

    BE->>FE: Send didMessage challenge
    FE->>FE: Sign didMessage with Ed25519 PrivKey
    FE->>BE: Return signed didMessage

    BE->>Hedera: Register DID & Anchor PubKey
    BE->>BE: Generate Verifiable Credential (VC)
    BE-->>FE: Return VC linking GitHub + GPG + DID
Loading

Flow B: Pull Request Verification

sequenceDiagram
    actor User
    participant GH as GitHub
    participant BE as Backend Verifier
    participant Hedera as Hedera DLT
    participant FE as Frontend Vault

    User->>GH: Opens Pull Request (GPG Signed)
    GH->>BE: Webhook: pull_request.opened

    BE->>BE: Fetch PR Commits & Extract GPG Key ID
    BE->>GH: Set PR Status: "Pending Verification"
    BE->>BE: Generate Unique Challenge Nonce

    User->>FE: Opens Dashboard & Decrypts Vault
    FE->>BE: Fetch Pending Tasks
    BE-->>FE: Returns Task + Nonce

    FE->>FE: Constructs & Signs VP with challenge nonce
    FE->>BE: Submit VP

    BE->>Hedera: Resolve DID β†’ fetch canonical Ed25519 PubKey
    Hedera-->>BE: Returns PubKey
    BE->>BE: Verify VP signature & nonce binding
    BE->>GH: Set PR Status: "Success βœ“"
Loading

βš™οΈ GitHub App β€” Verification Engine

The GitHub App is the operational core of the system. It is installed on the target repository and drives the full verification lifecycle via webhook events.

Webhook listeners:

  • pull_request.opened β€” triggers a new verification task on every new PR
  • pull_request.synchronize β€” re-triggers verification when new commits are pushed

Verification pipeline (per PR):

  1. Extract the committer's GitHub ID from the webhook payload
  2. Look up the user's registered GPG key in the database
  3. Fetch the commit's GPG verification data from the GitHub API
  4. Parse the raw PGP signature to extract the signing Key ID if GitHub doesn't surface it directly
  5. Compare the commit's signing Key ID against the registered key β€” fail immediately on mismatch
  6. If GPG matches, generate a nonce and create a PENDING verification task
  7. Set the PR status to pending, linking to the contributor dashboard
  8. Once the user submits a valid VP from the frontend, transition the PR status to success

GitHub PR Status Check States:

State Trigger Message
🟑 Pending GPG verified, awaiting VP signature GPG Verified. Waiting for Contributor Identity signature...
βœ… Success Full chain verified (GPG + Ed25519 + Hedera) Verified: Ed25519 signature & GPG Key match confirmed.
❌ Failure GPG key mismatch GPG Mismatch: Commit signed with <keyId>, but linked to <registeredKeyId>...
⚠️ Error User not registered / unexpected error User not registered / internal error

Live Status Check Screenshots:

βœ… Full verification passed β€” Ed25519 signature and GPG key confirmed on-chain:

Success Check

❌ GPG key mismatch β€” commit was signed with a different key than the registered one:

Failure Check

🟑 Pending β€” GPG verified, waiting for the contributor to sign the VP from the dashboard:

Pending Check


πŸ›‘οΈ Security Model

Replay Attack Prevention: Each PR verification task generates a unique server-side nonce. The VP proof must include and sign this exact nonce (challenge field). A captured VP cannot be replayed against a different task.

Independent DLT Resolution: The verifier ignores the public key in the API request body. It parses the holder DID from the VP and independently resolves the associated key on Hedera. This eliminates key substitution attacks.

Non-Custodial Key Storage: AES-256-GCM with PBKDF2-derived keys means the encrypted blob in localStorage is computationally infeasible to brute-force without the vault password. The plaintext private key never leaves the browser.

Cryptographic Triangulation: The GPG key ID extracted from the PR commit is cross-referenced against the GPG key registered and verified during onboarding. A contributor cannot open a verifiable PR under a different GPG identity than the one they enrolled with.


⚠️ Prototype Limitations & Future Work

This is a POC β€” the following are known constraints and the intended upgrade path:

Current State Limitation Future Implementation
Custom HTTP API for VP submission No standardized presentation exchange OID4VP (OpenID for Verifiable Presentations)
Direct VC issuance over REST No standardized credential issuance protocol OID4VCI (OpenID for Verifiable Credential Issuance)
Raw JSON-LD VC format Not interoperable with SD-JWT wallets SD-JWT VC format
Edge wallet in browser localStorage No cross-device portability or native key management Mobile application (React Native / native secure enclave)

The current prototype deliberately skips the OID4VC handshake layer to keep the cryptographic core demonstrable within the POC scope. The VC/VP data structures are W3C-compliant JSON-LD and are designed to be forward-compatible with the full OID4VC stack.


πŸ“‚ Project Structure

Backend (NestJS)

backend/src/
β”œβ”€β”€ auth/               # GitHub OAuth & JWT issuance
β”œβ”€β”€ user/               # PostgreSQL entities (TypeORM)
β”œβ”€β”€ hedera/             # Hedera DLT integration (DID registration & resolution)
β”œβ”€β”€ identity/           # VC issuance & GPG linking logic
└── github-identity/    # Webhook listeners & core verification engine
    └── verifier.ts     # Cryptographic verification logic (GPG + Ed25519 + DLT resolution)

Frontend (React/Vite)

frontend/src/
β”œβ”€β”€ pages/              # Dashboard, Onboarding, Login
β”œβ”€β”€ hooks/              # State management
└── services/
    β”œβ”€β”€ apiService.js   # Axios + backend communication
    └── cryptoService.js # Noble/ed25519, AES-GCM vault, VP construction

πŸ”— References

About

A decentralized identity prototype that secures the software supply chain by linking GPG commit signatures to DIDs and VCs. Preventing impersonation in Pull Request workflows.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors