Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for retention challenges #219

Merged
merged 11 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions impl/internal/did/pow.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/hex"
"fmt"
"math/big"
"strconv"
"strings"
)

Expand All @@ -29,14 +30,37 @@ func hasLeadingZeros(hash string, difficulty int) bool {
return strings.HasPrefix(binaryHash, target)
}

// computeRetentionProof generates the Retention Proof Hash and checks if it meets the criteria.
func computeRetentionProof(didIdentifier, bitcoinBlockHash string, difficulty, nonce int) (string, bool) {
// solveRetentionChallenge generates the Retention Challenge Hash and checks if it meets the criteria.
func solveRetentionChallenge(didIdentifier, inputHash string, difficulty, nonce int) (string, bool) {
// Concatenating the DID identifier with the retention value
retentionValue := didIdentifier + (bitcoinBlockHash + fmt.Sprintf("%d", nonce))
retentionValue := didIdentifier + (inputHash + fmt.Sprintf("%d", nonce))

// Computing the SHA-256 hash
hash := computeSHA256Hash(retentionValue)

// Checking for the required number of leading zeros according to the difficulty
return hash, hasLeadingZeros(hash, difficulty)
}

// validateRetentionSolution validates the Retention Solution.
func validateRetentionSolution(did, hash, retentionSolution string, difficulty int) bool {
parts := strings.Split(retentionSolution, ":")
if len(parts) != 2 {
return false
}

nonce, err := strconv.ParseUint(parts[1], 10, 64)
if err != nil {
return false
}

retentionValue := did + hash + strconv.FormatUint(nonce, 10)
computedHash := computeSHA256Hash(retentionValue)

if !hasLeadingZeros(computedHash, difficulty) {
return false
}

solutionHash := parts[0]
return solutionHash == computedHash
}
14 changes: 9 additions & 5 deletions impl/internal/did/pow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,26 @@ import (
)

func TestPOW(t *testing.T) {
// Example usage of computeRetentionProof
// Example usage of solveRetentionChallenge
didIdentifier := "did:dht:test"
bitcoinBlockHash := "000000000000000000022be0c55caae4152d023dd57e8d63dc1a55c1f6de46e7"
inputHash := "123bcdefghobc23567822be0c55caae4152d023dd57e8d63dc1a55c1f6de46e7"

// 26 leading zeros
difficulty := 26

timer := time.Now()
for nonce := 0; nonce < math.MaxInt; nonce++ {
hash, isValid := computeRetentionProof(didIdentifier, bitcoinBlockHash, difficulty, nonce)
solution, isValid := solveRetentionChallenge(didIdentifier, inputHash, difficulty, nonce)
if isValid {
fmt.Printf("Hash: %s\n", hash)
fmt.Printf("Valid Retention Proof: %v\n", isValid)
fmt.Printf("Solution: %s\n", solution)
fmt.Printf("Valid Retention Solution: %v\n", isValid)
fmt.Printf("Nonce: %d\n", nonce)

isValidRetentionSolution := validateRetentionSolution(didIdentifier, inputHash, fmt.Sprintf("%s:%d", solution, nonce), difficulty)
fmt.Printf("Validated Solution: %v\n", isValidRetentionSolution)
break
}
}

fmt.Printf("Time taken: %s\n", time.Since(timer))
}
108 changes: 67 additions & 41 deletions spec/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ info:
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
version: v0.1
version: v1.0
paths:
/{id}:
get:
Expand All @@ -22,7 +22,7 @@ paths:
type: string
responses:
"200":
description: "64 bytes sig, 8 bytes u64 big-endian seq, 0-1000 bytes of v."
description: 64 bytes sig, 8 bytes u64 big-endian seq, 0-1000 bytes of v
content:
application/octet-stream:
schema:
Expand Down Expand Up @@ -50,7 +50,7 @@ paths:
put:
tags:
- DHT
summary: Put DNS-encoded BEP44 records into the DHT
summary: Put a DNS-encoded BEP44 record set into the DHT
description: Put a DNS-encoded BEP44 record set into the DHT
parameters:
- name: id
Expand All @@ -60,7 +60,7 @@ paths:
schema:
type: string
requestBody:
description: "64 bytes sig, 8 bytes u64 big-endian seq, 0-1000 bytes of v."
description: 64 bytes sig, 8 bytes u64 big-endian seq, 0-1000 bytes of v
content:
application/octet-stream:
schema:
Expand Down Expand Up @@ -105,32 +105,35 @@ paths:
properties:
sig:
type: string
description: A base64URL-encoded signature of the BEP44 payload.
description: A base64URL-encoded signature of the BEP44 payload
seq:
type: integer
description: A sequence number for the request, recommended to be a unix timestamp in seconds.
description: A sequence number for the request, recommended to be a unix timestamp in seconds
v:
type: string
description: A base64URL-encoded bencoded DNS packet containing the DID Document.
retention_proof:
description: A base64URL-encoded bencoded DNS packet containing the DID Document
retention_solution:
type: string
description: A retention proof calculated according to the spec-defined retention proof algorithm.
description: A retention solution calculated according to the spec-defined retention solution algorithm
required: [ did, sig, seq, v ]
responses:
"202":
description: Accepted. The server has accepted the request as valid and will publish it to the
description: The server has accepted the request as valid and will publish it to the DHT
content:
application/json:
schema:
type: string
type: object
properties:
expiry:
type: number
"400":
description: Invalid request.
description: Invalid request
content:
application/json:
schema:
type: string
"401":
description: Invalid signature.
description: Invalid signature or retention solution
content:
application/json:
schema:
Expand All @@ -141,57 +144,66 @@ paths:
application/json:
schema:
type: string
"503":
description: Retention sets have been temporarily disabled.
content:
application/json:
schema:
type: string
get:
tags:
- DID
summary: Resolve a DID
description: Resolve a DID from the DHT first, with a fallback to local storage.
description: Resolve a DID from the DHT first, with a fallback to local storage
parameters:
- name: id
in: path
description: DID to resolve.
description: The DID to resolve
required: true
schema:
type: string
- name: seq
in: query
description: Sequence number of the DID to resolve.
description: The sequence number of the DID to resolve
required: false
schema:
type: integer
responses:
"200":
description: The resolved DID Document.
description: The resolved DID Document
content:
application/json:
schema:
type: object
properties:
did:
type: object
description: "The DID Document."
description: The DID Document
dht:
type: string
description: "An unpadded base64URL-encoded representation of a full DNS-encoded BEP44 payload, represented as 64 bytes sig, 8 bytes u64 big-endian seq, 0-1000 bytes of v concatenated; enabling independent verification."
description: An unpadded base64URL-encoded representation of a full DNS-encoded BEP44 payload, represented as 64 bytes sig, 8 bytes u64 big-endian seq, 0-1000 bytes of v concatenated; enabling independent verification
types:
type: array
items:
type: integer
description: "The types associated with the DID."
description: The types associated with the DID
sequence_numbers:
type: array
items:
type: integer
description: "The sequence numbers available for querying for this node."
description: The sequence numbers available for querying for this node
expiry:
type: number
description: The Unix Timestamp in seconds indicating when the DID will be evicted from the Gateway's Retained DID Set
required: [ did, dht ]
"400":
description: Invalid request.
description: Invalid request
content:
application/json:
schema:
type: string
"404":
description: DID could not be resolved.
description: The requested DID could not be resolved
content:
application/json:
schema:
Expand All @@ -200,11 +212,11 @@ paths:
get:
tags:
- DID
summary: Retrieve a list of supported types for indexing.
description: Retrieve a list of supported indexing types, according to the spec-defined type list.
summary: Retrieve a list of supported types for indexing
description: Retrieve a list of supported indexing types, according to the spec-defined type list
responses:
"200":
description: A list of types support, alongside their human-readable description.
description: A list of types support, alongside their human-readable description
content:
application/json:
schema:
Expand All @@ -218,7 +230,7 @@ paths:
type: string
required: [ type, description ]
"404":
description: Type indexing not supported by this gateway.
description: Type indexing not supported by this gateway
content:
application/json:
schema:
Expand All @@ -227,8 +239,8 @@ paths:
get:
tags:
- DID
summary: Retrieve a list of DIDs indexed under a given type.
description: Retrieve a list of DIDs indexed under a given type, according to the spec-defined type index.
summary: Retrieve a list of DIDs indexed under a given type
description: Retrieve a list of DIDs indexed under a given type, according to the spec-defined type index
parameters:
- name: id
in: path
Expand All @@ -238,51 +250,65 @@ paths:
type: integer
- name: offset
in: query
description: Specifies the starting position from where the type records should be retrieved. Default is 0.
description: Specifies the starting position from where the type records should be retrieved. Default is 0
schema:
type: integer
- name: limit
in: query
description: Specifies the maximum number of type records to retrieve. Default is 100.
description: Specifies the maximum number of type records to retrieve. The default is 100.
schema:
type: integer
responses:
"200":
description: A list of DIDs indexed under the given type.
description: A list of DIDs indexed under the given type
content:
application/json:
schema:
type: array
items:
type: string
"404":
description: Type not found.
description: Type not found
content:
application/json:
schema:
type: string
/difficulty:
/challenge:
decentralgabe marked this conversation as resolved.
Show resolved Hide resolved
get:
tags:
- DID
summary: Get information about the current difficulty.
description: Get information needed to calculate a retention proof for DID PUT operations.
summary: Get information necessary to solve a retention challenge
description: Get information needed to calculate a retention solution for DID PUT operations
responses:
"200":
description: The current hash and difficulty to calculate a retention proof against.
description: The current hash and difficulty to calculate a retention solution against, along with an estimated retention guarantee represented by the expiry property
content:
application/json:
schema:
type: object
properties:
hash:
type: string
description: The current hash which is to be used as input for computing a retention solution
hash_source:
type: string
description: The source of the hash as defined by the Hash Source Registry.
difficulty:
type: integer
required: [ hash, difficulty ]
"404":
description: Retention proofs not supported by this gateway.
description: The current difficulty of the challenge representing the number of bits of leading zeros the resulting hash must contain
expiry:
type: integer
description: An approximate expiry date-time value, if a valid Retention Solution is submitted against this challenge, represented as a Unix Timestamp in seconds. The precise expiry date-time value is returned as a part of a PUT operation
required: [ hash, difficult, expiry ]
"501":
description: Retention challenges are not supported
content:
application/json:
schema:
type: string
"503":
description: Retention sets have been temporarily disabled
content:
application/json:
schema:
type: string
type: string
Loading
Loading