Skip to content

Instantly share code, notes, and snippets.

@javereec
Created March 8, 2022 07:19
Show Gist options
  • Save javereec/897bc4dc57c66eb311bfaff00fbf883b to your computer and use it in GitHub Desktop.
Save javereec/897bc4dc57c66eb311bfaff00fbf883b to your computer and use it in GitHub Desktop.
Ruby Verifiable Credential
# Instructions
# tested with ruby 3.1.1
# gem install ed25519
# gem install json-canonicalization
require 'base64'
require 'ed25519'
# require 'json/ext'
require 'json/canonicalization'
require 'openssl'
require 'securerandom'
require 'time'
module Proof
def create_proof
{
"type": "Ed25519Signature2018",
"created": Time.now.utc.iso8601,
"proofPurpose": "assertionMethod",
"verificationMethod": "https://example.com/jdoe/keys/1",
"verify_key": Base64.encode64(signing_key.verify_key.to_bytes)
}
end
def create_tbs(payload, proof_options)
hash_alg.digest(payload) + hash_alg.digest(proof_options)
end
def create_signature(payload, proof_options, key=signing_key)
tbs = create_tbs(payload, proof_options)
signature = key.sign(tbs)
Base64.encode64(signature)
end
def verify_signature?(payload)
proof_options = payload[:proof]
payload.delete(:proof)
signature = Base64.decode64(proof_options[:challenge])
proof_options.delete(:challenge)
key = Ed25519::VerifyKey.new(Base64.decode64(proof_options[:verify_key]))
tbs = create_tbs(payload.to_json_c14n, proof_options.to_json_c14n)
# puts payload.to_json_c14n
# puts proof_options.to_json_c14n
begin
key.verify(signature, tbs)
rescue Ed25519::VerifyError
false
end
# true
end
def signing_key
@_signing_key ||= Ed25519::SigningKey.generate
end
def hash_alg
@_hash_alg ||= OpenSSL::Digest::SHA256.new
end
end
class VerifiableCredential
include Proof
def build
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://vc-schemas.meeco.me/credentials/id/1.0/context"
],
"id": "uuid:of:vc",
"type": "VerifiableCredential",
"issuer": "did:example:CCnF3zFaXkPN4zB94XaomRdvw2zX3XHPVX3aExcgo6PV",
"issuanceDate": Time.now.utc.iso8601,
"credentialSubject": {
"id": "urn:uuid:#{SecureRandom.uuid}",
"type": "IdCredential",
"givenName": "Alice",
"familyName": "Miller",
},
}
end
def attach_proof(payload)
proof_options = create_proof
proof_options.merge!("challenge": create_signature(payload.to_json_c14n, proof_options.to_json_c14n))
# puts payload.to_json_c14n
# puts proof_options.to_json_c14n
payload.merge("proof": proof_options)
end
end
vc = VerifiableCredential.new
credential = vc.build
# puts credential
signed_credential = vc.attach_proof(credential)
# puts signed_credential
puts vc.verify_signature?(signed_credential)
# tamper
credential = vc.build
signed_credential = vc.attach_proof(credential)
# puts signed_credential
signed_credential[:credentialSubject][:givenName] = "Eve"
# puts signed_credential
puts vc.verify_signature?(signed_credential)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment