Part 3: Privledge

This is the final part of my blockchain series, continued from Part 2: Blockchain Present and Beyond

The details in this article are pulled directly from the project README. If you’re interested in the project, go there to get the latest information.

A 15:52 Video Demonstration is available on YouTube as well, and covers much of the content below:


Privledge Overview

Privledge is a proof of concept private permissioned distributed ledger used for public key management written in Python 3.5 and released under the MIT License.

Installation

Environment Recommendations

Privledge uses Python 3.5 so be sure to use the appropriate command for Python 3.5 pip

I recommend using a virtual environment with virtualenvwrapper and mkproject (documentation/installation):

$ mkproject -p python3.5 privledge

To enter and leave your virtual environment, use the commands workon and deactivate respectively:

$ workon privledge
(privledge) $ deactivate
$

Install from Github

(privledge) $ git clone [email protected]:elBradford/privledge.git .
(privledge) $ pip install -e .
(privledge) $ pls
Welcome to Privledge Shell...
> help

-e is an optional pip argument that allows you to modify the code and have the changes immediately applied to the installed script - no need to reinstall to see changes you made.

Tutorial

This project consists of two main components:

  • Privledge Daemon
  • Privledge Shell

Privledge Daemon

The daemon maintains the state, including the ledger, all known peers, and any communication threads needed to pass messages to peers.

Privledge Shell

The shell is your interface to the daemon. In the shell you can interact with the ledger, search for more peers, and more.

Getting Started

We enter the Privledge shell by the command pls after a successful installation:

(privledge) $ pls

Welcome to Privledge Shell...
>

Typing help within the shell will show all the available commands:

> help

Documented commands (type help <topic>):
========================================
block  discover  help  join  leave   quit   status
debug  exit      init  key   ledger  shell

Typing help <command name> will give specific help for that command:

> help key
Manage your local private key

        Arguments:
        gen: Generate a new RSA key
        pub (default): Prints the public key
        priv: Prints the private key
        
> 

Initializing a Ledger

We can initialize a ledger with the init command, followed by one of the following:

  • A base58 encoded RSA public key string
  • A path to a public key on the local filesystem
  • gen, which will generate a public/private RSA key pair. If you also provide a path, it will save the keys to the local filesystem.
> init gen

Public Key Hash: 08022ade6757177ad4e0395118cf638b0eabf562
Added key (08022ade6757177ad4e0395118cf638b0eabf562) as a new Root of Trust
root>

Joining a Ledger

If we would like to join an existing ledger, we use the discover command to search our local subnet for available ledgers, or discover <ip> to query a specific ip address:

> discover
Found 2 available ledgers
1 | 192.168.159.131: (1 members) 19991b9288c93cb41a6e042d040383763912fd03e0f6b5c717b42965c0b99a7e 
2 | 192.168.159.130: (1 members) 812858c1fd8fcb38cd8fa3f8c1040dae06714a78822818c3b7a48eb8b66ced16 
>

If we see a ledger we would like to join, we use the join command, followed by the number of the item provided by the list command:

> join 1
Joined ledger 19991b9288c93cb41a6e042d040383763912fd03e0f6b5c717b42965c0b99a7e
>

To see the status of our ledger, we can use the status command:

> status
You are a member of ledger 19991b9288c93cb41a6e042d040383763912fd03e0f6b5c717b42965c0b99a7e and connected to 1 peers.
>

status detail gives us more details about our ledger; the Root of Trust:

> status detail
You are a member of ledger 19991b9288c93cb41a6e042d040383763912fd03e0f6b5c717b42965c0b99a7e and connected to 1 peers.

Root of Trust:
		Type: key (root)
		Block Hash: d1a57995ecf02bed7c08b546702424ee2fd67a7654c48f2f2f22a7502033be81
		Message: 2TuPVgMCHJy5atawrsADEzjP7MCVbyyCA89UW6Wvjp9HrAsCWKC5L4c1xVjtShQ7
		Message Hash: 19991b9288c93cb41a6e042d040383763912fd03e0f6b5c717b42965c0b99a7e
		Signatory Hash: 19991b9288c93cb41a6e042d040383763912fd03e0f6b5c717b42965c0b99a7e (self-signed)
		Predecessor: None

> 

The init and join commands will join us to a ledger. If we would like to leave the ledger, leave will remove the ledger from our system and allow us to join another or generate our own:

> leave
Left ledger 19991b9288c93cb41a6e042d040383763912fd03e0f6b5c717b42965c0b99a7e
>

