This library provides a set of tools for converting Verifiable Credentials (VCs) into Prolog facts and rules. This allows for expressive and powerful policy-based access control and other logic-based systems to be built on top of a verifiable data model.
The library takes a VC as input, validates it against the corresponding schema, and then converts it into a Prolog fact or rule. These facts and rules can then be asserted into a Prolog engine to build a knowledge base.
Here is the schema for a VC's credentialSubject for a person:
{
"title": "Person",
"type": "object",
"properties": {
"claimType": {
"type": "string",
"const": "person"
},
"id": { "type": "string", "description": "Person's ID" },
"updateView": {
"type": "string",
"enum": ["assert", "retract", "assertz", "asserta"],
"default": "assert"
}
},
"required": ["claimType", "id", "updateView"]
}So following that schema we can construct this VC:
{
"credentialSubject": {
"claimType": "person",
"id": "person1",
"updateView": "assert"
}
}And pass to the extractPrologStatement function which will return the following Prolog fact:
assert(person(person1)).Here is the schema for a VC's credentialSubject for a rule.
{
"title": "Rule Definition (Generalized Boolean Logic)",
"type": "object",
"properties": {
"claimType": {
"type": "string",
"const": "rule"
},
"name": { "type": "string" },
"evaluate": { "$ref": "#/$defs/logicNode" },
"variables": {
"type": "array",
"items": { "type": "string" }
},
"returns": { "enum": ["boolean"] },
"updateView": {
"type": "string",
"enum": ["assert", "retract"],
"default": "assert"
}
},
"required": [
"claimType",
"name",
"evaluate",
"variables",
"returns",
"updateView"
],
"$defs": {
"logicNode": {
"description": "A logical expression node (predicate or combinator)",
"type": "object",
"oneOf": [
{
"description": "A predicate (atomic condition)",
"properties": {
"predicate": { "type": "string" },
"args": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["predicate", "args"],
"additionalProperties": false
},
{
"description": "Logical AND combinator",
"properties": {
"and": {
"type": "array",
"items": { "$ref": "#/$defs/logicNode" },
"minItems": 1
}
},
"required": ["and"],
"additionalProperties": false
},
{
"description": "Logical OR combinator",
"properties": {
"or": {
"type": "array",
"items": { "$ref": "#/$defs/logicNode" },
"minItems": 1
}
},
"required": ["or"],
"additionalProperties": false
},
{
"description": "Logical NOT combinator",
"properties": {
"not": { "$ref": "#/$defs/logicNode" }
},
"required": ["not"],
"additionalProperties": false
}
]
}
}
}Which is a bit complicated but lets us chain and embed multiple rules with ANDs, ORs and NOTs.
So following that schema we can construct this VC:
{
"credentialSubject": {
"claimType": "rule",
"name": "my_rule",
"evaluate": {
"and": [
{ "predicate": "p", "args": ["a"] },
{ "predicate": "q", "args": ["b"] }
]
},
"variables": ["X"],
"returns": "boolean",
"updateView": "assert"
}
}And pass to the extractPrologStatement function which will return the following Prolog fact:
assert(my_rule(X) :- (p(a), q(b))).The library is built around a set of schemas that define the structure of the VCs. These schemas represent the core concepts of a system that could be built using this library. Below are the categories of statements that get constructed using the VCs that implement the corresponding schema.
- Person: Represents a user in the system.
assert(person(personId)).- Person Custom Property: Allows for adding arbitrary properties to a person.
assert(person_custom_property(person1, age, 30)).- Group: Represents a collection of people.
assert(group(exampleGroupId)).- Group Custom Property: Allows for adding arbitrary properties to a group.
assert(group_custom_property(group1, department, engineering)).- Entity Represents a more abstract entity.
assert(entity(entityId)).- Entity Custom Property: Allows for adding arbitrary properties to an entity.
assert(entity_custom_property(entityId, property, value)).- Entity Group: Reresents a collection of entities.
assert(entity_group(entityGroupId)).- Entity Group Custom Property: Allows for adding arbitrary properties to an entity group.
assert(entity_group_custom_property(entity_group_id, property, value)).These are pre-defined rules that provide relations between our existing entities.
- Person Belongs to Group: A relationship that links a person to a group.
assert(person_belongs_to_group(person1, group1))."- Resource Owned By Person: A relationship that indicates a person owns a resource.
assert(resource_owned_by_person(resource1, person1)).- Resource Shared With Person: A relationship that indicates a resource is shared with a person.
assert(resource_shared_with_person(sharer1, resource1, person1)).- Resource Shared With Group: A relationship that indicates a resource is shared with a group.
assert(resource_shared_with_group(sharer1, resource1, group1)).- Resource Contained In: A relationship that links a resource to a folder.
assert(resource_contained_in(resource1, folder1)).- Custom Relation: A relationship that links a resource to a folder.
assert(trust(person, resource)).- Entity Belongs to Entity Group
assert(entity_belongs_to_entity_group(entityID, entityGroupID)).- Resource: A generic entity that can be accessed.
assert(resource(resource1)).- File: A specific type of resource.
assert(file(resource1)).- Folder: A container for other resources.
assert(folder(resource1)).- Rule: Defines a custom rule using a JSON-based logic structure. Supports conjunction, disjunction and negation of other rules.
assert(my_rule(X) :- (p(a), q(b))).- Rule Custom: Defines a custom rule using raw Prolog.
assert(my_rule(X) :- a(X), b(X)).- Query: Represents a query to the Prolog system.
parent(john, mary).- Query Custom: Represents a custom query using raw Prolog.
parent(john, X).The claimType property in the credential subject of a VC is used to determine which schema to validate against and how to generate the Prolog statement. The possible values for claimType are defined by the ClaimType enum:
| Claim Type | Description |
|---|---|
person |
Represents a user in the system. |
person_custom_property |
A custom property for a person. |
| Claim Type | Description |
|---|---|
group |
Represents a group of people. |
group_custom_property |
A custom property for a group. |
| Claim Type | Description |
|---|---|
entity |
Represents a entity in the system. |
entity_custom_property |
A custom property for an entity. |
| Claim Type | Description |
|---|---|
person_belongs_to_group |
Links a person to a group. |
resource_owned_by_person |
Indicates a person owns a resource. |
resource_shared_with_group |
Indicates a resource is shared with a group. |
resource_shared_with_person |
Indicates a resource is shared with a person. |
resource_contained_in |
Links a resource to a folder. |
entity_belongs_to_entity_group |
Links an entity to an entity group. |
relation_custom |
A custom relationship. |
| Claim Type | Description |
|---|---|
resource |
A generic entity that can be accessed. |
file |
Labels a resource as a file. |
folder |
Labels a resource as a folder. |
| Claim Type | Description |
|---|---|
rule |
Defines a custom rule using a JSON-based logic structure. |
rule_custom |
Defines a custom rule using raw Prolog. |
| Claim Type | Description |
|---|---|
query |
Represents a query to the Prolog system. |
query_custom |
A custom query using raw Prolog. |
In a Node.js project, run npm i prolog-vc-tools.
The primary function of this library is extractPrologStatement, which takes a VC that conforms to a supported schema and returns a Prolog statement.
import { extractPrologStatement } from "prolog-vc-tools";
const vc = {
credentialSubject: {
claimType: "person",
id: "person1",
updateView: "assert",
},
};
const { fact, type } = extractPrologStatement(vc);
console.log(fact); // assert(person(person1)).You can also pass an updateView argument which will override any updateView set in the credentialSubject.
import { extractPrologStatement, UpdateView } from "prolog-vc-tools";
const vc = {
credentialSubject: {
claimType: "person",
id: "person1",
updateView: "assert",
},
};
const { fact, type } = extractPrologStatement(vc, UpdateView.Retract);
console.log(fact); // retract(person(person1)).The library also provides a function isStringValidTerm to check if a string is a valid Prolog term.
import { isStringValidTerm } from "prolog-vc-tools";
const isValid = await isStringValidTerm("person(person1).");
console.log(isValid); // trueAn application with multiple example implementations of systems using this library can be found here: policy-use-cases.
A demo application that implements this library can be found here: prolog-vc-tools-app.
Full schemas can be found here: GitHub.
Example VCs implementing those schemas can be found here: Github.