-
Notifications
You must be signed in to change notification settings - Fork 82
/
merkle_key.rs
105 lines (80 loc) · 3.83 KB
/
merkle_key.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// Copyright 2020-2021 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
//! An example that revokes a key and shows how verification fails as a consequence.
//!
//! cargo run --example merkle_key
use rand::rngs::OsRng;
use rand::Rng;
use identity::core::ToJson;
use identity::credential::Credential;
use identity::crypto::merkle_key::Sha256;
use identity::crypto::merkle_tree::Proof;
use identity::crypto::KeyCollection;
use identity::crypto::PrivateKey;
use identity::crypto::PublicKey;
use identity::did::MethodScope;
use identity::iota::ClientMap;
use identity::iota::CredentialValidation;
use identity::iota::CredentialValidator;
use identity::iota::IotaDID;
use identity::iota::IotaVerificationMethod;
use identity::iota::Receipt;
use identity::prelude::*;
mod common;
mod create_did;
#[tokio::main]
async fn main() -> Result<()> {
// Create a client instance to send messages to the Tangle.
let client: ClientMap = ClientMap::new();
// Create a signed DID Document/KeyPair for the credential issuer (see create_did.rs).
let (mut issuer_doc, issuer_key, issuer_receipt): (IotaDocument, KeyPair, Receipt) = create_did::run().await?;
// Create a signed DID Document/KeyPair for the credential subject (see create_did.rs).
let (subject_doc, _, _): (IotaDocument, KeyPair, Receipt) = create_did::run().await?;
// Generate a Merkle Key Collection Verification Method with 8 keys (Must be a power of 2)
let keys: KeyCollection = KeyCollection::new_ed25519(8)?;
let method_did: IotaDID = issuer_doc.id().clone();
let method = IotaVerificationMethod::create_merkle_key::<Sha256, _>(method_did, &keys, "merkle-key")?;
// Add to the DID Document as a general-purpose verification method
issuer_doc.insert_method(MethodScope::VerificationMethod, method);
issuer_doc.set_previous_message_id(*issuer_receipt.message_id());
issuer_doc.sign(issuer_key.private())?;
// Publish the Identity to the IOTA Network and log the results.
// This may take a few seconds to complete proof-of-work.
let receipt: Receipt = client.publish_document(&issuer_doc).await?;
println!("Publish Receipt > {:#?}", receipt);
// Create an unsigned Credential with claims about `subject` specified by `issuer`.
let mut credential: Credential = common::issue_degree(&issuer_doc, &subject_doc)?;
// Select a random key from the collection
let index: usize = OsRng.gen_range(0..keys.len());
let public: &PublicKey = keys.public(index).unwrap();
let private: &PrivateKey = keys.private(index).unwrap();
// Generate an inclusion proof for the selected key
let proof: Proof<Sha256> = keys.merkle_proof(index).unwrap();
// Sign the Credential with the issuers private key
issuer_doc
.signer(private)
.method("merkle-key")
.merkle_key((public, &proof))
.sign(&mut credential)?;
println!("Credential JSON > {:#}", credential);
let credential_json: String = credential.to_json()?;
// Check the verifiable credential is valid
let validator: CredentialValidator<ClientMap> = CredentialValidator::new(&client);
let validation: CredentialValidation = validator.check(&credential_json).await?;
assert!(validation.verified);
println!("Credential Validation > {:#?}", validation);
// The Issuer would like to revoke the credential (and therefore revokes key at `index`)
issuer_doc
.try_resolve_mut("merkle-key")
.and_then(IotaVerificationMethod::try_from_mut)?
.revoke_merkle_key(index)?;
issuer_doc.set_previous_message_id(*receipt.message_id());
issuer_doc.sign(issuer_key.private())?;
let receipt: Receipt = client.publish_document(&issuer_doc).await?;
println!("Publish Receipt > {:#?}", receipt);
// Check the verifiable credential is revoked
let validation: CredentialValidation = validator.check(&credential_json).await?;
assert!(!validation.verified);
println!("Credential Validation > {:#?}", validation);
Ok(())
}