Adding Blocks to the Ledger

Only a block signed by a valid key will be accepted onto the ledger. If you are the node that initialized the ledger (with init), your private key is already automatically used to sign any new blocks.

The block command adds new blocks to the ledger and requires a blocktype (key|revoke|text) followed by a message. To add a new key, the command is

root> block key <base58-encoded public key>
Added new block to ledger:

		Type: key
		Block Hash: 1ddafda59d2a6a6be1c4796f1664244341b13fa1b8d2d8255afe316578463e59
		Message: <base58-encoded public key>
		Message Hash: c84e8341fd47b00911f49ae921a247a99603ca2a1f594234279a91892e16ac32
		Signatory Hash: ab8c88feeccf1f108111ae777fc24be76a4b1d2348f564ea2fadabc07f91b0b3
		Predecessor: 66d2e72288cc9299415aa0ee014f2accea3f63f054fbd2e1d7c87e0dfd0f9993

root> 

The revoke blocktype requires a public key and revokes it from the ledger. text blocks simply contain arbitrary text:

root> block text hello world!
Added new block to ledger:

		Type: text
		Block Hash: 66d2e72288cc9299415aa0ee014f2accea3f63f054fbd2e1d7c87e0dfd0f9993
		Message: hello world!
		Message Hash: 7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9
		Signatory Hash: ab8c88feeccf1f108111ae777fc24be76a4b1d2348f564ea2fadabc07f91b0b3
		Predecessor: f99e2442950afc5d43a076481510ddb9a9f647baac23f3cf5b2d501b6dd51aa7

root>

Generating a Key

If you need a quick and dirty way to generate an RSA key, key will do it for you.

> key gen
<new public key>
> 

The key gen command generates a public-private key pair and outputs the public portion to the console base58 encoded. You can then copy that and use it to add a new key to the ledger from a node with an authorized private key.

root> block key <new public key>
Added new block to ledger:

		Type: key
		Block Hash: 148e395adfd8f3dfe798572eb318c2514a91f255f77636b2dd33168c691c362a
		Message: <new public key>
		Message Hash: de2e233f919c09137f97a113a797cc69b99e34465e5b1d2ea25da6f6bbb09649
		Signatory Hash: d77bf92679bfa82207743a8790c9b266183d480b50c23d69cfd56e44ce20e0a7
		Predecessor: 1ddafda59d2a6a6be1c4796f1664244341b13fa1b8d2d8255afe316578463e59

root>

With our key added, we can now write to the ledger as well:

> block text I'm a trusted node!
Added new block to ledger:

		Type: text
		Block Hash: 3882d9cd33bb20c4d189c4f717164e1a97ad1d7008287ce3f50616c822a82fa6
		Message: I'm a trusted node!
		Message Hash: 676b9a62c5d772e0d428c2c08074920da49510a94b187bf164049c8ec3daec6f
		Signatory Hash: de2e233f919c09137f97a113a797cc69b99e34465e5b1d2ea25da6f6bbb09649
		Predecessor: 148e395adfd8f3dfe798572eb318c2514a91f255f77636b2dd33168c691c362a

>

Displaying the Ledger

Displaying the ledger is done with the ledger command

> ledger


13		Type: text
		Block Hash: 3882d9cd33bb20c4d189c4f717164e1a97ad1d7008287ce3f50616c822a82fa6
		Message: I'm a trusted node!
		Message Hash: 676b9a62c5d772e0d428c2c08074920da49510a94b187bf164049c8ec3daec6f
		Signatory Hash: de2e233f919c09137f97a113a797cc69b99e34465e5b1d2ea25da6f6bbb09649
		Predecessor: 148e395adfd8f3dfe798572eb318c2514a91f255f77636b2dd33168c691c362a


12		Type: key
		Block Hash: 148e395adfd8f3dfe798572eb318c2514a91f255f77636b2dd33168c691c362a
		Message: 2TuPVgMCHJy5atawrsADEzjP7MCVbyyCA89UW6Wvjp9HrAUjudRyQEGBjDpD5UH7
		Message Hash: de2e233f919c09137f97a113a797cc69b99e34465e5b1d2ea25da6f6bbb09649
		Signatory Hash: d77bf92679bfa82207743a8790c9b266183d480b50c23d69cfd56e44ce20e0a7
		Predecessor: 1ddafda59d2a6a6be1c4796f1664244341b13fa1b8d2d8255afe316578463e59


