Skip to content

Disclosable DID DHT Documents #147

@decentralgabe

Description

@decentralgabe

Overview

tl;dr only publish signed commitments to DID Documents instead of encoded documents

There are two use-cases where this might be useful

  1. Large DID Documents
  2. DID Documents that want to be publicly discoverable (and verifiable) but privately shareable

The latter case is mostly useful for discover in the case of uses with type indexing or alias schemes (#77)

Proposal

The proposal is as follows:

Create a Disclosable DID DHT Document

  1. Create a DID DHT Document
  2. Create a hash of the document - this could optionally be salted if we believe plaintext attacks to be of concern
  3. Encode a minimal DNS packet that contains only the hash value
  4. Publish to the DHT as normal

Resolve a Disclosable DID DHT Document

  1. Resolve the DID Document from the DHT
  2. Verify its signature
    ...
  3. Have the controller of the DID Document send the revealed DID Document and salt if available
  4. Re-compute the hash and compare it to the record from the DHT

Alternate proposal

There is a possible modification to this proposal that reduces the need for a holder to transmit the DID Document to a resolver, which is to rely on a secondary storage mechanism. Alongside the hash DNS record would be a record to a storage system to retrieve and verify the full DID Document. A nice property is that the storage does not need to be trusted as tamper evidence is still provided by the DHT.

Sample Code

This code is a bit contrived. In reality there is no reason to sign the hash separately from the BEP44 packet, unless there is utility in being able to share the document without publishing it to the network.

package main

import (
    "crypto/ed25519"
    "crypto/rand"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
)

// GenerateKeyPair generates a new Ed25519 public/private key pair.
func GenerateKeyPair() (ed25519.PublicKey, ed25519.PrivateKey, error) {
    publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
    if err != nil {
        return nil, nil, err
    }
    return publicKey, privateKey, nil
}

// CommitToDocument creates a "commitment" to the DID Document using a hash function.
func CommitToDocument(doc string) string {
    hasher := sha256.New()
    hasher.Write([]byte(doc))
    return hex.EncodeToString(hasher.Sum(nil))
}

// SignCommitment signs the commitment with the private key.
func SignCommitment(commitment string, privateKey ed25519.PrivateKey) ([]byte, error) {
    sig, err := privateKey.Sign(rand.Reader, []byte(commitment), nil)
    if err != nil {
        return nil, err
    }
    return sig, nil
}

// VerifyCommitmentSignature verifies the signature of the commitment.
func VerifyCommitmentSignature(publicKey ed25519.PublicKey, commitment string, sig []byte) bool {
    return ed25519.Verify(publicKey, []byte(commitment), sig)
}

func main() {
    // Simulating a DID Document
    didDocument := `{"id":"did:example:123","publicKey":"...","authentication":[...]}`
    
    // Generate key pair
    pubKey, privKey, err := GenerateKeyPair()
    if err != nil {
        fmt.Println("Error generating keys:", err)
        return
    }
    
    // Create a commitment to the DID Document
    commitment := CommitToDocument(didDocument)
    fmt.Println("Commitment:", commitment)
    
    // Sign the commitment
    sig, err := SignCommitment(commitment, privKey)
    if err != nil {
        fmt.Println("Error signing commitment:", err)
        return
    }
    fmt.Println("Signature:", hex.EncodeToString(sig))
    
    // Verify the signature
    verified := VerifyCommitmentSignature(pubKey, commitment, sig)
    fmt.Println("Signature verified:", verified)
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions