Skip to main content

DIDs

DIDs are a decentralized way to represent an identity, be that an organization or a person. It is possible to recover a DID even if the key is lost, by having multiple parties send messages approving the inner puzzle change.

More functionality will be added to the DID standard in the future, allowing for easier identification and recovery methods.

Code Examples

chia-blockchain

The official Chia wallet has a reference implementation for the following in Python:

chia-rs

The wallet code used by the MonsterSprouts example game has the following reference methods:

DID Code

This is the source code of the DID inner puzzle, which can also be found in the chia-blockchain repository in the puzzle did_innerpuz.clvm.

Expand DID Inner Puzzle
did_innerpuz.clvm
; The DID innerpuzzle is designed to sit inside the singleton layer and provide functionality related to being an identity.
; At the moment the two pieces of functionality are recovery and message creation.
; A DID's ID is it's Singleton ID
; Recovery is based around having a list of known other DIDs which can send messages approving you change the innerpuzzle of your DID singleton

(mod
(
INNER_PUZZLE ; Standard P2 inner puzzle, used to record the ownership of the DID.
RECOVERY_DID_LIST_HASH ; the list of DIDs that can send messages to you for recovery we store only the hash so that we don't have to reveal every time we make a message spend
NUM_VERIFICATIONS_REQUIRED ; how many of the above list are required for a recovery
SINGLETON_STRUCT ; my singleton_struct, formerly a Truth - ((SINGLETON_MOD_HASH, (LAUNCHER_ID, LAUNCHER_PUZZLE_HASH)))
METADATA ; Customized metadata, e.g KYC info
mode ; this indicates which spend mode we want. 0. Recovery mode 1. Run INNER_PUZZLE with p2_solution
my_amount_or_inner_solution ; In mode 0, we use this to recover our coin and assert it is our actual amount
; In mode 1 this is the solution of the inner P2 puzzle, only required in the create message mode and transfer mode.
new_inner_puzhash ; In recovery mode, this will be the new wallet DID puzzle hash
parent_innerpuzhash_amounts_for_recovery_ids ; during a recovery we need extra information about our recovery list coins
pubkey ; this is the new pubkey used for a recovery
recovery_list_reveal ; this is the reveal of the stored list of DIDs approved for recovery
my_id ; my coin ID
)
;message is the new puzzle in the recovery and standard spend cases

;MOD_HASH, MY_PUBKEY, RECOVERY_DID_LIST_HASH are curried into the puzzle
;EXAMPLE SOLUTION (0xcafef00d 0x12341234 0x923bf9a7856b19d335a65f12d68957d497e1f0c16c0e14baf6d120e60753a1ce 2 1 100 (q "source code") 0xdeadbeef 0xcafef00d ((0xdadadada 0xdad5dad5 200) () (0xfafafafa 0xfaf5faf5 200)) 0xfadeddab (0x22222222 0x33333333 0x44444444))

(include condition_codes.clvm)
(include curry-and-treehash.clinc)

; takes a lisp tree and returns the hash of it
(defun sha256tree1 (TREE)
(if (l TREE)
(sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE)))
(sha256 1 TREE)
)
)

; recovery message module - gets values curried in to make the puzzle
(defun make_message_puzzle (recovering_coin newpuz pubkey)
(qq (q . (((unquote CREATE_COIN_ANNOUNCEMENT) (unquote recovering_coin)) ((unquote AGG_SIG_UNSAFE) (unquote pubkey) (unquote newpuz)))))
)

; this function creates the assert announcement for each message coin approving a recovery
(defun-inline create_consume_message (coin_id my_id new_innerpuz pubkey)
(list ASSERT_COIN_ANNOUNCEMENT (sha256 (sha256 coin_id (sha256tree1 (make_message_puzzle my_id new_innerpuz pubkey))) my_id))
)

; this function calculates a coin ID given the inner puzzle and singleton information
(defun create_coin_ID_for_recovery (SINGLETON_STRUCT launcher_id parent innerpuzhash amount)
(sha256 parent (calculate_full_puzzle_hash (c (f SINGLETON_STRUCT) (c launcher_id (r (r SINGLETON_STRUCT)))) innerpuzhash) amount)
)


; return the full puzzlehash for a singleton with the innerpuzzle curried in
; puzzle-hash-of-curried-function is imported from curry-and-treehash.clinc
(defun-inline calculate_full_puzzle_hash (SINGLETON_STRUCT inner_puzzle_hash)
(puzzle-hash-of-curried-function (f SINGLETON_STRUCT)
inner_puzzle_hash
(sha256tree1 SINGLETON_STRUCT)
)
)

; this loops over our identities to check list, and checks if we have been given parent information for this identity
; the reason for this is because we might only require 3/5 of the IDs give approval messages for a recovery
; if we have the information for an identity then we create a consume message using that information

(defun check_messages_from_identities (SINGLETON_STRUCT num_verifications_required identities my_id new_puz parent_innerpuzhash_amounts_for_recovery_ids pubkey num_verifications)
(if identities
(if (f parent_innerpuzhash_amounts_for_recovery_ids)
; if we have parent information then we should create a consume coin condition
(c
(create_consume_message
; create coin_id from DID
(create_coin_ID_for_recovery
SINGLETON_STRUCT
(f identities)
(f (f parent_innerpuzhash_amounts_for_recovery_ids))
(f (r (f parent_innerpuzhash_amounts_for_recovery_ids)))
(f (r (r (f parent_innerpuzhash_amounts_for_recovery_ids)))))
my_id
new_puz
pubkey
)
(check_messages_from_identities
SINGLETON_STRUCT
num_verifications_required
(r identities)
my_id
new_puz
(r parent_innerpuzhash_amounts_for_recovery_ids)
pubkey
(+ num_verifications 1)
)
)
; if no parent information found for this identity, move on to next in list
(check_messages_from_identities
SINGLETON_STRUCT
(r identities)
my_id
new_puz
(r parent_innerpuzhash_amounts_for_recovery_ids)
pubkey
num_verifications
)
)
;if we're out of identites to check for, check we have enough
(if (> num_verifications (- num_verifications_required 1))
(list (list AGG_SIG_UNSAFE pubkey new_puz) )
(x)
)
)
)

;Spend modes:
;0 = recovery
;1 = run the INNER_PUZZLE

;MAIN
(if mode
; mode 1 - run INNER_PUZZLE
(a INNER_PUZZLE my_amount_or_inner_solution)

; mode 0 - recovery
(if (all (= (sha256tree1 recovery_list_reveal) RECOVERY_DID_LIST_HASH) (> NUM_VERIFICATIONS_REQUIRED 0))
(c (list ASSERT_MY_AMOUNT my_amount_or_inner_solution)
(c (list CREATE_COIN new_inner_puzhash my_amount_or_inner_solution (list new_inner_puzhash))
(c (list ASSERT_MY_COIN_ID my_id)
(check_messages_from_identities SINGLETON_STRUCT NUM_VERIFICATIONS_REQUIRED recovery_list_reveal my_id new_inner_puzhash parent_innerpuzhash_amounts_for_recovery_ids pubkey 0)
)
)
)
(x)
)
)
)

Conclusion

DIDs are the next generation of cryptographic identification technology. They can be used with NFTs to validate the source and prevent fakes. They can also be used as a more recoverable form of authorization than keys.