11		Type: key
		Block Hash: 1ddafda59d2a6a6be1c4796f1664244341b13fa1b8d2d8255afe316578463e59
		Message: 2TuPVgMCHJy5atawrsADEzjP7MCVbyyCA89UW6Wvjp9HrAibjYGr3FUsSLd5q8yu
		Message Hash: c84e8341fd47b00911f49ae921a247a99603ca2a1f594234279a91892e16ac32
		Signatory Hash: ab8c88feeccf1f108111ae777fc24be76a4b1d2348f564ea2fadabc07f91b0b3
		Predecessor: 66d2e72288cc9299415aa0ee014f2accea3f63f054fbd2e1d7c87e0dfd0f9993


		...10 hidden blocks...

r		Type: key (root)
		Block Hash: 6cbc660069f687426f36bb92a6a1bc8c564ca40f6aa7f81d11f7fa44730b09e2
		Message: 2TuPVgMCHJy5atawrsADEzjP7MCVbyyCA89UW6Wvjp9HrBtr9a3jck5CbJcZbSq1
		Message Hash: ab8c88feeccf1f108111ae777fc24be76a4b1d2348f564ea2fadabc07f91b0b3
		Signatory Hash: ab8c88feeccf1f108111ae777fc24be76a4b1d2348f564ea2fadabc07f91b0b3 (self-signed)
		Predecessor: None


>

You may display an arbitrary number of blocks by including a number after the command, such as

> ledger 1


13		Type: text
		Block Hash: 3882d9cd33bb20c4d189c4f717164e1a97ad1d7008287ce3f50616c822a82fa6
		Message: I'm a trusted node!
		Message Hash: 676b9a62c5d772e0d428c2c08074920da49510a94b187bf164049c8ec3daec6f
		Signatory Hash: de2e233f919c09137f97a113a797cc69b99e34465e5b1d2ea25da6f6bbb09649
		Predecessor: 148e395adfd8f3dfe798572eb318c2514a91f255f77636b2dd33168c691c362a


		...12 hidden blocks...

r		Type: key (root)
		Block Hash: 6cbc660069f687426f36bb92a6a1bc8c564ca40f6aa7f81d11f7fa44730b09e2
		Message: 2TuPVgMCHJy5atawrsADEzjP7MCVbyyCA89UW6Wvjp9HrBtr9a3jck5CbJcZbSq1
		Message Hash: ab8c88feeccf1f108111ae777fc24be76a4b1d2348f564ea2fadabc07f91b0b3
		Signatory Hash: ab8c88feeccf1f108111ae777fc24be76a4b1d2348f564ea2fadabc07f91b0b3 (self-signed)
		Predecessor: None


> 

The ledger command will always show the root of trust in addition to the specified number of blocks.

Nitty Gritty: Protocols

Privledge uses both TCP and UDP to communicate between peers. Once a ledger is established by the daemon, the daemon spawns a listener on port 2525 for each protocol:

UDP Listener

The UDP Listener listens for ledger queries and responds with a hash of the root of trust public key. This is the ledger id and serves to identify the ledger.

The UDP Listener also listens for heartbeat messages. Heartbeat messages contain a ledger id - if the heartbeat ledger id is the same as our ledger id we consider the source a peer and add them to the daemon peer list along with the current time.

In addition to keeping the peer list alive, these heartbeat messages help keep the ledger in sync. Each heartbeat contains the hash of the last block in the chain - if it matches our tail hash, we are in sync and do nothing. If it is in our ledger, the peer is out of sync and we do nothing. If it is not in our ledger we initiate a ledger sync, detailed below.

An additional thread, UDP Heartbeat, regularly loops through the list of peers and sends heartbeat messages. It also maintains the peer list by pruning away peers it hasn’t received a heartbeat from in some time.

TCP Listener

The TCP Listener accepts sockets and spawns threads that manage different message types. TCP messages are of the following types:

  • join : This message contains a block hash. If it matches the ledger id, the receiver will respond with the entire public key of the root of trust
  • ledger : This message contains a block hash. The receiver will respond with a list of blocks up to the specified block hash. If the block hash is null, the entire ledger will be transmitted. This message type allows for synchronization between nodes.
  • peers : This message is used to request the list of peers from the another peer. The receiver replies with a list of its peers.

To Be Implemented

As a proof of concept, this project is a work in progress. The following features are planned but have not yet been implemented:

  • System Integration: As a proof of concept, it should demonstrate how a system could utilize the ledger as a system access control list.

  • Privledge Levels: Demonstrate different uses for different privilege levels:

    • root
    • trusted
    • member