Merge pull request #37 from apache/develop

Preparing for 0.1.0 release
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..9baece7
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,3 @@
+.git/
+tagret/
+vendor/
diff --git a/.gitignore b/.gitignore
index e69de29..b2ed953 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1,3 @@
+target/
+vendor/
+libs/crypto/libpqnist/build/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..5854278
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,13 @@
+language: go
+go:
+  - "1.12.x"
+
+services:
+  - docker
+
+install:
+  - docker build -t milagro-test -f Dockerfile-alpine .
+  - docker run -d -p 127.0.0.1:5556:5556 --name milagro milagro-test
+
+script:
+  - docker ps | grep -q milagro
diff --git a/DISCLAIMER b/DISCLAIMER
new file mode 100644
index 0000000..36eb7cb
--- /dev/null
+++ b/DISCLAIMER
@@ -0,0 +1,10 @@
+Apache Milagro (incubating) is an effort undergoing incubation at the Apache Software
+Foundation (ASF), sponsored by the Apache Incubator PMC.
+
+Incubation is required of all newly accepted projects until a further review
+indicates that the infrastructure, communications, and decision making process
+have stabilized in a manner consistent with other successful ASF projects.
+
+While incubation status is not necessarily a reflection of the completeness
+or stability of the code, it does indicate that the project has yet to be
+fully endorsed by the ASF.
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..c58b656
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,104 @@
+FROM ubuntu:latest as libs_builder
+
+RUN apt-get update &&  apt-get install -y --no-install-recommends \
+    ca-certificates \
+    cmake \
+    g++ \
+    gcc \
+    git \
+    make \
+    libtool \
+    automake \
+    libssl-dev
+
+ENV BUILD_PATH=/tmp/milagro-dta-build
+ENV LIBRARY_PATH=$BUILD_PATH/lib
+ENV C_INCLUDE_PATH=$BUILD_PATH/include
+
+WORKDIR /root
+
+# Milagro Crypto C Library
+RUN echo Building Milagro Crypt C library && \
+	git clone https://github.com/apache/incubator-milagro-crypto-c.git && \
+	cd incubator-milagro-crypto-c && \
+    mkdir build && \
+    cd build && \
+    cmake \
+    -DCMAKE_BUILD_TYPE=Release \
+    -DBUILD_SHARED_LIBS=OFF \
+    -DAMCL_CHUNK=64 \
+    -DAMCL_CURVE="BLS381,SECP256K1" \
+    -DAMCL_RSA="" \
+    -DBUILD_PYTHON=OFF \
+    -DBUILD_BLS=ON \
+    -DBUILD_WCC=OFF \
+    -DBUILD_MPIN=OFF \
+    -DBUILD_X509=OFF \
+    -DCMAKE_C_FLAGS="-fPIC" \
+    -DCMAKE_INSTALL_PREFIX=$BUILD_PATH \
+    .. && \
+    make && make install 
+
+# LibOQS
+RUN echo Building LibOQS && \
+	git clone https://github.com/open-quantum-safe/liboqs.git && \
+	cd liboqs && \
+    git checkout 7cb03c3ce9182790c77e69cd21a6901e270781d6 && \
+    autoreconf -i && \
+    ./configure \
+    --prefix=$BUILD_PATH \
+    --disable-shared \
+    --disable-aes-ni \
+    --disable-kem-bike \
+    --disable-kem-frodokem \
+    --disable-kem-newhope \
+    --disable-kem-kyber \
+    --disable-sig-qtesla \
+    --disable-doxygen-doc && \
+    make -j && make install
+
+
+# Lib pqnist
+ADD libs/crypto/libpqnist pqnist/
+RUN mkdir -p pqnist/build && \
+	cd pqnist/build && \
+	cmake \
+	-DCMAKE_BUILD_TYPE=Release\
+	-DBUILD_SHARED_LIBS=OFF \
+    -DCMAKE_INSTALL_PREFIX=$BUILD_PATH \
+	.. && \
+	make && make install
+
+
+FROM golang:1.13 as go_builder
+
+ENV LIBS_PATH=/tmp/milagro-dta-build
+ENV LIBRARY_PATH=$LIBS_PATH/lib
+ENV C_INCLUDE_PATH=$LIBS_PATH/include
+ENV PROJECT_PATH=/src/github.com/apache/incubator-milagro-dta
+ENV CGO_LDFLAGS="-L $LIBRARY_PATH"
+ENV CGO_CPPFLAGS="-I $C_INCLUDE_PATH"
+
+COPY --from=libs_builder $LIBS_PATH $LIBS_PATH
+ADD . $PROJECT_PATH
+WORKDIR $PROJECT_PATH
+
+RUN CGO_ENABLED=1 \
+    GO111MODULES=on \
+    go build \
+      -ldflags '-w -linkmode external -extldflags "-static"' \
+      -o $GOPATH/bin/milagro \
+      github.com/apache/incubator-milagro-dta/cmd/service
+
+RUN $GOPATH/bin/milagro init
+
+FROM alpine as certs
+RUN apk add --no-cache ca-certificates
+
+
+FROM scratch
+COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
+COPY --from=go_builder /root/.milagro .milagro
+COPY --from=go_builder /go/bin/milagro /
+
+ENTRYPOINT ["/milagro", "daemon"]
diff --git a/Dockerfile-alpine b/Dockerfile-alpine
new file mode 100644
index 0000000..36a4243
--- /dev/null
+++ b/Dockerfile-alpine
@@ -0,0 +1,106 @@
+FROM golang:1.13-alpine as builder
+
+RUN apk update && apk add --no-cache \
+    ca-certificates \
+    cmake \
+    musl-dev \
+    g++ \
+    gcc \
+    git \
+    make \
+    libtool \
+    automake \
+    autoconf
+
+ENV BUILD_PATH=/tmp/milagro-dta-build
+ENV LIBRARY_PATH=$BUILD_PATH/lib:$BUILD_PATH/lib64
+ENV LD_LIBRARY_PATH=$LIBRARY_PATH
+ENV C_INCLUDE_PATH=$BUILD_PATH/include
+
+WORKDIR /root
+
+# Milagro Crypto C Library
+RUN echo Building Milagro Crypto C library && \
+	git clone https://github.com/apache/incubator-milagro-crypto-c.git && \
+	cd incubator-milagro-crypto-c && \
+    mkdir build && \
+    cd build && \
+    cmake \
+    -DCMAKE_BUILD_TYPE=Release \
+    -DBUILD_SHARED_LIBS=OFF \
+    -DAMCL_CHUNK=64 \
+    -DAMCL_CURVE="BLS381,SECP256K1" \
+    -DAMCL_RSA="" \
+    -DBUILD_PYTHON=OFF \
+    -DBUILD_BLS=ON \
+    -DBUILD_WCC=OFF \
+    -DBUILD_MPIN=OFF \
+    -DBUILD_X509=OFF \
+    -DWORD_SIZE=64 \
+    -DCMAKE_C_FLAGS="-fPIC" \
+    -DCMAKE_INSTALL_PREFIX=$BUILD_PATH \
+    .. && \
+    make && make install 
+
+# LibOQS
+RUN echo Building LibOQS && \
+	git clone https://github.com/open-quantum-safe/liboqs.git && \
+	cd liboqs && \
+    git checkout 7cb03c3ce9182790c77e69cd21a6901e270781d6 && \
+    autoreconf -i && \
+    ./configure \
+    --prefix=$BUILD_PATH \
+    --disable-shared \
+    --disable-aes-ni \
+    --disable-kem-bike \
+    --disable-kem-frodokem \
+    --disable-kem-newhope \
+    --disable-kem-kyber \
+    --disable-sig-qtesla \
+    --disable-doxygen-doc && \
+    make -j && make install
+
+
+# Lib pqnist
+ADD libs/crypto/libpqnist pqnist/
+RUN mkdir -p pqnist/build && \
+	cd pqnist/build && \
+	cmake \
+	-DCMAKE_BUILD_TYPE=Release\
+	-DBUILD_SHARED_LIBS=OFF \
+    -DCMAKE_INSTALL_PREFIX=$BUILD_PATH \
+	.. && \
+	make && make install
+
+
+RUN go get -u golang.org/x/lint/golint
+
+RUN echo Building Milagro DTA
+
+ENV PROJECT_PATH=/src/github.com/apache/incubator-milagro-dta
+ENV CGO_LDFLAGS="-L $LIBRARY_PATH"
+ENV CGO_CPPFLAGS="-I $C_INCLUDE_PATH"
+
+WORKDIR $PROJECT_PATH
+ADD . $PROJECT_PATH
+
+RUN GO111MODULES=on go mod vendor
+
+RUN ./lint.sh
+
+RUN CGO_ENABLED=1 \
+    go build \
+      -ldflags '-w -linkmode external -extldflags "-static"' \
+      -o $GOPATH/bin/milagro \
+      github.com/apache/incubator-milagro-dta/cmd/service
+
+RUN go test -cover `go list ./...`
+
+RUN $GOPATH/bin/milagro init
+
+FROM scratch
+COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
+COPY --from=builder /root/.milagro .milagro
+COPY --from=builder /go/bin/milagro /
+
+ENTRYPOINT ["/milagro", "daemon"]
diff --git a/LICENSE b/LICENSE
index 7a4a3ea..eb16d4c 100644
--- a/LICENSE
+++ b/LICENSE
@@ -187,7 +187,7 @@
       same "printed page" as the copyright notice for easier
       identification within third-party archives.
 
-   Copyright [yyyy] [name of copyright owner]
+   Copyright 2019 The Apache Software Foundation
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -199,4 +199,4 @@
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
-   limitations under the License.
\ No newline at end of file
+   limitations under the License.
diff --git a/README.md b/README.md
index f1d9ea8..0a0d543 100644
--- a/README.md
+++ b/README.md
@@ -1,57 +1,198 @@
-# Milagro-DTA
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+# Apache Milagro (Incubating) Decentralized Trust Authority
 ---
-[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://GitHub.com/Naereen/StrapDown.js/graphs/commit-activity)
+[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/apache/incubator-milagro-dta/graphs/commit-activity)
 
+The Apache Milagro (Incubating) Decentralized Trust Authority (D-TA) is a collaborative key management server. 
 
+The D-TA facilitates secure and auditable communication between people who to use key pairs (Principal) and service providers who can keep the secret keys safe (Master Fiduciary). It is written in Go and uses REST services based on the [GoKit microservices framework](https://gokit.io), it uses IPFS to create a shared immutable log of transactions and relies on Milagro-Crypto-C for it's crypto.
 
-Milagro Distributed Trust Authority creates an ecosystem in which service providers can issue and protect secrets. When a node is connected to the network it will discover service providers who are able to offer secure longterm storage of highly sensitive digital assets. 
-
-It is written in Go and uses Qredo's implmentation of the GoKit microservices framework: https://gokit.io/
+## Plugins
+The Milagro D-TA provides a basic set of services for creating identities for actors in the system, and passing encrypted communication between them but it assumes that different service providers will have their own "special sauce" for securely storing secret keys, so the vanilla services can be extended using a plugin framework. Two basic plugins are included in this release to give you an idea of how this can be done.
+1. **BitcoinPlugin**  Generates a Bitcoin address and reveals the corresponding secret key
+2. **SafeGuardSecret** Encrypts a string and decrypts it again
 
 ## Installation
+Below are instructions on how to build and run the Milagro D-TA either using Docker or as developments builds for Linux and Mac.
 
-The Milagro DTA has two major dependedncies
+These instructions will build the service with default settings including an embeded IPFS node connected to a private IPFS network and an embedded "Bolt" database. This will get you up and running quickly **but is not recommended for production use!**
 
-### Redis
+### Docker
+To see the Milagro D-TA in action you can run the Milagro D-TA in a docker container.  This is currently the preferred method to build and run the D-TA.  Tested on Ubuntu 19.04 and MacOS but should run in any Docker environment.
 
-Instructions
+#### Prerequisites
+[Docker](https://www.docker.com/)
 
-
-### IPFS
-
-Instructions
-
-export IPFS_PATH=$HOME/.ipfs-custody
-
-
-## Linux / MacOS
-
-Click here to download the binary
-
-To build the code
-
-Clone it and run 
-
+#### Build & Run on Docker
 ```
-$ go get ./..
+git clone https://github.com/apache/incubator-milagro-dta.git
+
+cd incubator-milagro-dta
+
+docker build -t mydta .
+
+docker run -p5556:5556 mydta
 ```
 
-## Integration
+### Build and run on development machine
+Tested on Ubuntu 19, MacOS 10.14 Mojave & Debian 10
 
-Milagro-DTA is designed to be used by any organisation that might have digital assets such as keys and tokens that need to be secured, its is designed to be integrated in your existing back-office systems via a simple REST api.[The specification of which can be seen here](/swagger)
+#### Install development Tools on Ubuntu/Debian
+```
+sudo apt-get update
+sudo apt-get install \
+     ca-certificates \
+     cmake \
+     g++ \
+     gcc \
+     git \
+     make \
+     libtool \
+     automake \
+     libssl-dev \
+     jq \
+     curl
+```
 
-## Developer Notes
+#### Install development Tools on MacOS
+```
+brew install \
+     cmake \
+     autoconf \
+     automake \
+     libtool 
+```
 
-If you would like further information about how to integrate or extend Milagro-DTA the docs can be found here [https://milagro.apache.org/docs/d-ta-overview/](https://milagro.apache.org/docs/d-ta-overview/)
+#### golang
 
-You may need to install protobufs
+Download and install [Golang](https://golang.org/dl/)
 
-If you change the portobufs definition run 
+#### liboqs
+
+[liboqs](https://github.com/open-quantum-safe/liboqs) is a C library for
+quantum-resistant cryptographic algorithms. It is a API level on top of the
+NIST round two submissions.
 
 ```
-$ protoc -I=. --go_out=. ./docs.proto
+git clone https://github.com/open-quantum-safe/liboqs.git
+cd liboqs
+git checkout 7cb03c3ce9182790c77e69cd21a6901e270781d6 
+autoreconf -i
+./configure --disable-shared --disable-aes-ni --disable-kem-bike --disable-kem-frodokem --disable-kem-newhope --disable-kem-kyber --disable-sig-qtesla 
+make clean
+make -j
+sudo make install
+```
+
+#### AMCL
+
+[AMCL](https://github.com/apache/incubator-milagro-crypto-c) is required
+
+Build and install the AMCL library
+
+```
+git clone https://github.com/apache/incubator-milagro-crypto-c.git
+cd incubator-milagro-crypto-c
+mkdir build
+cd build
+cmake -D CMAKE_BUILD_TYPE=Release -D BUILD_SHARED_LIBS=ON -D AMCL_CHUNK=64 -D AMCL_CURVE="BLS381,SECP256K1" -D AMCL_RSA="" -D BUILD_PYTHON=OFF -D BUILD_BLS=ON -D BUILD_WCC=OFF -D BUILD_MPIN=OFF -D BUILD_X509=OFF -D CMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_C_FLAGS="-fPIC" ..
+make
+make test
+sudo make install
+```
+
+#### pqnist
+
+```
+git clone https://github.com/apache/incubator-milagro-dta.git
+cd incubator-milagro-dta/libs/crypto/libpqnist
+mkdir build
+cd build
+cmake -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=ON ..
+make
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
+make test
+sudo make install
 ```
 
 
+#### Set the library path
+```
+export C_INCLUDE_PATH=$C_INCLUDE_PATH:/usr/local/lib
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
+```
+
+#### Build & Run Instructions
+```
+./build.sh
+```
+
+To run the service with default settings:
+
+```
+./target/milagro init
+./target/milagro daemon 
+```
 
 
+## Documentation
+
+You can find documentation for Milagro D-TA in the main [Milagro docs site](https://milagro.apache.org/) 
+
+This includes a quick start guide that will show you how to get Milagro D-TA to "do stuff"
+
+
+## Contributing
+
+ Key pairs are becoming central to our online lives, and keeping secret keys safe is a growing industry, we hope to create an ecosystem of custodial service providers who collaborate to make the Internet a safer place for everyone. We are keen to get contributions and feedback from anyone in this space. This is a brand new project so our development processes are still being figured out, but if you have suggestions, questions or wish to make contributions please go ahead raise an issue and someone on the team will get right on it.
+
+
+## Crypto Notice
+
+This distribution includes cryptographic software. The country in which you
+currently reside may have restrictions on the import, possession, use, and/or
+re-export to another country, of encryption software. BEFORE using any
+encryption software, please check your country's laws, regulations and
+policies concerning the import, possession, or use, and re-export of encryption
+software, to see if this is permitted. See <http://www.wassenaar.org/> for
+more information.
+
+The Apache Software Foundation has classified this software as Export Commodity
+Control Number (ECCN) 5D002, which includes information security software using
+or performing cryptographic functions with asymmetric algorithms. The form and
+manner of this Apache Software Foundation distribution makes it eligible for
+export under the "publicly available" Section 742.15(b) exemption (see the BIS
+Export Administration Regulations, Section 742.15(b)) for both object code and
+source code.
+
+
+## Disclaimer
+
+Apache Milagro is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.
+
+## Credits
+
+* Design and Concept... [Brian Spector](https://github.com/spector-in-london)
+* Core Algorithm and Services... [Chris Morris](https://github.com/fluidjax)
+* Framework and Refactoring... [Stanislav Mihaylov](https://github.com/smihaylov)
+* Crypto Genius... [Kealan McCusker](https://github.com/kealan)
+* Keeper of "The Apache Way"... [John McCane-Whitney](https://github.com/johnmcw)
+* Prototype and Cat Herding... [Howard Kitto](https://github.com/howardkitto)
\ No newline at end of file
diff --git a/build-static.sh b/build-static.sh
new file mode 100755
index 0000000..a65d659
--- /dev/null
+++ b/build-static.sh
@@ -0,0 +1,87 @@
+#! /bin/bash
+
+set -e
+
+apt-get update &&  apt-get install \
+    ca-certificates git g++ gcc curl \
+    make cmake automake libtool libssl-dev
+
+CURRENT_PATH=$(pwd)
+OUTPUT_PATH=$CURRENT_PATH/bin
+BUILD_PATH=`mktemp -d`
+LIB_SOURCE_PATH=$BUILD_PATH/src
+export LIBRARY_PATH=$BUILD_PATH/lib
+export C_INCLUDE_PATH=$BUILD_PATH/include
+export CGO_LDFLAGS="-L $LIBRARY_PATH"
+export CGO_CPPFLAGS="-I $C_INCLUDE_PATH"
+
+
+echo Building Milagro Crypt C library
+
+git clone https://github.com/apache/incubator-milagro-crypto-c.git $LIB_SOURCE_PATH/milagro-crypto-c
+cd $LIB_SOURCE_PATH/milagro-crypto-c
+git checkout 1.0.0
+mkdir build
+cd build
+cmake \
+  -DCMAKE_BUILD_TYPE=Release \
+  -DBUILD_SHARED_LIBS=OFF \
+  -DAMCL_CHUNK=64 \
+  -DAMCL_CURVE="BLS381,SECP256K1" \
+  -DAMCL_RSA="" \
+  -DBUILD_PYTHON=OFF \
+  -DBUILD_BLS=ON \
+  -DBUILD_WCC=OFF \
+  -DBUILD_MPIN=OFF \
+  -DBUILD_X509=OFF \
+  -DCMAKE_C_FLAGS="-fPIC" \
+  -DCMAKE_INSTALL_PREFIX=$BUILD_PATH ..
+make && make install 
+
+
+echo Building LibOQS
+
+git clone https://github.com/open-quantum-safe/liboqs.git $LIB_SOURCE_PATH/liboqs
+cd $LIB_SOURCE_PATH/liboqs
+git checkout 7cb03c3ce9182790c77e69cd21a6901e270781d6
+autoreconf -i
+./configure \
+  --prefix=$BUILD_PATH \
+  --disable-shared \
+  --disable-aes-ni \
+  --disable-kem-bike \
+  --disable-kem-frodokem \
+  --disable-kem-newhope \
+  --disable-kem-kyber \
+  --disable-sig-qtesla \
+  --disable-doxygen-doc
+make -j && make install
+
+
+echo Building pqnist
+
+mkdir -p $LIB_SOURCE_PATH/pqnist
+cd $LIB_SOURCE_PATH/pqnist
+cmake \
+  -DCMAKE_BUILD_TYPE=Release\
+  -DBUILD_SHARED_LIBS=OFF \
+  -DCMAKE_INSTALL_PREFIX=$BUILD_PATH \
+  $CURRENT_PATH/libs/crypto/libpqnist
+make && make install
+
+
+echo Downloading Go
+
+curl -o "$BUILD_PATH/go.tar.gz" "https://dl.google.com/go/go1.12.9.linux-amd64.tar.gz"
+cd $BUILD_PATH && tar xzvf go.tar.gz
+export GOROOT=$BUILD_PATH/go
+
+cd $CURRENT_PATH
+
+GO111MODULES=on \
+CGO_ENABLED=1 \
+$GOROOT/bin/go build -o target/out \
+  -ldflags '-w -linkmode external -extldflags "-static"' \
+  -o $OUTPUT_PATH/milagro \
+  github.com/apache/incubator-milagro-dta/cmd/service
+
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..cf4e7a3
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,5 @@
+set -e
+
+GO111MODULE=on go build -o target/milagro github.com/apache/incubator-milagro-dta/cmd/service
+
+target/milagro $@ 
diff --git a/cmd/service/commands.go b/cmd/service/commands.go
new file mode 100644
index 0000000..2f9167e
--- /dev/null
+++ b/cmd/service/commands.go
@@ -0,0 +1,86 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package main
+
+import (
+	"flag"
+	"os"
+	"path/filepath"
+
+	"github.com/apache/incubator-milagro-dta/pkg/config"
+)
+
+const (
+	envMilagroHome      = "MILAGRO_HOME"
+	milagroConfigFolder = ".milagro"
+
+	cmdInit   = "init"
+	cmdDaemon = "daemon"
+)
+
+func configFolder() string {
+	userHome, err := os.UserHomeDir()
+	if err != nil {
+		userHome = ""
+	}
+
+	return getEnv(envMilagroHome, filepath.Join(userHome, milagroConfigFolder))
+}
+
+func getEnv(name, defaultValue string) string {
+	v, ok := os.LookupEnv(name)
+	if !ok {
+		return defaultValue
+	}
+
+	return v
+}
+
+func parseCommand() (cmd string, args []string) {
+	if len(os.Args) < 2 {
+		return
+	}
+	return os.Args[1], os.Args[2:]
+}
+
+func printHelp() string {
+	return `Milagro DTA
+USAGE
+	milagro <command> [options]
+	
+COMMANDS
+	init	Initialize configuration
+	daemon	Starts the milagro daemon
+	`
+}
+
+func parseConfig(args []string) (*config.Config, error) {
+	cfg, err := config.ParseConfig(configFolder())
+	if err != nil {
+		return nil, err
+	}
+
+	fs := flag.NewFlagSet("daemon", flag.ExitOnError)
+	fs.StringVar(&(cfg.Plugins.Service), "service", cfg.Plugins.Service, "Service plugin")
+
+	if err := fs.Parse(args); err != nil {
+		return nil, err
+	}
+
+	return cfg, nil
+}
diff --git a/cmd/service/initnode.go b/cmd/service/initnode.go
new file mode 100644
index 0000000..2760e51
--- /dev/null
+++ b/cmd/service/initnode.go
@@ -0,0 +1,165 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package main
+
+import (
+	"bufio"
+	"crypto/rand"
+	"encoding/hex"
+	"errors"
+	"flag"
+	"fmt"
+	"os"
+	"strings"
+
+	"github.com/apache/incubator-milagro-dta/libs/datastore"
+	"github.com/apache/incubator-milagro-dta/libs/documents"
+	"github.com/apache/incubator-milagro-dta/libs/ipfs"
+	"github.com/apache/incubator-milagro-dta/libs/logger"
+	"github.com/apache/incubator-milagro-dta/pkg/api"
+	"github.com/apache/incubator-milagro-dta/pkg/common"
+	"github.com/apache/incubator-milagro-dta/pkg/service"
+)
+
+type initOptions struct {
+	NodeName             string
+	MasterFidNodeID      string
+	MasterFidNodeAddress string
+	ServicePlugin        string
+	Interactive          bool
+}
+
+func parseInitOptions(args []string) (*initOptions, error) {
+	i := &initOptions{}
+
+	var masterFidNode string
+
+	fs := flag.NewFlagSet("init", flag.ExitOnError)
+	fs.StringVar(&i.NodeName, "nodename", "", "Node name")
+	fs.StringVar(&masterFidNode, "masterfiduciarynode", "", "Master fiduciary node")
+	fs.StringVar(&i.ServicePlugin, "service", "milagro", "Service plugin")
+	fs.BoolVar(&i.Interactive, "interactive", false, "Interactive setup")
+
+	if err := fs.Parse(args); err != nil {
+		return nil, err
+	}
+
+	if masterFidNode != "" {
+		spl := strings.Split(masterFidNode, ",")
+		if len(spl) != 2 {
+			return nil, errors.New("Invalid master fiduciary node format")
+		}
+		i.MasterFidNodeID = strings.TrimSpace(spl[0])
+		i.MasterFidNodeAddress = strings.TrimSpace(spl[1])
+	}
+
+	return i, nil
+
+}
+
+func cliInput(text string) (val string, err error) {
+	reader := bufio.NewReader(os.Stdin)
+
+	fmt.Print(text + ": ")
+	val, err = reader.ReadString('\n')
+	val = strings.TrimSpace(val)
+	return
+}
+
+func interactiveSetup(i *initOptions) error {
+	var err error
+	i.NodeName, err = cliInput("What is your node name?. Leave blank to generate a random name")
+	if err != nil {
+		return err
+	}
+	i.MasterFidNodeID, err = cliInput("What is your Master Fiduciary DTA’s node name? Leave blank to use this DTA as the Master Fiduciary")
+	if err != nil {
+		return err
+	}
+	if i.MasterFidNodeID != "" {
+		i.MasterFidNodeAddress, err = cliInput("What is your Master Fiduciary DTA’s address?")
+		if err != nil {
+			return err
+		}
+	}
+
+	plugin, err := cliInput("What plugin do you want to install? (B)itcoin wallet address generator or (S)afeguard secret. Leave blank for no plugin")
+	if err != nil {
+		return err
+	}
+
+	switch strings.ToLower(plugin) {
+	case "b", "bitcoinwallet":
+		i.ServicePlugin = "bitcoinwallet"
+	case "s", "safeguardsecret":
+		i.ServicePlugin = "safeguardsecret"
+	default:
+		i.ServicePlugin = "milagro"
+	}
+
+	return nil
+}
+
+//checkForID - Setup a NodeID if not supplied in the config
+func checkForID(logger *logger.Logger, optNodeID, optNodeName string, ipfs ipfs.Connector, store *datastore.Store, service service.Service) (nodeID string, err error) {
+	if optNodeID != "" {
+		var idSecrets = &common.IdentitySecrets{}
+		if err := store.Get("id-doc", optNodeID, idSecrets); err == nil {
+			id := &documents.IDDoc{}
+			rawDocI, err := ipfs.Get(optNodeID)
+			if err == nil {
+				if err := documents.DecodeIDDocument(rawDocI, optNodeID, id); err != nil {
+					logger.Error("Invalid ID document")
+					return "", err
+				}
+				return optNodeID, nil
+			}
+			logger.Error("ID not found in IPFS: %v", optNodeID)
+		} else {
+			logger.Error("ID not found in the database: %v", optNodeID)
+		}
+	} else {
+		logger.Error("No ID found in flags or config")
+	}
+
+	if optNodeName == "" {
+		return "", errors.New("Please provide Node name")
+	}
+
+	return createNewID(optNodeName, service)
+}
+
+func createNewID(name string, service service.Service) (newID string, err error) {
+
+	req := &api.CreateIdentityRequest{
+		Name: strings.TrimSpace(name),
+	}
+
+	resp, err := service.CreateIdentity(req)
+	if err != nil {
+		return "", err
+	}
+	return resp.IDDocumentCID, nil
+}
+
+func generateRandomName() string {
+	b := make([]byte, 8)
+	rand.Read(b)
+
+	return hex.EncodeToString(b)
+}
diff --git a/cmd/service/main.go b/cmd/service/main.go
new file mode 100644
index 0000000..e788374
--- /dev/null
+++ b/cmd/service/main.go
@@ -0,0 +1,295 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package main - handles config, initialisation and starts the service daemon
+*/
+package main
+
+import (
+	"crypto/rand"
+	"fmt"
+	"net/http"
+	"os"
+	"os/signal"
+	"path/filepath"
+	"strings"
+	"syscall"
+
+	"github.com/apache/incubator-milagro-dta/libs/datastore"
+	"github.com/apache/incubator-milagro-dta/libs/ipfs"
+	"github.com/apache/incubator-milagro-dta/libs/logger"
+	"github.com/apache/incubator-milagro-dta/libs/transport"
+	"github.com/apache/incubator-milagro-dta/pkg/api"
+	"github.com/apache/incubator-milagro-dta/pkg/config"
+	"github.com/apache/incubator-milagro-dta/pkg/endpoints"
+	"github.com/apache/incubator-milagro-dta/plugins"
+	"github.com/go-kit/kit/metrics/prometheus"
+	"github.com/pkg/errors"
+	stdprometheus "github.com/prometheus/client_golang/prometheus"
+	"github.com/prometheus/client_golang/prometheus/promhttp"
+)
+
+func initConfig(args []string) error {
+	cfg := config.DefaultConfig()
+	logger, err := logger.NewLogger("text", "info")
+	if err != nil {
+		return err
+	}
+
+	initOptions, err := parseInitOptions(args)
+	if err != nil {
+		return err
+	}
+
+	if initOptions.Interactive {
+		if err := interactiveSetup(initOptions); err != nil {
+			return err
+		}
+	}
+
+	if initOptions.NodeName != "" {
+		cfg.Node.NodeName = initOptions.NodeName
+	} else {
+		cfg.Node.NodeName = generateRandomName()
+		logger.Info("Node name not provided. Generated random name: %s", cfg.Node.NodeName)
+	}
+	cfg.Plugins.Service = initOptions.ServicePlugin
+
+	// Init the config folder
+	config.Init(configFolder(), cfg)
+
+	store, err := initDataStore(cfg.Node.Datastore)
+	if err != nil {
+		return errors.Wrap(err, "init datastore")
+	}
+
+	logger.Info("IPFS connector type: %s", cfg.IPFS.Connector)
+	var ipfsConnector ipfs.Connector
+	switch cfg.IPFS.Connector {
+	case "api":
+		ipfsConnector, err = ipfs.NewAPIConnector(ipfs.NodeAddr(cfg.IPFS.APIAddress))
+	case "embedded":
+		ipfsConnector, err = ipfs.NewNodeConnector(
+			ipfs.AddLocalAddress(cfg.IPFS.ListenAddress),
+			ipfs.AddBootstrapPeer(cfg.IPFS.Bootstrap...),
+			ipfs.WithLevelDatastore(filepath.Join(configFolder(), "ipfs-data")),
+		)
+	}
+	if err != nil {
+		return errors.Wrap(err, "init IPFS connector")
+	}
+
+	svcPlugin := plugins.FindServicePlugin(cfg.Plugins.Service)
+	if svcPlugin == nil {
+		return errors.Errorf("Invalid service plugin: %v", initOptions.ServicePlugin)
+	}
+
+	if err := svcPlugin.Init(svcPlugin, logger, rand.Reader, store, ipfsConnector, nil, cfg); err != nil {
+		return errors.Errorf("init service plugin %s", cfg.Plugins.Service)
+	}
+
+	newID, err := createNewID(cfg.Node.NodeName, svcPlugin)
+	if err != nil {
+		return err
+	}
+
+	cfg.Node.NodeID = newID
+	if initOptions.MasterFidNodeID != "" {
+		cfg.Node.MasterFiduciaryNodeID = initOptions.MasterFidNodeID
+	} else {
+		cfg.Node.MasterFiduciaryNodeID = newID
+	}
+
+	if initOptions.MasterFidNodeAddress != "" {
+		cfg.Node.MasterFiduciaryServer = initOptions.MasterFidNodeAddress
+	}
+
+	if cfg.Node.MasterFiduciaryNodeID == "" {
+		cfg.Node.MasterFiduciaryNodeID = newID
+	}
+
+	if cfg.Node.NodeType == "" {
+		cfg.Node.NodeType = "multi"
+	}
+
+	return config.SaveConfig(configFolder(), cfg)
+}
+
+func startDaemon(args []string) error {
+	cfg, err := parseConfig(args)
+	if err != nil {
+		return err
+	}
+
+	logger, err := logger.NewLogger(
+		cfg.Log.Format,
+		cfg.Log.Level,
+	)
+
+	if err != nil {
+		return errors.Wrap(err, "init logger")
+	}
+
+	// Create KV store
+	logger.Info("Datastore type: %s", cfg.Node.Datastore)
+	store, err := initDataStore(cfg.Node.Datastore)
+	if err != nil {
+		return errors.Wrap(err, "init datastore")
+	}
+
+	logger.Info("IPFS connector type: %s", cfg.IPFS.Connector)
+	var ipfsConnector ipfs.Connector
+	switch cfg.IPFS.Connector {
+	case "api":
+		ipfsConnector, err = ipfs.NewAPIConnector(ipfs.NodeAddr(cfg.IPFS.APIAddress))
+	case "embedded":
+		ipfsConnector, err = ipfs.NewNodeConnector(
+			ipfs.AddLocalAddress(cfg.IPFS.ListenAddress),
+			ipfs.AddBootstrapPeer(cfg.IPFS.Bootstrap...),
+			ipfs.WithLevelDatastore(filepath.Join(configFolder(), "ipfs-data")),
+		)
+	}
+	if err != nil {
+		return errors.Wrap(err, "init IPFS connector")
+	}
+
+	// Setup Endpoint authorizer
+	var authorizer transport.Authorizer
+	switch cfg.HTTP.OIDCProvider {
+	case "":
+		authorizer = &transport.EmptyAuthorizer{}
+	case "local":
+		authorizer = &transport.LocalAuthorizer{}
+	default:
+		authorizer, err = transport.NewOIDCAuthorizer(
+			cfg.HTTP.OIDCClientID,
+			cfg.HTTP.OIDCProvider,
+		)
+		if err != nil {
+			return errors.Wrap(err, "init authorizer")
+		}
+	}
+
+	masterFiduciaryServer, err := api.NewHTTPClient(cfg.Node.MasterFiduciaryServer, logger)
+	if err != nil {
+		return errors.Wrap(err, "init custody client")
+	}
+
+	//The Server must have a valid ID before starting up
+	svcPlugin := plugins.FindServicePlugin(cfg.Plugins.Service)
+	if svcPlugin == nil {
+		return errors.Errorf("invalid plugin: %v", cfg.Plugins.Service)
+	}
+
+	if err := svcPlugin.Init(svcPlugin, logger, rand.Reader, store, ipfsConnector, masterFiduciaryServer, cfg); err != nil {
+		return errors.Errorf("init service plugin %s", cfg.Plugins.Service)
+	}
+	logger.Info("Service plugin loaded: %s", svcPlugin.Name())
+
+	nodeID, err := checkForID(logger, cfg.Node.NodeID, cfg.Node.NodeName, ipfsConnector, store, svcPlugin)
+	if err != nil {
+		return err
+	}
+
+	if nodeID != cfg.Node.NodeID {
+		cfg.Node.NodeID = nodeID
+		if err := config.SaveConfig(configFolder(), cfg); err != nil {
+			return errors.Wrap(err, "cannot update config")
+		}
+	}
+
+	svcPlugin.SetMasterFiduciaryNodeID(cfg.Node.MasterFiduciaryNodeID)
+	svcPlugin.SetNodeID(nodeID)
+
+	// Create metrics
+	duration := prometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
+		Namespace: "milagro",
+		Subsystem: "milagroservice",
+		Name:      "request_duration_seconds",
+		Help:      "Request duration in seconds.",
+	}, []string{"method", "success"})
+
+	// Stop chan
+	errChan := make(chan error)
+
+	logger.Info("NODE ID (IPFS):  %v", svcPlugin.NodeID())
+	logger.Info("Node Type: %v", strings.ToLower(cfg.Node.NodeType))
+	endpoints := endpoints.Endpoints(svcPlugin, cfg.HTTP.CorsAllow, authorizer, logger, cfg.Node.NodeType)
+	httpHandler := transport.NewHTTPHandler(endpoints, logger, duration)
+	// Start the application http server
+	go func() {
+		logger.Info("starting listener on %v, custody server %v", cfg.HTTP.ListenAddr, cfg.Node.MasterFiduciaryServer)
+		// httpHandler.PathPrefix("/api/").Handler(http.St:ripPrefix("/api/", http.FileServer(http.Dir("./swagger"))))
+		errChan <- http.ListenAndServe(cfg.HTTP.ListenAddr, httpHandler)
+	}()
+
+	if cfg.HTTP.MetricsAddr != "" {
+		http.DefaultServeMux.Handle("/metrics", promhttp.Handler())
+		// Start the debug and metrics http server
+		go func() {
+			logger.Info("starting metrics listener on %v", cfg.HTTP.MetricsAddr)
+			errChan <- http.ListenAndServe(cfg.HTTP.MetricsAddr, http.DefaultServeMux)
+		}()
+	}
+
+	// Start the signal handler
+	go func() {
+		c := make(chan os.Signal, 1)
+		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
+		errChan <- errors.Errorf("received signal %s", <-c)
+	}()
+
+	stopErr := <-errChan
+	_ = logger.Log("exit", stopErr.Error())
+	return store.Close()
+}
+
+func initDataStore(ds string) (*datastore.Store, error) {
+	var dsBackend datastore.Backend
+	var err error
+	switch ds {
+	case "embedded":
+		dsBackend, err = datastore.NewBoltBackend(filepath.Join(configFolder(), "datastore.dat"))
+	default:
+		return nil, errors.Errorf("invalid datastore: %s", ds)
+	}
+	if err != nil {
+		return nil, err
+	}
+
+	store, err := datastore.NewStore(datastore.WithBackend(dsBackend), datastore.WithCodec(datastore.NewGOBCodec()))
+	return store, err
+}
+
+func main() {
+	var err error
+	cmd, args := parseCommand()
+	switch cmd {
+	default:
+		fmt.Println(printHelp())
+	case cmdInit:
+		err = initConfig(args)
+	case cmdDaemon:
+		err = startDaemon(args)
+	}
+
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+}
diff --git a/cmd/servicetester/e2e_test.sh b/cmd/servicetester/e2e_test.sh
new file mode 100755
index 0000000..8ed21f3
--- /dev/null
+++ b/cmd/servicetester/e2e_test.sh
@@ -0,0 +1,244 @@
+#!/bin/bash
+#End to End Test of Services using curl/bash
+
+apiVersion="v1"
+defaultURL="http://localhost:5556"
+apiURL="${1:-$defaultURL}"
+
+
+status () {
+  #Determine if an extension is running
+  statusOutput=$(curl -s -X GET "$apiURL/$apiVersion/status" -H "accept: */*" -H "Content-Type: application/json")
+  identity=$(echo $statusOutput | jq .nodeCID)
+  extensionVendor=$(echo $statusOutput | jq -r .extensionVendor)
+  plugin=$(echo $statusOutput | jq -r .plugin)
+  echo "Plugin $plugin"
+
+  if [ -z "${extensionVendor}" ]; then
+      echo "Server Not Running"
+      exit 1
+  fi
+}
+
+###############################################################################################################################
+
+execute_bitcoin () {
+  # #Run 4 Tests against the Bitcoin Extension
+  echo "Bitcoin Plugin Tests [4 Tests]"
+  output1=$(curl -s -X POST "$apiURL/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":\"\",\"extension\":{\"coin\":\"0\"}}")
+  #echo $output1
+  op1=$(echo $output1 | jq .orderReference)
+  commitment1=$(echo $output1 | jq .commitment)
+  address1=$(echo $output1 | jq .extension.address)
+  output2=$(curl -s -X POST "$apiURL/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op1,\"beneficiaryIDDocumentCID\":$identity}")
+  address2=$(echo $output2 | jq .extension.address)
+  commitment2=$(echo $output2 | jq .commitment)
+
+  echo "Committment1 $commitment1 $address1"
+  echo "Committment2 $commitment2 $address2"
+
+  if [ -z $commitment2 ]; then
+      echo "Failed Commitment is empty"
+      exit 1
+  fi
+
+  if [ $commitment1 == $commitment2 ]; then
+    echo "Pass - Id, Order & OrderSecret(Beneficiary)"
+  else
+    echo "Fail"
+    exit 1
+  fi
+
+  output3=$(curl -s -X POST "$apiURL/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":$identity,\"extension\":{\"coin\":\"0\"}}")
+
+  op3=$(echo $output3 | jq .orderReference)
+  commitment3=$(echo $output3 | jq .commitment)
+  address3=$(echo $output3 | jq .extension.address)
+  output4=$(curl -s -X POST "$apiURL/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op3}")
+  commitment4=$(echo $output4 | jq .commitment)
+  address4=$(echo $output4 | jq .extension.address)
+  orderReference=$(echo $output4 | jq .orderReference)
+  orderIndex=1
+
+  echo "Committment3 $commitment3 $address3"
+  echo "Committment4 $commitment4 $address4"
+
+  if [ -z $commitment4 ]; then
+      echo "Failed Commitment is empty"
+      exit 1
+  fi
+
+  if [ $commitment3 == $commitment4 ]; then
+    echo "Pass - Id, Order(Beneficiary) & OrderSecret"
+  else
+      echo "Fail"
+      exit 1
+  fi
+
+
+   #make another BeneficiaryID
+   output5=$(curl -s -X POST "http://localhost:5556/$apiVersion/identity" -H "accept: */*" -H       "Content-Type: application/json" -d "{\"Name\":\"AA\"}")
+   benid=$(echo $output5 | jq -r .idDocumentCID)
+
+
+
+   #Tests against the Bitcoin Extension - different befificary
+   output6=$(curl -s -X POST "http://localhost:5556/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":\"\",\"extension\":{\"coin\":\"0\"}}")
+   #echo $output6
+   op6=$(echo $output6 | jq .orderReference)
+   commitment6=$(echo $output6 | jq .commitment)
+   address6=$(echo $output6 | jq .extension.address)
+
+   output7=$(curl -s -X POST "http://localhost:5556/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op6,\"beneficiaryIDDocumentCID\":\"$benid\"}")
+   address7=$(echo $output7 | jq .extension.address)
+   commitment7=$(echo $output7 | jq .commitment)
+
+   echo "Committment5 $commitment6 $address6"
+   echo "Committment6 $commitment7 $address7"
+
+   if [ -z $commitment7 ]; then
+       echo "Failed Commitment is empty"
+       exit 1
+   fi
+
+   if [ $commitment6 == $commitment7 ]; then
+     echo "Pass - Id, Order & OrderSecret(Beneficiary)"
+   else
+     echo "Fail"
+     exit 1
+   fi
+
+  output8=$(curl -s -X POST "http://localhost:5556/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":\"$benid\",\"extension\":{\"coin\":\"0\"}}")
+  op8=$(echo $output8 | jq .orderReference)
+  commitment8=$(echo $output8 | jq .commitment)
+  address8=$(echo $output8 | jq .extension.address)
+
+
+  output9=$(curl -s -X POST "http://localhost:5556/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op8}")
+  commitment9=$(echo $output9 | jq .commitment)
+  address9=$(echo $output9 | jq .extension.address)
+  orderReference=$(echo $output9 | jq .orderReference)
+  orderIndex=1
+
+  echo "Committment7 $commitment8 $address8"
+  echo "Committment8 $commitment9 $address9"
+
+  if [ -z $commitment9 ]; then
+      echo "Failed Commitment is empty"
+      exit 1
+  fi
+
+  if [ $commitment8 == $commitment9 ]; then
+    echo "Pass - Id, Order(Beneficiary) & OrderSecret"
+  else
+      echo "Fail"
+      exit 1
+  fi
+
+}
+
+
+###############################################################################################################################
+
+execute_safeguardsecret () {
+  inputString="This is some random test text 1234567890!"
+  echo "Encrypt a String [1 Test]"
+  echo $output1
+  output1=$(curl -s -X POST "$apiURL/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":$identity,\"extension\":{\"plainText\":\"$inputString\"}}")
+  echo $output1
+  op1=$(echo $output1 | jq .orderReference)
+  cipherText=$(echo $output1 | jq .extension.cypherText)
+  tvalue=$(echo $output1 | jq .extension.t)
+  vvalue=$(echo $output1 | jq .extension.v)
+  commitment1=$(echo $output1 | jq .commitment)
+  output2=$(curl -s -X POST "$apiURL/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op1,\"beneficiaryIDDocumentCID\":$identity,\"extension\":{\"cypherText\":$cipherText,\"t\":$tvalue,\"v\":$vvalue}}")
+  result=$(echo $output2 | jq -r .extension.plainText)
+
+  orderReference=$(echo $output2 | jq .orderReference)
+  orderIndex=0
+
+
+  if [ "$inputString" == "$result" ]; then
+    echo "Pass"
+  else
+    echo "Fail"
+    exit 1
+  fi
+}
+
+# #############################################################################
+
+
+execute_milagro () {
+  echo "Milagro Tests [1 Test]"
+  output1=$(curl -s -X POST "$apiURL/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":$identity}")
+  echo $output1
+  op1=$(echo $output1 | jq .orderReference)
+
+
+  commitment1=$(echo $output1 | jq .commitment)
+  output2=$(curl -s -X POST "$apiURL/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op1,\"beneficiaryIDDocumentCID\":$identity}")
+  commitment2=$(echo $output2 | jq .commitment)
+
+  orderReference=$(echo $output2 | jq .orderReference)
+  orderIndex=0
+
+
+  echo "Committment1 $commitment1"
+  echo "Committment2 $commitment2"
+
+  if [ -z $commitment2 ]; then
+      echo "Failed Commitment is empty"
+      exit 1
+  fi
+
+  if [ $commitment1 == $commitment2 ]; then
+    echo "Order Create/Retrieve Pass"
+  else
+    echo "Order Create/Retrieve Fail"
+    exit 1
+  fi
+}
+
+
+
+
+
+
+# #############################################################################
+
+execute_orderlist () {
+  echo "Milagro Tests [1 Test]"
+  commitment2=$(echo $output2 | jq .commitment)
+  outputList=$(curl -s -X GET "$apiURL/$apiVersion/order?page=0&perPage=2&sortBy=dateCreatedDsc" -H "accept: */*")
+  orderReference=$(echo $outputList | jq -r ".orderReference | .[$orderIndex]")
+  outputOrder=$(curl -s -X GET "$apiURL/$apiVersion/order/$orderReference" -H "accept: */*")
+
+  #A simple smoke test to ensure some sort of order is returned
+  hasSecret=`echo $outputOrder | grep "Secret"`
+
+  if [ -z $hasSecret ]; then
+      echo "Failed Order has error"
+      exit 1
+  else
+     echo "Passed orderList & get"
+  fi
+}
+
+# #############################################################################
+
+status
+
+if [ $plugin == "bitcoinwallet" ]; then
+   execute_bitcoin
+fi
+
+if [ $plugin == "milagro"  ]; then
+   execute_milagro
+fi
+
+if [ $plugin == "safeguardsecret" ]; then
+    execute_safeguardsecret
+fi
+execute_orderlist
+
diff --git a/cmd/servicetester/fulltest.sh b/cmd/servicetester/fulltest.sh
new file mode 100755
index 0000000..fb75a10
--- /dev/null
+++ b/cmd/servicetester/fulltest.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+pushd () {
+    command pushd "$@" > /dev/null
+}
+
+popd () {
+    command popd "$@" > /dev/null
+}
+
+start_server () {
+    GO111MODULE=on go build -o target/service github.com/apache/incubator-milagro-dta/cmd/service
+    target/service daemon -service=$1 > /dev/null &
+    pid=$!
+    sleep 3
+}
+
+report () {
+    if [ $2 -eq 0 ]; then
+        echo "PASSED $1"
+    else
+        echo "FAILED $1"
+    fi
+}
+
+test_plugin () {
+    pushd .
+    cd ../..
+    start_server $1
+    popd 
+    ./e2e_test.sh > /dev/null
+    res=$?
+    report "$1" $res 
+    kill -s int $pid
+}
+
+cd "$(dirname "$0")"
+test_plugin bitcoinwallet
+test_plugin milagro
+test_plugin safeguardsecret
+
+
+
diff --git a/cmd/servicetester/id_test.sh b/cmd/servicetester/id_test.sh
new file mode 100755
index 0000000..b30032a
--- /dev/null
+++ b/cmd/servicetester/id_test.sh
@@ -0,0 +1,83 @@
+#!/bin/bash
+#End to End Test of Services using curl/bash
+
+apiVersion="v1"
+
+
+status () {
+  #Determine if an extension is running
+  statusOutput=$(curl -s -X GET "http://localhost:5556/$apiVersion/status" -H "accept: */*" -H "Content-Type: application/json")
+  identity=$(echo $statusOutput | jq .nodeCID)
+  extensionVendor=$(echo $statusOutput | jq -r .extensionVendor)
+  plugin=$(echo $statusOutput | jq -r .plugin)
+  echo "ID $identity"
+  echo "Plugin: $plugin"
+  echo "Vendor: $extensionVendor"
+
+  if [ -z '${extensionVendor}' ]; then
+      echo "Server Not Running"
+      exit
+  fi
+}
+
+
+
+
+pushd () {
+    command pushd "$@" > /dev/null
+}
+
+popd () {
+    command popd "$@" > /dev/null
+}
+
+start_server () {
+    GO111MODULE=on go build -o target/service github.com/apache/incubator-milagro-dta/cmd/service
+    target/service daemon -service=$1 > /dev/null &
+    pid=$!
+    sleep 3
+}
+
+report () {
+    if [ $2 -eq 0 ]; then
+        echo "PASSED $1"
+    else
+        echo "FAILED $1"
+    fi
+}
+
+
+cd "$(dirname "$0")"
+pushd .
+cd ../..
+start_server milagro
+
+popd 
+
+status
+
+#Create a new Idenity
+output1=$(curl -s -X POST "http://localhost:5556/$apiVersion/identity" -H "accept: */*" -H "Content-Type: application/json" -d "{\"Name\":\"AA\"}")
+docid=$(echo $output1 | jq -r .idDocumentCID)
+
+#Get the single ID
+output2=$(curl -s -X GET "http://localhost:5556/$apiVersion/identity/$docid" -H "accept: */*" -H "Content-Type: application/json")
+
+
+
+SikePublicKey=$(echo $output2 | jq -r .sikePublicKey)
+BlsPublicKey=$(echo $output2 | jq -r .blsPublicKey)
+BeneficiaryECPubl=$(echo $output2 | jq -r .beneficiaryECPublicKey)
+
+#Get a list of all identities
+output3=$(curl -s -X GET "http://localhost:5556/$apiVersion/identity?page=0&perPage=1&sortBy=dateCreatedDsc")
+firstDoc=$(echo $output3 | jq -r '.idDocumentList[0].idDocumentCID')
+
+#Pass test if Created ID is top of the list
+if [ $firstDoc == $docid ]; then
+  echo "Passed"
+else
+  echo "fail"
+fi
+
+kill -s int $pid
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..4e49a25
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,52 @@
+module github.com/apache/incubator-milagro-dta
+
+require (
+	github.com/VividCortex/gohistogram v1.0.0 // indirect
+	github.com/btcsuite/btcd v0.0.0-20190427004231-96897255fd17
+	github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d
+	github.com/coreos/go-oidc v2.0.0+incompatible
+	github.com/go-kit/kit v0.8.0
+	github.com/go-playground/locales v0.12.1 // indirect
+	github.com/go-playground/universal-translator v0.16.0 // indirect
+	github.com/go-test/deep v1.0.2
+	github.com/go-yaml/yaml v2.1.0+incompatible
+	github.com/gogo/protobuf v1.2.1
+	github.com/golang/protobuf v1.3.1
+	github.com/google/uuid v1.1.1
+	github.com/gorilla/mux v1.7.3
+	github.com/ipfs/go-datastore v0.0.5
+	github.com/ipfs/go-ds-leveldb v0.0.2
+	github.com/ipfs/go-ipfs v0.4.22
+	github.com/ipfs/go-ipfs-api v0.0.1
+	github.com/ipfs/go-ipfs-config v0.0.3
+	github.com/ipfs/go-ipfs-files v0.0.3
+	github.com/ipfs/interface-go-ipfs-core v0.0.8
+	github.com/leodido/go-urn v1.1.0 // indirect
+	github.com/libp2p/go-libp2p-crypto v0.0.2
+	github.com/libp2p/go-libp2p-peer v0.1.1
+	github.com/multiformats/go-multihash v0.0.5
+	github.com/mwitkow/go-proto-validators v0.0.0-20190709101305-c00cd28f239a
+	github.com/pkg/errors v0.8.1
+	github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
+	github.com/prometheus/client_golang v0.9.3
+	github.com/stretchr/testify v1.3.0
+	github.com/tyler-smith/go-bip39 v1.0.0
+	go.etcd.io/bbolt v1.3.3
+	golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 // indirect
+	gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
+	gopkg.in/go-playground/validator.v9 v9.29.1
+	gopkg.in/square/go-jose.v2 v2.3.1 // indirect
+)
+
+replace (
+	github.com/go-critic/go-critic v0.0.0-20181204210945-c3db6069acc5 => github.com/go-critic/go-critic v0.3.5-0.20190210220443-ee9bf5809ead
+	github.com/go-critic/go-critic v0.0.0-20181204210945-ee9bf5809ead => github.com/go-critic/go-critic v0.3.5-0.20190210220443-ee9bf5809ead
+	github.com/golangci/errcheck v0.0.0-20181003203344-ef45e06d44b6 => github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6
+	github.com/golangci/go-tools v0.0.0-20180109140146-af6baa5dc196 => github.com/golangci/go-tools v0.0.0-20190318060251-af6baa5dc196
+	github.com/golangci/gofmt v0.0.0-20181105071733-0b8337e80d98 => github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98
+	github.com/golangci/gosec v0.0.0-20180901114220-66fb7fc33547 => github.com/golangci/gosec v0.0.0-20190211064107-66fb7fc33547
+	github.com/golangci/lint-1 v0.0.0-20180610141402-ee948d087217 => github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217
+	mvdan.cc/unparam v0.0.0-20190124213536-fbb59629db34 => mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34
+)
+
+go 1.12
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..a70d453
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,799 @@
+bazil.org/fuse v0.0.0-20180421153158-65cc252bf669 h1:FNCRpXiquG1aoyqcIWVFmpTSKVcx2bQD38uZZeGtdlw=
+bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
+github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4=
+github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=
+github.com/Kubuxu/gocovmerge v0.0.0-20161216165753-7ecaa51963cd/go.mod h1:bqoB8kInrTeEtYAwaIXoSRqdwnjQmFhsfusnzyui6yY=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/OpenPeeDeeP/depguard v0.0.0-20180806142446-a69c782687b2/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o=
+github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
+github.com/Stebalien/go-bitfield v0.0.0-20180330043415-076a62f9ce6e/go.mod h1:3oM7gXIttpYDAJXpVNnSCiUMYBLIZ6cb1t+Ip982MRo=
+github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo=
+github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s=
+github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=
+github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
+github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/bifurcation/mint v0.0.0-20181105073638-824af6541065/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/bren2010/proquint v0.0.0-20160323162903-38337c27106d h1:QgeLLoPD3kRVmeu/1al9iIpIANMi9O1zXFm8BnYGCJg=
+github.com/bren2010/proquint v0.0.0-20160323162903-38337c27106d/go.mod h1:Jbj8eKecMNwf0KFI75skSUZqMB4UCRcndUScVBTWyUI=
+github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
+github.com/btcsuite/btcd v0.0.0-20190427004231-96897255fd17 h1:m0N5Vg5nP3zEz8TREZpwX3gt4Biw3/8fbIf4A3hO96g=
+github.com/btcsuite/btcd v0.0.0-20190427004231-96897255fd17/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
+github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
+github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
+github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng=
+github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
+github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
+github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
+github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
+github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
+github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
+github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY=
+github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
+github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
+github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764=
+github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/go-oidc v2.0.0+incompatible h1:+RStIopZ8wooMx+Vs5Bt8zMXxV1ABl5LbakNExNmZIg=
+github.com/coreos/go-oidc v2.0.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-semver v0.2.1-0.20180108230905-e214231b295a h1:U0BbGfKnviqVBJQB4etvm+mKx53KfkumNLBt6YeF/0Q=
+github.com/coreos/go-semver v0.2.1-0.20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0=
+github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis=
+github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018 h1:6xT9KW8zLC5IlbaIF5Q7JNieBoACT7iW0YTxQHR0in0=
+github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4=
+github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=
+github.com/dgraph-io/badger v1.6.0-rc1 h1:JphPpoBZJ3WHha133BGYlQqltSGIhV+VsEID0++nN9A=
+github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
+github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302/go.mod h1:qBlWZqWeVx9BjvqBsnC/8RUlAYpIFmPvgROcw0n1scE=
+github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 h1:BBso6MBKW8ncyZLv37o+KNyy0HrrHgfnOaGQC2qvN+A=
+github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg=
+github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI=
+github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
+github.com/go-critic/go-critic v0.3.5-0.20190210220443-ee9bf5809ead/go.mod h1:3MzXZKJdeXqdU9cj+rvZdNiN7SZ8V9OjybF8loZDmHU=
+github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
+github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
+github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
+github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
+github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
+github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw=
+github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
+github.com/go-toolsmith/astcast v0.0.0-20181028201508-b7a89ed70af1/go.mod h1:TEo3Ghaj7PsZawQHxT/oBvo4HK/sl1RcuUHDKTTju+o=
+github.com/go-toolsmith/astcopy v0.0.0-20180903214859-79b422d080c4/go.mod h1:c9CPdq2AzM8oPomdlPniEfPAC6g1s7NqZzODt8y6ib8=
+github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
+github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg=
+github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk=
+github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks=
+github.com/go-toolsmith/strparse v0.0.0-20180903215201-830b6daa1241/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
+github.com/go-toolsmith/typep v0.0.0-20181030061450-d63dc7650676/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
+github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
+github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
+github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
+github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
+github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
+github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0=
+github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8=
+github.com/golangci/go-tools v0.0.0-20190318060251-af6baa5dc196/go.mod h1:unzUULGw35sjyOYjUt0jMTXqHlZPpPc6e+xfO4cd6mM=
+github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o=
+github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU=
+github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
+github.com/golangci/golangci-lint v1.16.1-0.20190425135923-692dacb773b7/go.mod h1:kSe2pu2LlcsMT5Dr95yNKUT5RNfMkwif9MZqtOW5NEs=
+github.com/golangci/gosec v0.0.0-20190211064107-66fb7fc33547/go.mod h1:0qUabqiIQgfmlAmulqxyiGkkyF6/tOGSnY2cnPVwrzU=
+github.com/golangci/ineffassign v0.0.0-20180808204949-2ee8f2867dde/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU=
+github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
+github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
+github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
+github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI=
+github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4=
+github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ=
+github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gxed/go-shellwords v1.0.3/go.mod h1:N7paucT91ByIjmVJHhvoarjoQnmsi3Jd3vH7VqgtMxQ=
+github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
+github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
+github.com/gxed/pubsub v0.0.0-20180201040156-26ebdf44f824/go.mod h1:OiEWyHgK+CWrmOlVquHaIK1vhpUJydC9m0Je6mhaiNE=
+github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/hsanjuan/go-libp2p-gostream v0.0.31/go.mod h1:cWvV5/NQ5XWi0eQZnX/svsAk6NLc4U26pItvj0eDeRk=
+github.com/hsanjuan/go-libp2p-http v0.0.2/go.mod h1:MynY94gfOZxrw/0lVF4o7vbV2Zr84IC8sLBXmj8F5IE=
+github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag=
+github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo=
+github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
+github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/ipfs/bbloom v0.0.1 h1:s7KkiBPfxCeDVo47KySjK0ACPc5GJRUxFpdyWEuDjhw=
+github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI=
+github.com/ipfs/dir-index-html v1.0.3/go.mod h1:TG9zbaH/+4MnkGel0xF4SLNhk+YZvBNo6jjBkO/LaWc=
+github.com/ipfs/go-bitswap v0.0.3/go.mod h1:jadAZYsP/tcRMl47ZhFxhaNuDQoXawT8iHMg+iFoQbg=
+github.com/ipfs/go-bitswap v0.0.8-0.20190704155249-cbb485998356 h1:DNc/6p5YnnHWnKab5Lmg6BS4CsRjWyYvapaIsQELAJg=
+github.com/ipfs/go-bitswap v0.0.8-0.20190704155249-cbb485998356/go.mod h1:kYh8QssUH3mAuCwV3WmfcSqwJLhQC4WynKpd1hxt85A=
+github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc=
+github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE=
+github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
+github.com/ipfs/go-blockservice v0.0.3 h1:40OvwrxeudTAlUGUAKNYnNPcwQeLtXedjzTWecnUinQ=
+github.com/ipfs/go-blockservice v0.0.3/go.mod h1:/NNihwTi6V2Yr6g8wBI+BSwPuURpBRMtYNGrlxZ8KuI=
+github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
+github.com/ipfs/go-cid v0.0.2 h1:tuuKaZPU1M6HcejsO3AcYWW8sZ8MTvyxfc4uqB4eFE8=
+github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
+github.com/ipfs/go-cidutil v0.0.2 h1:CNOboQf1t7Qp0nuNh8QMmhJs0+Q//bRL1axtCnIB1Yo=
+github.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s=
+github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
+github.com/ipfs/go-datastore v0.0.3/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
+github.com/ipfs/go-datastore v0.0.5 h1:q3OfiOZV5rlsK1H5V8benjeUApRfMGs4Mrhmr6NriQo=
+github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
+github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
+github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
+github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=
+github.com/ipfs/go-ds-badger v0.0.5 h1:dxKuqw5T1Jm8OuV+lchA76H9QZFyPKZeLuT6bN42hJQ=
+github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s=
+github.com/ipfs/go-ds-flatfs v0.0.2 h1:1zujtU5bPBH6B8roE+TknKIbBCrpau865xUk0dH3x2A=
+github.com/ipfs/go-ds-flatfs v0.0.2/go.mod h1:YsMGWjUieue+smePAWeH/YhHtlmEMnEGhiwIn6K6rEM=
+github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc=
+github.com/ipfs/go-ds-leveldb v0.0.2 h1:P5HB59Zblym0B5XYOeEyw3YtPtbpIqQCavCSWaWEEk8=
+github.com/ipfs/go-ds-leveldb v0.0.2/go.mod h1:CWFeBh5IAAscWyG/QRH+lJaAlnLWjsfPSNs4teyPUp0=
+github.com/ipfs/go-ds-measure v0.0.1 h1:PrCueug+yZLkDCOthZTXKinuoCal/GvlAT7cNxzr03g=
+github.com/ipfs/go-ds-measure v0.0.1/go.mod h1:wiH6bepKsgyNKpz3nyb4erwhhIVpIxnZbsjN1QpVbbE=
+github.com/ipfs/go-fs-lock v0.0.1 h1:XHX8uW4jQBYWHj59XXcjg7BHlHxV9ZOYs6Y43yb7/l0=
+github.com/ipfs/go-fs-lock v0.0.1/go.mod h1:DNBekbboPKcxs1aukPSaOtFA3QfSdi5C855v0i9XJ8Y=
+github.com/ipfs/go-ipfs v0.4.22 h1:dDUSkIj0kSrMJW55wOm9P+mYewxCDSATy+PGZrShdfI=
+github.com/ipfs/go-ipfs v0.4.22/go.mod h1:vgIn+MMrMEN2Yd6AWxAZVP/+YGI8dSGSgwiTEU6R2kw=
+github.com/ipfs/go-ipfs-addr v0.0.1 h1:DpDFybnho9v3/a1dzJ5KnWdThWD1HrFLpQ+tWIyBaFI=
+github.com/ipfs/go-ipfs-addr v0.0.1/go.mod h1:uKTDljHT3Q3SUWzDLp3aYUi8MrY32fgNgogsIa0npjg=
+github.com/ipfs/go-ipfs-api v0.0.1 h1:4wx4mSgeq5FwMN8LDF7WLwPDKEd+YKjgySrpOJQ2r8o=
+github.com/ipfs/go-ipfs-api v0.0.1/go.mod h1:0FhXgCzrLu7qNmdxZvgYqD9jFzJxzz1NAVt3OQ0WOIc=
+github.com/ipfs/go-ipfs-blockstore v0.0.1 h1:O9n3PbmTYZoNhkgkEyrXTznbmktIXif62xLX+8dPHzc=
+github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08=
+github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ=
+github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk=
+github.com/ipfs/go-ipfs-chunker v0.0.1 h1:cHUUxKFQ99pozdahi+uSC/3Y6HeRpi9oTeUHbE27SEw=
+github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw=
+github.com/ipfs/go-ipfs-cmds v0.0.8 h1:ZMo0ZeQOr10ZKY4yxYA3lRHUbnF/ZYcV9cpU0IrlGFI=
+github.com/ipfs/go-ipfs-cmds v0.0.8/go.mod h1:TiK4e7/V31tuEb8YWDF8lN3qrnDH+BS7ZqWIeYJlAs8=
+github.com/ipfs/go-ipfs-config v0.0.1/go.mod h1:KDbHjNyg4e6LLQSQpkgQMBz6Jf4LXiWAcmnkcwmH0DU=
+github.com/ipfs/go-ipfs-config v0.0.3 h1:Ep4tRdP1iVK76BgOprD9B/qtOEdpno+1Xb57BqydgGk=
+github.com/ipfs/go-ipfs-config v0.0.3/go.mod h1:KDbHjNyg4e6LLQSQpkgQMBz6Jf4LXiWAcmnkcwmH0DU=
+github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
+github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ=
+github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
+github.com/ipfs/go-ipfs-ds-help v0.0.1 h1:QBg+Ts2zgeemK/dB0saiF/ykzRGgfoFMT90Rzo0OnVU=
+github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo=
+github.com/ipfs/go-ipfs-exchange-interface v0.0.1 h1:LJXIo9W7CAmugqI+uofioIpRb6rY30GUu7G6LUfpMvM=
+github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM=
+github.com/ipfs/go-ipfs-exchange-offline v0.0.1 h1:P56jYKZF7lDDOLx5SotVh5KFxoY6C81I1NSHW1FxGew=
+github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0=
+github.com/ipfs/go-ipfs-files v0.0.1/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4=
+github.com/ipfs/go-ipfs-files v0.0.2/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4=
+github.com/ipfs/go-ipfs-files v0.0.3 h1:ME+QnC3uOyla1ciRPezDW0ynQYK2ikOh9OCKAEg4uUA=
+github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4=
+github.com/ipfs/go-ipfs-flags v0.0.1/go.mod h1:RnXBb9WV53GSfTrSDVK61NLTFKvWc60n+K9EgCDh+rA=
+github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs=
+github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A=
+github.com/ipfs/go-ipfs-pq v0.0.1 h1:zgUotX8dcAB/w/HidJh1zzc1yFq6Vm8J7T2F4itj/RU=
+github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=
+github.com/ipfs/go-ipfs-routing v0.0.1 h1:394mZeTLcbM/LDO12PneBYvkZAUA+nRnmC0lAzDXKOY=
+github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs=
+github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50=
+github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=
+github.com/ipfs/go-ipld-cbor v0.0.1/go.mod h1:RXHr8s4k0NE0TKhnrxqZC9M888QfsBN9rhS5NjfKzY8=
+github.com/ipfs/go-ipld-cbor v0.0.2 h1:amzFztBQQQ69UA5+f7JRfoXF/z2l//MGfEDHVkS20+s=
+github.com/ipfs/go-ipld-cbor v0.0.2/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc=
+github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms=
+github.com/ipfs/go-ipld-format v0.0.2 h1:OVAGlyYT6JPZ0pEfGntFPS40lfrDmaDbQwNHEY2G9Zs=
+github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k=
+github.com/ipfs/go-ipld-git v0.0.2 h1:dn5Quu9lgjkSqkc9CaTsRjzg90kaIitj9wENtigVMH8=
+github.com/ipfs/go-ipld-git v0.0.2/go.mod h1:RuvMXa9qtJpDbqngyICCU/d+cmLFXxLsbIclmD0Lcr0=
+github.com/ipfs/go-ipns v0.0.1 h1:5vX0+ehF55YWxE8Pmf4eB8szcP+fh24AXnvCkOmSLCc=
+github.com/ipfs/go-ipns v0.0.1/go.mod h1:HOiAXgGiH0wCSwsFM1IKdOy6YGT4iZafcsUKni703/g=
+github.com/ipfs/go-log v0.0.1 h1:9XTUN/rW64BCG1YhPK9Hoy3q8nr4gOmHHBpgFdfw6Lc=
+github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
+github.com/ipfs/go-merkledag v0.0.3 h1:A5DlOMzqTRDVmdgkf3dzCKCFmVWH4Zqwb0cbYXUs+Ro=
+github.com/ipfs/go-merkledag v0.0.3/go.mod h1:Oc5kIXLHokkE1hWGMBHw+oxehkAaTOqtEb7Zbh6BhLA=
+github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg=
+github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY=
+github.com/ipfs/go-metrics-prometheus v0.0.2/go.mod h1:ELLU99AQQNi+zX6GCGm2lAgnzdSH3u5UVlCdqSXnEks=
+github.com/ipfs/go-mfs v0.0.7 h1:Xjqk0jAhgwhMHO39oH4jqP1QkeAGqDelxa814voygN0=
+github.com/ipfs/go-mfs v0.0.7/go.mod h1:10Hdow7wUbSlIamnOduxeP6MEp58TozZmdnAhugOKz8=
+github.com/ipfs/go-path v0.0.3/go.mod h1:zIRQUez3LuQIU25zFjC2hpBTHimWx7VK5bjZgRLbbdo=
+github.com/ipfs/go-path v0.0.4 h1:zG/id80tV51XAfvCsRJIEGQSHGuTDBi8RWrtr3EfcfY=
+github.com/ipfs/go-path v0.0.4/go.mod h1:zIRQUez3LuQIU25zFjC2hpBTHimWx7VK5bjZgRLbbdo=
+github.com/ipfs/go-peertaskqueue v0.0.5-0.20190704154349-f09820a0a5b6 h1:/8zfOPbZ8q0YadOu7snck13TtYW9f08v65XDWag9+jU=
+github.com/ipfs/go-peertaskqueue v0.0.5-0.20190704154349-f09820a0a5b6/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP1MX6Kd+aN+rMQ=
+github.com/ipfs/go-todocounter v0.0.1 h1:kITWA5ZcQZfrUnDNkRn04Xzh0YFaDFXsoO2A81Eb6Lw=
+github.com/ipfs/go-todocounter v0.0.1/go.mod h1:l5aErvQc8qKE2r7NDMjmq5UNAvuZy0rC8BHOplkWvZ4=
+github.com/ipfs/go-unixfs v0.0.4/go.mod h1:eIo/p9ADu/MFOuyxzwU+Th8D6xoxU//r590vUpWyfz8=
+github.com/ipfs/go-unixfs v0.0.6 h1:mQ6KS3NK4GA9hyUpGdGItqt5llzyIx0Qy2UxC/A7bEo=
+github.com/ipfs/go-unixfs v0.0.6/go.mod h1:g41FlHFM/qacA3jzMPOYKIwNwbgTQEKJH2hQiq19Zrc=
+github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E=
+github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0=
+github.com/ipfs/hang-fds v0.0.1/go.mod h1:U4JNbzwTpk/qP2Ms4VgrZ4HcgJGVosBJqMXvwe4udSY=
+github.com/ipfs/interface-go-ipfs-core v0.0.8 h1:nmEYOfK6QRf3VIdggoZ4rmbKXcC2g6cEdU13Z1CvmL4=
+github.com/ipfs/interface-go-ipfs-core v0.0.8/go.mod h1:RU+DSZXV+JdA7Yagu3OrSoB6hngSmMtK1w6ENOqmfQ8=
+github.com/ipfs/iptb v1.4.0/go.mod h1:1rzHpCYtNp87/+hTxG5TfCVn/yMY3dKnLn8tBiMfdmg=
+github.com/ipfs/iptb-plugins v0.0.2/go.mod h1:Vud+X6lHv5QlgVbqCPBHt91I0gPIRgmkD6/tMUsI07U=
+github.com/jackpal/gateway v1.0.4/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
+github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc=
+github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
+github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA=
+github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
+github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs=
+github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc=
+github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
+github.com/jbenet/go-is-domain v1.0.2 h1:11r5MSptcNFZyBoqubBQnVMUKRWLuRjL1banaIk+iYo=
+github.com/jbenet/go-is-domain v1.0.2/go.mod h1:xbRLRb0S7FgzDBTJlguhDVwLYM/5yNtvktxj2Ttfy7Q=
+github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c/go.mod h1:sdx1xVM9UuLw1tXnhJWN3piypTUO3vCIHYmG15KE/dU=
+github.com/jbenet/go-random-files v0.0.0-20190219210431-31b3f20ebded/go.mod h1:FKvZrl5nnaGnTAMewcq0i7wM5zHD75e0lwlnF8q46uo=
+github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2 h1:vhC1OXXiT9R2pczegwz6moDvuRpggaroAXhPIseh57A=
+github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs=
+github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY=
+github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr10=
+github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
+github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
+github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE=
+github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v0.0.0-20161130080628-0de1eaf82fa3/go.mod h1:jxZFDH7ILpTPQTk+E2s+z4CUas9lVNjIuKR4c5/zKgM=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b h1:wxtKgYHEncAU00muMD06dzLiahtGM1eouRNOzVV7tdQ=
+github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
+github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
+github.com/libp2p/go-addr-util v0.0.1 h1:TpTQm9cXVRVSKsYbgQ7GKc3KbbHVTnbostgGaDEP+88=
+github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ=
+github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ=
+github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=
+github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=
+github.com/libp2p/go-conn-security v0.0.1 h1:4kMMrqrt9EUNCNjX1xagSJC+bq16uqjMe9lk1KBMVNs=
+github.com/libp2p/go-conn-security v0.0.1/go.mod h1:bGmu51N0KU9IEjX7kl2PQjgZa40JQWnayTvNMgD/vyk=
+github.com/libp2p/go-conn-security-multistream v0.0.1/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE=
+github.com/libp2p/go-conn-security-multistream v0.0.2 h1:Ykz0lnNjxk+0SdslUmlLNyrleqdpS1S/VW+dxFdt74Y=
+github.com/libp2p/go-conn-security-multistream v0.0.2/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE=
+github.com/libp2p/go-flow-metrics v0.0.1 h1:0gxuFd2GuK7IIP5pKljLwps6TvcuYgvG7Atqi3INF5s=
+github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8=
+github.com/libp2p/go-libp2p v0.0.2/go.mod h1:Qu8bWqFXiocPloabFGUcVG4kk94fLvfC8mWTDdFC9wE=
+github.com/libp2p/go-libp2p v0.0.27/go.mod h1:kjeVlESxQisK2DvyKp38/UMHYd9gAMTj3C3XOB/DEZo=
+github.com/libp2p/go-libp2p v0.0.28 h1:tkDnM7iwrz9OSRRb8YAV4HYjv8TKsAxyxrV2sES9/Aw=
+github.com/libp2p/go-libp2p v0.0.28/go.mod h1:GBW0VbgEKe8ELXVpLQJduJYlJHRv/XfwP6Fo9TEcDJU=
+github.com/libp2p/go-libp2p-autonat v0.0.2/go.mod h1:fs71q5Xk+pdnKU014o2iq1RhMs9/PMaG5zXRFNnIIT4=
+github.com/libp2p/go-libp2p-autonat v0.0.3/go.mod h1:fs71q5Xk+pdnKU014o2iq1RhMs9/PMaG5zXRFNnIIT4=
+github.com/libp2p/go-libp2p-autonat v0.0.5/go.mod h1:cKt+qOSnWAZp0dqIuUk62v0/QAPw0vnLuVZnmzkOXRk=
+github.com/libp2p/go-libp2p-autonat v0.0.6 h1:OCStANLLpeyQeWFUuqZJ7aS9+Bx0/uoVb1PtLA9fGTQ=
+github.com/libp2p/go-libp2p-autonat v0.0.6/go.mod h1:uZneLdOkZHro35xIhpbtTzLlgYturpu4J5+0cZK3MqE=
+github.com/libp2p/go-libp2p-autonat-svc v0.0.2/go.mod h1:j4iMiw0d3diRm5iB0noXumtb0mPvWrM1qAyh640cp8w=
+github.com/libp2p/go-libp2p-autonat-svc v0.0.5 h1:bTom7QFAkJMXiA8ibSsKQ2+LKEHsXZz2IAWYolg/YYg=
+github.com/libp2p/go-libp2p-autonat-svc v0.0.5/go.mod h1:6aLiQelA0CKEcPR0TvE9bqJ7U8Mc0nVdwCoho3ROdck=
+github.com/libp2p/go-libp2p-blankhost v0.0.1 h1:/mZuuiwntNR8RywnCFlGHLKrKLYne+qciBpQXWqp5fk=
+github.com/libp2p/go-libp2p-blankhost v0.0.1/go.mod h1:Ibpbw/7cPPYwFb7PACIWdvxxv0t0XCCI10t7czjAjTc=
+github.com/libp2p/go-libp2p-circuit v0.0.1/go.mod h1:Dqm0s/BiV63j8EEAs8hr1H5HudqvCAeXxDyic59lCwE=
+github.com/libp2p/go-libp2p-circuit v0.0.7/go.mod h1:DFCgZ2DklFGTUIZIhSvbbWXTErUgjyNrJGfDHOrTKIA=
+github.com/libp2p/go-libp2p-circuit v0.0.8 h1:vd9vZDy+LDssTvUuxIqnYUOAK2hfHoSQO2xjWhPVEmc=
+github.com/libp2p/go-libp2p-circuit v0.0.8/go.mod h1:DFCgZ2DklFGTUIZIhSvbbWXTErUgjyNrJGfDHOrTKIA=
+github.com/libp2p/go-libp2p-connmgr v0.0.1/go.mod h1:eUBBlbuwBBTd/eim7KV5x0fOD2UHDjSwhzmBL6miIx8=
+github.com/libp2p/go-libp2p-connmgr v0.0.6 h1:oEUriPO/qWTvfHRPEU4HdNlNhYigdueOs2X3UZCdbYM=
+github.com/libp2p/go-libp2p-connmgr v0.0.6/go.mod h1:uwDfgdgqB5248sQYib1xo603cSsMg9PgAKu0Z+Y65Qk=
+github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE=
+github.com/libp2p/go-libp2p-crypto v0.0.2 h1:TTdJ4y6Uoa6NxQcuEaVkQfFRcQeCE2ReDk8Ok4I0Fyw=
+github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I=
+github.com/libp2p/go-libp2p-daemon v0.0.6/go.mod h1:nkhjsjSzkF+tg6iScsTTgq9m+VfyMtXNpycYG4CFvC8=
+github.com/libp2p/go-libp2p-discovery v0.0.1/go.mod h1:ZkkF9xIFRLA1xCc7bstYFkd80gBGK8Fc1JqGoU2i+zI=
+github.com/libp2p/go-libp2p-discovery v0.0.4 h1:/kZwOVmcUHvB94zegSJYnUA9EvT1g8APoQJb5FHyT1c=
+github.com/libp2p/go-libp2p-discovery v0.0.4/go.mod h1:ReQGiv7QTtza8FUWzewfuMmRDVOQVp+lxHlJJA8YQCM=
+github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go=
+github.com/libp2p/go-libp2p-host v0.0.3 h1:BB/1Z+4X0rjKP5lbQTmjEjLbDVbrcmLOlA6QDsN5/j4=
+github.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8=
+github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k=
+github.com/libp2p/go-libp2p-interface-connmgr v0.0.4/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k=
+github.com/libp2p/go-libp2p-interface-connmgr v0.0.5 h1:KG/KNYL2tYzXAfMvQN5K1aAGTYSYUMJ1prgYa2/JI1E=
+github.com/libp2p/go-libp2p-interface-connmgr v0.0.5/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k=
+github.com/libp2p/go-libp2p-interface-pnet v0.0.1 h1:7GnzRrBTJHEsofi1ahFdPN9Si6skwXQE9UqR2S+Pkh8=
+github.com/libp2p/go-libp2p-interface-pnet v0.0.1/go.mod h1:el9jHpQAXK5dnTpKA4yfCNBZXvrzdOU75zz+C6ryp3k=
+github.com/libp2p/go-libp2p-kad-dht v0.0.4/go.mod h1:oaBflOQcuC8H+SVV0YN26H6AS+wcUEJyjUGV66vXuSY=
+github.com/libp2p/go-libp2p-kad-dht v0.0.13 h1:ReMb41jJrngvXnU5Tirf74bBkXx4M9ne5QyFQPeNYtw=
+github.com/libp2p/go-libp2p-kad-dht v0.0.13/go.mod h1:3A4xaZJeJ3zD3jCg17mtI+rA7uuXiiQdKVyAZOhZo1U=
+github.com/libp2p/go-libp2p-kbucket v0.0.1/go.mod h1:Y0iQDHRTk/ZgM8PC4jExoF+E4j+yXWwRkdldkMa5Xm4=
+github.com/libp2p/go-libp2p-kbucket v0.1.1 h1:ZrvW3qCM+lAuv7nrNts/zfEiClq+GZe8OIzX4Vb3Dwo=
+github.com/libp2p/go-libp2p-kbucket v0.1.1/go.mod h1:Y0iQDHRTk/ZgM8PC4jExoF+E4j+yXWwRkdldkMa5Xm4=
+github.com/libp2p/go-libp2p-loggables v0.0.1 h1:HVww9oAnINIxbt69LJNkxD8lnbfgteXR97Xm4p3l9ps=
+github.com/libp2p/go-libp2p-loggables v0.0.1/go.mod h1:lDipDlBNYbpyqyPX/KcoO+eq0sJYEVR2JgOexcivchg=
+github.com/libp2p/go-libp2p-metrics v0.0.1 h1:yumdPC/P2VzINdmcKZd0pciSUCpou+s0lwYCjBbzQZU=
+github.com/libp2p/go-libp2p-metrics v0.0.1/go.mod h1:jQJ95SXXA/K1VZi13h52WZMa9ja78zjyy5rspMsC/08=
+github.com/libp2p/go-libp2p-mplex v0.1.1 h1:lSPS1VJ36P01gGO//KgcsmSah5uoC3X9r7WY5j+iP4c=
+github.com/libp2p/go-libp2p-mplex v0.1.1/go.mod h1:KUQWpGkCzfV7UIpi8SKsAVxyBgz1c9R5EvxgnwLsb/I=
+github.com/libp2p/go-libp2p-nat v0.0.2/go.mod h1:QrjXQSD5Dj4IJOdEcjHRkWTSomyxRo6HnUkf/TfQpLQ=
+github.com/libp2p/go-libp2p-nat v0.0.4 h1:+KXK324yaY701On8a0aGjTnw8467kW3ExKcqW2wwmyw=
+github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY=
+github.com/libp2p/go-libp2p-net v0.0.0-20190226201932-e71fff5ba6e9/go.mod h1:8W6Wx3AZbTRTe8zSMLoAmT3mGyau+w6kGIRk+Z+MZ7Q=
+github.com/libp2p/go-libp2p-net v0.0.1/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c=
+github.com/libp2p/go-libp2p-net v0.0.2 h1:qP06u4TYXfl7uW/hzqPhlVVTSA2nw1B/bHBJaUnbh6M=
+github.com/libp2p/go-libp2p-net v0.0.2/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c=
+github.com/libp2p/go-libp2p-netutil v0.0.1 h1:LgD6+skofkOx8z6odD9+MZHKjupv3ng1u6KRhaADTnA=
+github.com/libp2p/go-libp2p-netutil v0.0.1/go.mod h1:GdusFvujWZI9Vt0X5BKqwWWmZFxecf9Gt03cKxm2f/Q=
+github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo=
+github.com/libp2p/go-libp2p-peer v0.1.1 h1:qGCWD1a+PyZcna6htMPo26jAtqirVnJ5NvBQIKV7rRY=
+github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es=
+github.com/libp2p/go-libp2p-peerstore v0.0.0-20190226201924-e2df3e49eabf/go.mod h1:lLfgn0N3z2t+ER57a88K7NTZjMO27ez5TyWSURd428E=
+github.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20=
+github.com/libp2p/go-libp2p-peerstore v0.0.6 h1:RgX/djPFXqZGktW0j2eF4NAX0pzDsCot45jO2GewC+g=
+github.com/libp2p/go-libp2p-peerstore v0.0.6/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20=
+github.com/libp2p/go-libp2p-pnet v0.0.1 h1:2e5d15M8XplUKsU4Fqrll5eDfqGg/7mHUufLkhbfKHM=
+github.com/libp2p/go-libp2p-pnet v0.0.1/go.mod h1:bWN8HqdpgCdKnXSCsJhbWjiU3UZFa/tIe4no5jCmHVw=
+github.com/libp2p/go-libp2p-protocol v0.0.0-20171212212132-b29f3d97e3a2/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s=
+github.com/libp2p/go-libp2p-protocol v0.0.1 h1:+zkEmZ2yFDi5adpVE3t9dqh/N9TbpFWywowzeEzBbLM=
+github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s=
+github.com/libp2p/go-libp2p-pubsub v0.0.1/go.mod h1:fYKlZBOF2yrJzYlgeEVFSbYWfbS+E8Zix6gMZ0A6WgE=
+github.com/libp2p/go-libp2p-pubsub v0.0.3 h1:DKVoDac2u1Dr8gX7B1HFjCrXkMxr8tfbnt0Fk1mmkgk=
+github.com/libp2p/go-libp2p-pubsub v0.0.3/go.mod h1:fYKlZBOF2yrJzYlgeEVFSbYWfbS+E8Zix6gMZ0A6WgE=
+github.com/libp2p/go-libp2p-pubsub-router v0.0.3 h1:2EF+8nueIsA9Unpj1MxdlS9+dX29kwCxSttchMMfXsI=
+github.com/libp2p/go-libp2p-pubsub-router v0.0.3/go.mod h1:h5z0kyMFRu2J46tt15eEuLHKEmu1MrFghsGHqTc/iII=
+github.com/libp2p/go-libp2p-quic-transport v0.0.0-20190301030811-862195d91de1/go.mod h1:bw/6H57fSVn44ldP1Js6hnzpoiUm9YgBDKSv+ch+hWc=
+github.com/libp2p/go-libp2p-quic-transport v0.0.3 h1:FGEPXsjpY9K6P3iMtJQPKGl45eXickBY1+xSJ84lVVI=
+github.com/libp2p/go-libp2p-quic-transport v0.0.3/go.mod h1:v2oVuaFLkxlFpkFbXUty3dfEYSlNb0sCzvf8cRi1m/k=
+github.com/libp2p/go-libp2p-record v0.0.1 h1:zN7AS3X46qmwsw5JLxdDuI43cH5UYwovKxHPjKBYQxw=
+github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q=
+github.com/libp2p/go-libp2p-routing v0.0.1 h1:hPMAWktf9rYi3ME4MG48qE7dq1ofJxiQbfdvpNntjhc=
+github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys=
+github.com/libp2p/go-libp2p-routing-helpers v0.0.2 h1:SLX7eDQE8Xo197NwNM/hM7WnH3w6fSGY9+G9HkiYwqQ=
+github.com/libp2p/go-libp2p-routing-helpers v0.0.2/go.mod h1:zf1ook9HoOQpfnVXrF4gGorkPrGGf1g25vgH5+4SRNU=
+github.com/libp2p/go-libp2p-secio v0.0.1/go.mod h1:IdG6iQybdcYmbTzxp4J5dwtUEDTOvZrT0opIDVNPrJs=
+github.com/libp2p/go-libp2p-secio v0.0.3 h1:h3fPeDrej7bvvARnC2oSjAfcLZOaS4REZKgWCRQNpE4=
+github.com/libp2p/go-libp2p-secio v0.0.3/go.mod h1:hS7HQ00MgLhRO/Wyu1bTX6ctJKhVpm+j2/S2A5UqYb0=
+github.com/libp2p/go-libp2p-swarm v0.0.1/go.mod h1:mh+KZxkbd3lQnveQ3j2q60BM1Cw2mX36XXQqwfPOShs=
+github.com/libp2p/go-libp2p-swarm v0.0.5/go.mod h1:+nkJir4feiXtWQjb/4CQHMEK8Vw+c5nVVxT8R5bs0yY=
+github.com/libp2p/go-libp2p-swarm v0.0.6 h1:gE0P/v2h+KEXtAi9YTw2UBOSODJ4m9VuuJ+ktc2LVUo=
+github.com/libp2p/go-libp2p-swarm v0.0.6/go.mod h1:s5GZvzg9xXe8sbeESuFpjt8CJPTCa8mhEusweJqyFy8=
+github.com/libp2p/go-libp2p-tls v0.0.1 h1:UIslpmpKDbjEymuidtP2D9up00GfWrOs6eyTKf83uBA=
+github.com/libp2p/go-libp2p-tls v0.0.1/go.mod h1:DInSFKxm9XHHSbCdJRbcWctRYkmtPGnqiaUtgjiEa7g=
+github.com/libp2p/go-libp2p-transport v0.0.0-20190226201958-e8580c8a519d/go.mod h1:lcwgOszllbhvQXul37Kv5YbSYXPoUhRB2Z+Nr3jaBmo=
+github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk=
+github.com/libp2p/go-libp2p-transport v0.0.4/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A=
+github.com/libp2p/go-libp2p-transport v0.0.5 h1:pV6+UlRxyDpASSGD+60vMvdifSCby6JkJDfi+yUMHac=
+github.com/libp2p/go-libp2p-transport v0.0.5/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A=
+github.com/libp2p/go-libp2p-transport-upgrader v0.0.1/go.mod h1:NJpUAgQab/8K6K0m+JmZCe5RUXG10UMEx4kWe9Ipj5c=
+github.com/libp2p/go-libp2p-transport-upgrader v0.0.3/go.mod h1:Ng1HzfMIopyYscMHNFmJqiMMcpgDlj0t+NyjVWW89ws=
+github.com/libp2p/go-libp2p-transport-upgrader v0.0.4 h1:uGMOd14BL1oFlfb/cGfOxPjiTKBhzWV4aMjjoCF1Z1o=
+github.com/libp2p/go-libp2p-transport-upgrader v0.0.4/go.mod h1:RGq+tupk+oj7PzL2kn/m1w6YXxcIAYJYeI90h6BGgUc=
+github.com/libp2p/go-libp2p-yamux v0.1.2/go.mod h1:xUoV/RmYkg6BW/qGxA9XJyg+HzXFYkeXbnhjmnYzKp8=
+github.com/libp2p/go-libp2p-yamux v0.1.3 h1:HmKvv2jWJ4GEm3iP7cEKjuw0POa6rK+Hcsu1FBKzpLc=
+github.com/libp2p/go-libp2p-yamux v0.1.3/go.mod h1:VGSQVrqkh6y4nm0189qqxMtvyBft44MOYYPpYKXiVt4=
+github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=
+github.com/libp2p/go-maddr-filter v0.0.4 h1:hx8HIuuwk34KePddrp2mM5ivgPkZ09JH4AvsALRbFUs=
+github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=
+github.com/libp2p/go-mplex v0.0.1/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=
+github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=
+github.com/libp2p/go-mplex v0.0.4 h1:043XJ3Zr7/Oz5cfyUaJwxUZyP02TngTpt4oq8R5UizQ=
+github.com/libp2p/go-mplex v0.0.4/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=
+github.com/libp2p/go-msgio v0.0.1/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
+github.com/libp2p/go-msgio v0.0.2 h1:ivPvEKHxmVkTClHzg6RXTYHqaJQ0V9cDbq+6lKb3UV0=
+github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
+github.com/libp2p/go-nat v0.0.3 h1:l6fKV+p0Xa354EqQOQP+d8CivdLM4kl5GxC1hSc/UeI=
+github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI=
+github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw=
+github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA=
+github.com/libp2p/go-reuseport-transport v0.0.1/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs=
+github.com/libp2p/go-reuseport-transport v0.0.2 h1:WglMwyXyBu61CMkjCCtnmqNqnjib0GIEjMiHTwR/KN4=
+github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs=
+github.com/libp2p/go-stream-muxer v0.0.0-20190218175335-a3f82916c8ad/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14=
+github.com/libp2p/go-stream-muxer v0.0.1 h1:Ce6e2Pyu+b5MC1k3eeFtAax0pW4gc6MosYSLV05UeLw=
+github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14=
+github.com/libp2p/go-stream-muxer-multistream v0.1.1 h1:DhHqb4nu1fQv/vQKeLAaZGmhLsUA4SF77IdYJiWE1d4=
+github.com/libp2p/go-stream-muxer-multistream v0.1.1/go.mod h1:zmGdfkQ1AzOECIAcccoL8L//laqawOsO03zX8Sa+eGw=
+github.com/libp2p/go-tcp-transport v0.0.1/go.mod h1:mnjg0o0O5TmXUaUIanYPUqkW4+u6mK0en8rlpA6BBTs=
+github.com/libp2p/go-tcp-transport v0.0.3/go.mod h1:f11C2zvCaGDkE8aFPUKmuYZwd3pP6HI24LeLMWhJnkQ=
+github.com/libp2p/go-tcp-transport v0.0.4 h1:2iRu994wCT/iEz62F+c60FUoSkijNEQ0q2Itc+79XlQ=
+github.com/libp2p/go-tcp-transport v0.0.4/go.mod h1:+E8HvC8ezEVOxIo3V5vCK9l1y/19K427vCzQ+xHKH/o=
+github.com/libp2p/go-testutil v0.0.1 h1:Xg+O0G2HIMfHqBOBDcMS1iSZJ3GEcId4qOxCQvsGZHk=
+github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I=
+github.com/libp2p/go-ws-transport v0.0.1/go.mod h1:p3bKjDWHEgtuKKj+2OdPYs5dAPIjtpQGHF2tJfGz7Ww=
+github.com/libp2p/go-ws-transport v0.0.3/go.mod h1:iU0kzfMcO4tBVIk3z+7srp1YG/RFLWTSuO4enpivw8g=
+github.com/libp2p/go-ws-transport v0.0.4 h1:3wt9ed0gIUrne627XHvPMTwG4/AUpsLDy4TGQi2EyQ0=
+github.com/libp2p/go-ws-transport v0.0.4/go.mod h1:X9wfEcm2LAJYMox9x2VHAMHAZZSQMFC9mIa/UF6OuZk=
+github.com/libp2p/go-yamux v1.2.1/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
+github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
+github.com/libp2p/go-yamux v1.2.3 h1:xX8A36vpXb59frIzWFdEgptLMsOANMFq2K7fPRlunYI=
+github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
+github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
+github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH9J1c9oX6otFSgdUHwUBUizmKlrMjxWnIAjff4m04=
+github.com/lucas-clemente/quic-go v0.10.0/go.mod h1:wuD+2XqEx8G9jtwx5ou2BEYBsE+whgQmlj0Vz/77PrY=
+github.com/lucas-clemente/quic-go v0.11.1 h1:zasajC848Dqq/+WqfqBCkmPw+YHNe1MBts/z7y7nXf4=
+github.com/lucas-clemente/quic-go v0.11.1/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw=
+github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58=
+github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA=
+github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
+github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/miekg/dns v1.1.12 h1:WMhc1ik4LNkTg8U9l3hI1LvxKmIL+f1+WV/SZtCbDDA=
+github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
+github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
+github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
+github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5 h1:l16XLUUJ34wIz+RIvLhSwGvLvKyy+W598b135bJN6mg=
+github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
+github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mozilla/tls-observatory v0.0.0-20180409132520-8791a200eb40/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
+github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
+github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78=
+github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
+github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=
+github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
+github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
+github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
+github.com/multiformats/go-multiaddr v0.0.4 h1:WgMSI84/eRLdbptXMkMWDXPjPq7SPLIgGUVm2eroyU4=
+github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
+github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
+github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
+github.com/multiformats/go-multiaddr-dns v0.0.3 h1:P19q/k9jwmtgh+qXFkKfgFM7rCg/9l5AVqh7VNxSXhs=
+github.com/multiformats/go-multiaddr-dns v0.0.3/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
+github.com/multiformats/go-multiaddr-net v0.0.1 h1:76O59E3FavvHqNg7jvzWzsPSW5JSi/ek0E4eiDVbg9g=
+github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU=
+github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA=
+github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
+github.com/multiformats/go-multicodec v0.1.6 h1:4u6lcjbE4VVVoigU4QJSSVYsGVP4j2jtDkR8lPwOrLE=
+github.com/multiformats/go-multicodec v0.1.6/go.mod h1:lliaRHbcG8q33yf4Ot9BGD7JqR/Za9HE7HTyVyKwrUQ=
+github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
+github.com/multiformats/go-multihash v0.0.5 h1:1wxmCvTXAifAepIMyF39vZinRw5sbqjPs/UIi93+uik=
+github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=
+github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=
+github.com/multiformats/go-multistream v0.0.4 h1:rNgWgFyzRSTI9L+xISrz7kN5MdNXoEcoIeeCH05wLKA=
+github.com/multiformats/go-multistream v0.0.4/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-proto-validators v0.0.0-20190709101305-c00cd28f239a h1:I9kKjn0Q7yK5amJAqRBIVCGT81G8dXPJKxkwC6bkWWM=
+github.com/mwitkow/go-proto-validators v0.0.0-20190709101305-c00cd28f239a/go.mod h1:bA3eoTMLQkf/A7h7JOC3ddMBLXwS19KK7DEeSPL1O+4=
+github.com/nbutton23/zxcvbn-go v0.0.0-20160627004424-a22cb81b2ecd/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
+github.com/nbutton23/zxcvbn-go v0.0.0-20171102151520-eafdab6b0663/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
+github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992 h1:bzMe+2coZJYHnhGgVlcQKuRy4FSny4ds8dLQjw5P1XE=
+github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
+github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
+github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
+github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.0-20190519111021-9935e8e0588d h1:Z5QMcUKnQw7ouB1wDuyZM6TL/rm+brJcNk6Ai8ut3zM=
+github.com/prometheus/procfs v0.0.0-20190519111021-9935e8e0588d/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
+github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
+github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
+github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
+github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
+github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa h1:E+gaaifzi2xF65PbDmuKI3PhLWY6G5opMLniFq8vmXA=
+github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU=
+github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE=
+github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a h1:/eS3yfGjQKG+9kayBkj0ip1BGhq6zJ3eaVksphxAaek=
+github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0=
+github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=
+github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
+github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
+github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g=
+github.com/tyler-smith/go-bip39 v1.0.0 h1:FOHg9gaQLeBBRbHE/QrTLfEiBHy5pQ/yXzf9JG5pYFM=
+github.com/tyler-smith/go-bip39 v1.0.0/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436 h1:qOpVTI+BrstcjTZLm2Yz/3sOnqkzj3FQoh0g+E5s3Gc=
+github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
+github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4=
+github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM=
+github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0=
+github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11/go.mod h1:Wlo/SzPmxVp6vXpGt/zaXhHH0fn4IxgqZc82aKg6bpQ=
+github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E=
+github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8=
+github.com/whyrusleeping/go-ctrlnet v0.0.0-20180313164037-f564fbbdaa95/go.mod h1:SJqKCCPXRfBFCwXjfNT/skfsceF7+MBFLI2OrvuRA7g=
+github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=
+github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=
+github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc h1:9lDbC6Rz4bwmou+oE6Dt4Cb2BGMur5eR/GYptkKUVHo=
+github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
+github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f h1:M/lL30eFZTKnomXY6huvM6G0+gVquFNf6mxghaWlFUg=
+github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8=
+github.com/whyrusleeping/go-smux-multiplex v0.1.0/go.mod h1:OXL5hggHNZSsadXDlBJDD4eD3IQYEB3Yu6xpovd6pPw=
+github.com/whyrusleeping/go-smux-multiplex v3.0.16+incompatible/go.mod h1:34LEDbeKFZInPUrAG+bjuJmUXONGdEFW7XL0SpTY1y4=
+github.com/whyrusleeping/go-smux-multistream v0.1.0/go.mod h1:/usW3LIBirW4h9ko1PnoF7tExBnbxPBszG0n4wylJr8=
+github.com/whyrusleeping/go-smux-multistream v2.0.2+incompatible/go.mod h1:dRWHHvc4HDQSHh9gbKEBbUZ+f2Q8iZTPG3UOGYODxSQ=
+github.com/whyrusleeping/go-smux-yamux v0.1.1/go.mod h1:Yw+ayOEKERDHXLJ4GiE5AnBmldJW4QRLDzGFC9do8G0=
+github.com/whyrusleeping/go-smux-yamux v2.0.8+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI=
+github.com/whyrusleeping/go-smux-yamux v2.0.9+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI=
+github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1/go.mod h1:tKH72zYNt/exx6/5IQO6L9LoQ0rEjd5SbbWaDTs9Zso=
+github.com/whyrusleeping/mafmt v1.2.8 h1:TCghSl5kkwEE0j+sU/gudyhVMRlpBin8fMBBHg59EbA=
+github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA=
+github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30 h1:nMCC9Pwz1pxfC1Y6mYncdk+kq8d5aLx0Q+/gyZGE44M=
+github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=
+github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds=
+github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=
+github.com/whyrusleeping/tar-utils v0.0.0-20180509141711-8c6c8ba81d5c h1:GGsyl0dZ2jJgVT+VvWBf/cNijrHRhkrTjkmp5wg7li0=
+github.com/whyrusleeping/tar-utils v0.0.0-20180509141711-8c6c8ba81d5c/go.mod h1:xxcJeBb7SIUl/Wzkz1eVKJE/CB34YNrqX2TQI6jY9zs=
+github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow=
+github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg=
+github.com/whyrusleeping/yamux v1.1.5/go.mod h1:E8LnQQ8HKx5KD29HZFUwM1PxCOdPRzGwur1mcYhXcD8=
+github.com/whyrusleeping/yamux v1.2.0/go.mod h1:Cgw3gpb4DrDZ1FrP/5pxg/cpiY54Gr5uCXwUylwi2GE=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/dig v1.7.0 h1:E5/L92iQTNJTjfgJF2KgU+/JpMaiuvK2DHLBj0+kSZk=
+go.uber.org/dig v1.7.0/go.mod h1:z+dSd2TP9Usi48jL8M3v63iSBVkiwtVyMKxMZYYauPg=
+go.uber.org/fx v1.9.0 h1:7OAz8ucp35AU8eydejpYG7QrbE8rLKzGhHbZlJi5LYY=
+go.uber.org/fx v1.9.0/go.mod h1:mFdUyAUuJ3w4jAckiKSKbldsxy1ojpAMJ+dVZg5Y0Aw=
+go.uber.org/goleak v0.10.0 h1:G3eWbSNIskeRqtsN/1uI5B+eP73y3JUuBsv9AZjehb4=
+go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=
+go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go4.org v0.0.0-20190218023631-ce4c26f7be8e/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
+go4.org v0.0.0-20190313082347-94abd6928b1d h1:JkRdGP3zvTtTbabWSAC6n67ka30y7gOzWAah4XYJSfw=
+go4.org v0.0.0-20190313082347-94abd6928b1d/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
+golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20180426230345-b49d69b5da94/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo=
+golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190310074541-c10a0554eabf/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190522135303-fa69b94a3b58/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20171026204733-164713f0dfce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k=
+golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.0.0-20170915090833-1cbadb444a80/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/tools v0.0.0-20170915040203-e531a2a1c15f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181205014116-22934f0fdb62/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190121143147-24cd39ecf745/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190420000508-685fecacd0a0/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/xerrors v0.0.0-20190212162355-a5947ffaace3/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522 h1:bhOzK9QyoD0ogCnFro1m2mz41+Ib0oOhfJnBp5MR4K4=
+golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
+gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
+gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
+gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
+gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
+gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
+gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+gotest.tools/gotestsum v0.3.4/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
+mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
+mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34/go.mod h1:H6SUd1XjIs+qQCyskXg5OFSrilMRUkD8ePJpHKDPaeY=
+sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
diff --git a/libs/crypto/libpqnist/CMakeLists.txt b/libs/crypto/libpqnist/CMakeLists.txt
new file mode 100644
index 0000000..76e5db2
--- /dev/null
+++ b/libs/crypto/libpqnist/CMakeLists.txt
@@ -0,0 +1,104 @@
+cmake_minimum_required (VERSION 3.1 FATAL_ERROR)
+project (libpqnist)
+
+# Helper Macros
+macro(log var)
+  message(STATUS "${var}: ${${var}}")
+endmacro()
+
+# Includes
+include(CTest)
+include(GNUInstallDirs)
+
+# Extract version from the VERSION file
+file(STRINGS VERSION VERSION_FILE_CONTENT)
+string(REPLACE "." ";" VERSION_FILE_PARTS ${VERSION_FILE_CONTENT})
+list(GET VERSION_FILE_PARTS 0 VERSION_MAJOR)
+list(GET VERSION_FILE_PARTS 1 VERSION_MINOR)
+list(GET VERSION_FILE_PARTS 2 VERSION_PATCH)
+set(BUILD_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
+log(BUILD_VERSION)
+log(CMAKE_GENERATOR)
+
+# Add options for build
+option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
+log(BUILD_SHARED_LIBS)
+log(BUILD_TESTING) # added by 'include(CTest)'
+
+# Allow the developer to select if Dynamic or Static libraries are built
+# Set the default LIB_TYPE variable to STATIC
+SET (LIB_TYPE STATIC)
+IF (BUILD_SHARED_LIBS)
+  # User wants to build Dynamic Libraries, so change the LIB_TYPE variable to CMake keyword 'SHARED'
+  SET (LIB_TYPE SHARED)
+ENDIF (BUILD_SHARED_LIBS)
+
+# Configure build
+set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}
+    CACHE STRING "Choose the type of build: Debug Release Coverage ASan Check CheckFull"
+    FORCE)
+
+# Set a default build type if none was specified
+if(NOT CMAKE_BUILD_TYPE)
+  message(STATUS "Setting build type to 'Release' as none was specified.")
+  set(CMAKE_BUILD_TYPE Release)
+endif(NOT CMAKE_BUILD_TYPE)
+log(CMAKE_BUILD_TYPE)
+
+if(CMAKE_COMPILER_IS_GNUCC)
+    execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
+                    OUTPUT_VARIABLE GCC_VERSION)
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-strict-prototypes -Wunused-value -Wcast-align -Wunused-variable -Wundef -Wformat-security -Wno-pointer-sign -Wno-unknown-pragmas")
+
+    if (GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
+        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow")
+        set(CMAKE_C_FLAGS_ASAN    "-O0 -g3 -fsanitize=address")
+    else (GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
+        message(STATUS "GCC 4.8 required to run address sanitizer - please upgrade your installation")
+    endif(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
+
+    IF (BUILD_SHARED_LIBS)
+        set(CMAKE_C_FLAGS_RELEASE     "-O2")
+        set(CMAKE_C_FLAGS_DEBUG       "-O0 -g3 -D DEBUG")
+        set(CMAKE_C_FLAGS_COVERAGE    "-O0 -g3 --coverage")
+    else(BUILD_SHARED_LIBS)
+        set(CMAKE_C_FLAGS_RELEASE     "-static -O2")
+        set(CMAKE_C_FLAGS_DEBUG       "-static -O0 -g3 -D DEBUG")
+        set(CMAKE_C_FLAGS_COVERAGE    "-static -O0 -g3 --coverage")
+    endif(BUILD_SHARED_LIBS)    
+
+endif(CMAKE_COMPILER_IS_GNUCC)
+
+if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
+    set(CMAKE_SHARED_LINKER_FLAGS "--coverage")
+endif(CMAKE_BUILD_TYPE STREQUAL "Coverage")
+
+log(CMAKE_INSTALL_PREFIX)
+
+# /include subdir
+set(INSTALL_INCLUDESUBDIR "${CMAKE_INSTALL_INCLUDEDIR}/amcl")
+log(CMAKE_INSTALL_INCLUDEDIR)
+log(INSTALL_INCLUDESUBDIR)
+
+# Add subdirectories
+add_subdirectory(include)
+add_subdirectory(src)
+add_subdirectory(examples)
+
+if(BUILD_TESTING)
+  message(STATUS "Build tests")
+  add_subdirectory(test/smoke)
+  add_subdirectory(test/unit)  
+endif()
+
+# uninstall target
+configure_file(
+    "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
+    "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
+    IMMEDIATE @ONLY)
+
+add_custom_target(uninstall
+    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
+
+include(CPackConfig.cmake)
+
diff --git a/libs/crypto/libpqnist/CPackConfig.cmake b/libs/crypto/libpqnist/CPackConfig.cmake
new file mode 100644
index 0000000..8101755
--- /dev/null
+++ b/libs/crypto/libpqnist/CPackConfig.cmake
@@ -0,0 +1,33 @@
+include (InstallRequiredSystemLibraries)
+
+########################### General Settings ###########################
+set(CPACK_PACKAGE_NAME "MILAGRO")
+set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
+set(CPACK_PACKAGE_RELEASE 1)
+set(CPACK_DESCRIPTION_SUMMARY "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
+set(CPACK_PACKAGE_VENDOR "MILAGRO")
+set(CPACK_PACKAGE_CONTACT "dev@milagro.apache.org")
+set(CPACK_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}")
+
+if (BUILD_PYTHON)
+  set(CPACK_RPM_PACKAGE_REQUIRES "python >= 2.7.0")
+endif (BUILD_PYTHON)
+
+set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_RELEASE}.${CMAKE_SYSTEM_PROCESSOR}")
+
+########################### Linux Settings ###########################
+if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+  set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
+
+  # Prevents CPack from generating file conflicts
+  set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${CPACK_PACKAGING_INSTALL_PREFIX}")
+  list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${CPACK_PACKAGING_INSTALL_PREFIX}/bin")
+  list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${CPACK_PACKAGING_INSTALL_PREFIX}/include")
+  list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${CPACK_PACKAGING_INSTALL_PREFIX}/lib")
+  list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${PYTHON_SITE_LIB}")
+  list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${PYTHON_SITE_PACKAGES}")
+  set(CPACK_GENERATOR "RPM")
+endif()
+
+include (CPack)
diff --git a/libs/crypto/libpqnist/LICENSE b/libs/crypto/libpqnist/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/libs/crypto/libpqnist/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file
diff --git a/libs/crypto/libpqnist/VERSION b/libs/crypto/libpqnist/VERSION
new file mode 100644
index 0000000..f0bb29e
--- /dev/null
+++ b/libs/crypto/libpqnist/VERSION
@@ -0,0 +1 @@
+1.3.0
diff --git a/libs/crypto/libpqnist/cmake_uninstall.cmake.in b/libs/crypto/libpqnist/cmake_uninstall.cmake.in
new file mode 100644
index 0000000..2037e36
--- /dev/null
+++ b/libs/crypto/libpqnist/cmake_uninstall.cmake.in
@@ -0,0 +1,21 @@
+if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+  message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+string(REGEX REPLACE "\n" ";" files "${files}")
+foreach(file ${files})
+  message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
+  if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+    exec_program(
+      "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+      OUTPUT_VARIABLE rm_out
+      RETURN_VALUE rm_retval
+      )
+    if(NOT "${rm_retval}" STREQUAL 0)
+      message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
+    endif(NOT "${rm_retval}" STREQUAL 0)
+  else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+    message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
+  endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+endforeach(file)
diff --git a/libs/crypto/libpqnist/examples/CMakeLists.txt b/libs/crypto/libpqnist/examples/CMakeLists.txt
new file mode 100644
index 0000000..b8ff74b
--- /dev/null
+++ b/libs/crypto/libpqnist/examples/CMakeLists.txt
@@ -0,0 +1,37 @@
+# List of examples
+file(GLOB_RECURSE SRCS *.c)
+
+# List of multithreaded examples 
+SET (SRCSTHREAD run_encap_decap.c run_bls.c)
+
+# Add the binary tree directory to the search path for linking and include files
+link_directories (${PROJECT_BINARY_DIR}/src
+                  /usr/local/lib)
+
+include_directories (${PROJECT_SOURCE_DIR}/include
+                     /usr/local/include)
+
+# Examples that are not multi-threaded
+foreach(example ${SRCS})
+  # Extract the filename without an extension
+  get_filename_component(target ${example} NAME_WE)
+
+  add_executable(${target} ${example})
+
+  target_link_libraries(${target} pqnist)
+endforeach(example)
+
+# Examples that are multi-threaded
+if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+  foreach(example ${SRCSTHREAD})
+    # Extract the filename without an extension
+    get_filename_component(base ${example} NAME_WE)
+    set(target ${base}_threads)
+
+    add_executable(${target} ${example})
+
+    target_compile_options(${target} PUBLIC -pthread -fopenmp)
+
+    target_link_libraries(${target} pqnist -fopenmp)
+  endforeach(example)
+endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
diff --git a/libs/crypto/libpqnist/examples/run_aescbc.c b/libs/crypto/libpqnist/examples/run_aescbc.c
new file mode 100644
index 0000000..6722c46
--- /dev/null
+++ b/libs/crypto/libpqnist/examples/run_aescbc.c
@@ -0,0 +1,137 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   Run AES-256 encryption and decryption in CBC mode
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/pqnist.h>
+
+int main()
+{
+    int i;
+
+    // Seed value for CSPRNG
+    char seed[PQNIST_SEED_LENGTH];
+    octet SEED = {sizeof(seed),sizeof(seed),seed};
+
+    csprng RNG;
+
+    // AES Key
+    char k[PQNIST_AES_KEY_LENGTH];
+    octet K= {sizeof(k),sizeof(k),k};
+
+    // Initialization vector
+    char iv[PQNIST_AES_IV_LENGTH];
+    octet IV= {sizeof(iv),sizeof(iv),iv};
+
+    // Message to be sent to Bob
+    char p[256];
+    octet P = {0, sizeof(p), p};
+    // OCT_jstring(&P,"Hello Bob!");
+    OCT_jstring(&P,"Hello Bob! This is a message from Alice");
+
+    // non random seed value
+    for (i=0; i<PQNIST_SEED_LENGTH; i++) SEED.val[i]=i+1;
+    printf("SEED: ");
+    OCT_output(&SEED);
+    printf("\n");
+
+    // initialise random number generator
+    CREATE_CSPRNG(&RNG,&SEED);
+
+    // Generate 256 bit AES Key
+    generateRandom(&RNG,&K);
+
+    // Alice
+
+    printf("Alice Key: ");
+    amcl_print_hex(K.val, K.len);
+
+    // Random initialization value
+    generateRandom(&RNG,&IV);
+    printf("Alice IV: ");
+    OCT_output(&IV);
+
+    printf("Alice Plaintext: ");
+    OCT_output(&P);
+
+    printf("Alice Plaintext: ");
+    OCT_output_string(&P);
+    printf("\n");
+    printf("Alice Pliantext hex:");
+    OCT_output(&P);
+
+    printf("PLAINTEXTLen = %d blocks %0.2f \n", P.len, (float) P.len/16);
+
+    // Pad message
+    int l = 16 - (P.len % 16);
+    if (l < 16)
+    {
+        OCT_jbyte(&P,0,l);
+    }
+
+    printf("Alice Plaintext: ");
+    OCT_output_string(&P);
+    printf("\n");
+    printf("Alice Pliantext hex:");
+    OCT_output(&P);
+
+    printf("PLAINTEXTLen = %d blocks %0.2f \n", P.len, (float) P.len/16);
+
+    // Encrypt plaintext
+    pqnist_aes_cbc_encrypt(K.val, K.len, IV.val, P.val, P.len);
+
+    printf("Alice: Ciphertext: ");
+    OCT_output(&P);
+
+    // Bob
+
+    printf("Bob Key: ");
+    amcl_print_hex(K.val, K.len);
+
+    printf("Bob IV ");
+    OCT_output(&IV);
+
+    printf("Bob Ciphertext: ");
+    OCT_output(&P);
+
+    pqnist_aes_cbc_decrypt(K.val, K.len, IV.val, P.val, P.len);
+
+    printf("Bob Plaintext: ");
+    OCT_output(&P);
+
+    printf("Bob Plaintext: ");
+    OCT_output_string(&P);
+    printf("\n");
+
+    /* clear memory */
+    OCT_clear(&K);
+    OCT_clear(&IV);
+    OCT_clear(&P);
+
+    KILL_CSPRNG(&RNG);
+
+    return 0;
+}
diff --git a/libs/crypto/libpqnist/examples/run_aesgcm.c b/libs/crypto/libpqnist/examples/run_aesgcm.c
new file mode 100644
index 0000000..1f0be67
--- /dev/null
+++ b/libs/crypto/libpqnist/examples/run_aesgcm.c
@@ -0,0 +1,177 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   Run AES-256 encryption and decryption in GCM mode
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/pqnist.h>
+
+#define Keylen 32
+#define IVlen 12
+#define Taglen 12
+
+int main()
+{
+    int i;
+
+    // Seed value for CSPRNG
+    char seed[PQNIST_SEED_LENGTH];
+    octet SEED = {sizeof(seed),sizeof(seed),seed};
+
+    csprng RNG;
+
+    // Alice's authentication Tag
+    char t1[Taglen];
+    octet T1= {sizeof(t1),sizeof(t1),t1};
+
+    // Bob's authentication Tag
+    char t2[Taglen];
+    octet T2= {sizeof(t2),sizeof(t2),t2};
+
+    // AES Key
+    char k[Keylen];
+    octet K= {0,sizeof(k),k};
+
+    // Initialization vector
+    char iv[IVlen];
+    octet IV= {0,sizeof(iv),iv};
+
+    // Ciphertext
+    char c[256];
+    octet C= {0,sizeof(c),c};
+
+    // Recovered plaintext
+    char p2[256];
+    octet P2= {0,sizeof(p2),p2};
+
+    // Message to be sent to Bob
+    char p1[256];
+    octet P1 = {0, sizeof(p1), p1};
+    OCT_jstring(&P1,"Hello Bob!");
+
+    // Additional authenticated data (AAD)
+    char aad[256];
+    octet AAD = {0, sizeof(aad), aad};
+    OCT_jstring(&AAD,"Header info");
+
+    // non random seed value
+    for (i=0; i<PQNIST_SEED_LENGTH; i++) SEED.val[i]=i+1;
+    printf("SEED: ");
+    OCT_output(&SEED);
+    printf("\n");
+
+    // initialise random number generator
+    CREATE_CSPRNG(&RNG,&SEED);
+
+    // Generate 256 bit AES Key
+    K.len=Keylen;
+    generateRandom(&RNG,&K);
+
+    // Alice
+
+    printf("Alice Key: ");
+    amcl_print_hex(K.val, K.len);
+
+    // Random initialization value
+    IV.len=IVlen;
+    generateRandom(&RNG,&IV);
+    printf("Alice IV: ");
+    OCT_output(&IV);
+
+    printf("Alice AAD: ");
+    OCT_output(&AAD);
+
+    printf("Alice Plaintext: ");
+    OCT_output(&P1);
+
+    printf("Alice Plaintext: ");
+    OCT_output_string(&P1);
+    printf("\n");
+
+    // Encrypt plaintext
+    pqnist_aes_gcm_encrypt(K.val, K.len, IV.val, IV.len, AAD.val, AAD.len, P1.val, P1.len, C.val, T1.val);
+
+    C.len = P1.len;
+    printf("Alice: Ciphertext: ");
+    OCT_output(&C);
+
+    T1.len = Taglen;
+    printf("Alice Tag: ");
+    OCT_output(&T1);
+    printf("\n");
+
+    // Bob
+
+    printf("Bob Key: ");
+    amcl_print_hex(K.val, K.len);
+
+    printf("Bob IV ");
+    OCT_output(&IV);
+
+    printf("Bob AAD: ");
+    OCT_output(&AAD);
+
+    printf("Bob Ciphertext: ");
+    OCT_output(&C);
+
+    pqnist_aes_gcm_decrypt(K.val, K.len, IV.val, IVlen, AAD.val, AAD.len, C.val, C.len, P2.val, T2.val);
+
+    printf("Bob Plaintext: ");
+    P2.len = C.len;
+    OCT_output(&P2);
+
+    printf("Bob Plaintext: ");
+    OCT_output_string(&P2);
+    printf("\n");
+
+    printf("Bob Tag: ");
+    T2.len = Taglen;
+    OCT_output(&T2);
+
+    if (!OCT_comp(&P1,&P2))
+    {
+        printf("FAILURE Decryption");
+        return 1;
+    }
+
+    if (!OCT_comp(&T1,&T2))
+    {
+        printf("FAILURE TAG mismatch");
+        return 1;
+    }
+
+    /* clear memory */
+    OCT_clear(&T1);
+    OCT_clear(&T2);
+    OCT_clear(&K);
+    OCT_clear(&IV);
+    OCT_clear(&C);
+    OCT_clear(&P1);
+    OCT_clear(&P2);
+
+    KILL_CSPRNG(&RNG);
+
+    return 0;
+}
diff --git a/libs/crypto/libpqnist/examples/run_bls.c b/libs/crypto/libpqnist/examples/run_bls.c
new file mode 100644
index 0000000..838ae92
--- /dev/null
+++ b/libs/crypto/libpqnist/examples/run_bls.c
@@ -0,0 +1,152 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   BLS sign a message and verify the signature
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/bls_BLS381.h>
+#include <amcl/pqnist.h>
+
+#define NTHREADS 8
+#define MAXSIZE 256
+
+#define G2LEN 4*BFS_BLS381
+#define SIGLEN BFS_BLS381+1
+
+int main()
+{
+    int i,rc;
+
+    // Seed value for CSPRNG
+    char seed[NTHREADS][PQNIST_SEED_LENGTH];
+
+    // Message to be sent to Bob
+    char p[NTHREADS][MAXSIZE];
+    octet P[NTHREADS];
+
+    // BLS signature
+    char s[NTHREADS][SIGLEN];
+    octet S[NTHREADS];
+
+    // Initialise seed
+    for(i=0; i<NTHREADS; i++)
+    {
+        for(int j=0; j<PQNIST_SEED_LENGTH; j++)
+        {
+            seed[i][j] = i;
+        }
+    }
+
+    // Generate BLS keys
+
+    // Alice's BLS keys
+    char BLSsk[NTHREADS][BGS_BLS381];
+    char BLSpk[NTHREADS][G2LEN];
+
+    #pragma omp parallel for
+    for(i=0; i<NTHREADS; i++)
+    {
+
+        rc = pqnist_bls_keys(seed[i], BLSpk[i], BLSsk[i]);
+        if (rc)
+        {
+            fprintf(stderr, "ERROR pqnist_keys rc: %d\n", rc);
+            exit(EXIT_FAILURE);
+        }
+
+        printf("BLS pklen %d pk: ", G2LEN);
+        amcl_print_hex(BLSpk[i], G2LEN);
+        printf("BLS sklen %d BLS sk: ", BGS_BLS381);
+        amcl_print_hex(BLSsk[i], BGS_BLS381);
+        printf("\n");
+
+    }
+
+    // Alice
+
+    for(i=0; i<NTHREADS; i++)
+    {
+        bzero(p[i],sizeof(p[i]));
+        P[i].max = MAXSIZE;
+        P[i].len = sprintf(p[i], "Hello Bob! This is a message from Alice %d", i);
+        P[i].val = p[i];
+        printf("Alice Plaintext: ");
+        OCT_output_string(&P[i]);
+        printf("\n");
+    }
+
+    for(i=0; i<NTHREADS; i++)
+    {
+        bzero(s[i],sizeof(s[i]));
+        S[i].max = SIGLEN;
+        S[i].len = SIGLEN;
+        S[i].val = s[i];
+    }
+
+    #pragma omp parallel for
+    for(i=0; i<NTHREADS; i++)
+    {
+        // Alice signs message
+        rc = pqnist_bls_sign(P[i].val, BLSsk[i], S[i].val);
+        if(rc)
+        {
+            fprintf(stderr, "ERROR pqnist_bls_sign rc: %d\n", rc);
+            printf("FAILURE\n");
+            exit(EXIT_FAILURE);
+        }
+
+        printf("Alice SIGlen %d  SIG", S[i].len);
+        OCT_output(&S[i]);
+        printf("\n");
+    }
+
+    #pragma omp parallel for
+    for(i=0; i<NTHREADS; i++)
+    {
+        // Bob verifies message
+        rc = pqnist_bls_verify(P[i].val, BLSpk[i], S[i].val);
+        if (rc)
+        {
+            fprintf(stderr, "ERROR pqnist_bls_verify rc: %d\n", rc);
+            exit(EXIT_FAILURE);
+        }
+        else
+        {
+            printf("SUCCESS Test %d pqnist_bls_verify rc: %d\n", i, rc);
+            OCT_output_string(&P[i]);
+            printf("\n");
+        }
+    }
+
+    // clear memory
+    for(i=0; i<NTHREADS; i++)
+    {
+        OCT_clear(&P[i]);
+        OCT_clear(&S[i]);
+    }
+
+    printf("TEST PASSED\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/examples/run_bls_add.c b/libs/crypto/libpqnist/examples/run_bls_add.c
new file mode 100644
index 0000000..516a85e
--- /dev/null
+++ b/libs/crypto/libpqnist/examples/run_bls_add.c
@@ -0,0 +1,173 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   Sign a message and verify the signature. 
+   Generate a public key from externally generated secret key
+   Add public keys and signatures.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/bls_BLS381.h>
+#include <amcl/pqnist.h>
+
+#define G2LEN 4*BFS_BLS381
+#define SIGLEN BFS_BLS381+1
+
+int main()
+{
+    int rc;
+
+    // Message to be signed
+    char message[] = "test message";
+
+    // Seed values for CSPRNG
+    char seed1[PQNIST_SEED_LENGTH];
+    char seed2[PQNIST_SEED_LENGTH];
+
+    // seed values
+    char* seed1Hex = "3370f613c4fe81130b846483c99c032c17dcc1904806cc719ed824351c87b0485c05089aa34ba1e1c6bfb6d72269b150";
+    char* seed2Hex = "46389f32b7cdebbbc46b7165d8fae888c9de444898390a939977e1a066256a6f465e7d76307178aef81ae0c6841f9b7c";
+    amcl_hex2bin(seed1Hex, seed1, PQNIST_SEED_LENGTH*2);
+    amcl_hex2bin(seed2Hex, seed2, PQNIST_SEED_LENGTH*2);
+    printf("seed1: ");
+    amcl_print_hex(seed1, PQNIST_SEED_LENGTH);
+    printf("seed2: ");
+    amcl_print_hex(seed2, PQNIST_SEED_LENGTH);
+    printf("\n");
+
+    // BLS keys
+    char sk1[BGS_BLS381];
+    char pktmp[G2LEN];
+    char pk1[G2LEN];    
+    char sk2[BGS_BLS381];
+    char pk2[G2LEN];
+    char pk12[G2LEN];
+
+    // BLS signature
+    char sig1[SIGLEN];
+    char sig2[SIGLEN];
+    char sig12[SIGLEN];
+
+    rc = pqnist_bls_keys(seed1, pktmp, sk1);
+    if (rc)
+    {
+        fprintf(stderr, "ERROR pqnist_keys rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = pqnist_bls_keys(seed2, pk2, sk2);
+    if (rc)
+    {
+        fprintf(stderr, "ERROR pqnist_keys rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    // Generate pk from sk 
+    rc = pqnist_bls_keys(NULL, pk1, sk1);
+    if (rc)
+    {
+        fprintf(stderr, "ERROR pqnist_keys rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("sk1: ");
+    amcl_print_hex(sk1, BGS_BLS381);    
+    printf("pktmp: ");
+    amcl_print_hex(pktmp, G2LEN);
+    printf("pk1: ");
+    amcl_print_hex(pk1, G2LEN);
+    printf("sk2: ");
+    amcl_print_hex(sk2, BGS_BLS381);    
+    printf("pk2: ");
+    amcl_print_hex(pk2, G2LEN);
+    printf("\n");
+
+    // Sign message
+    rc = pqnist_bls_sign(message, sk1, sig1);
+    if(rc != BLS_OK)
+    {
+        fprintf(stderr, "ERROR pqnist_bls_sign rc: %d\n", rc);
+        printf("FAILURE\n");
+        exit(EXIT_FAILURE);
+    }
+
+    rc = pqnist_bls_sign(message, sk2, sig2);
+    if(rc != BLS_OK)
+    {
+        fprintf(stderr, "ERROR pqnist_bls_sign rc: %d\n", rc);
+        printf("FAILURE\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("sig1: ");
+    amcl_print_hex(sig1, SIGLEN);
+    printf("sig2: ");
+    amcl_print_hex(sig2, SIGLEN);
+    printf("\n");
+
+    // Verify message
+    rc = pqnist_bls_verify(message, pk1, sig1);
+    if (rc != BLS_OK)
+    {
+        fprintf(stderr, "ERROR pqnist_bls_verify rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = pqnist_bls_verify(message, pk2, sig2);
+    if (rc != BLS_OK)
+    {
+        fprintf(stderr, "ERROR pqnist_bls_verify rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = pqnist_bls_addg1(sig1, sig2, sig12);
+    if (rc != BLS_OK)
+    {
+        fprintf(stderr, "ERROR pqnist_bls_addg1 rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = pqnist_bls_addg2(pk1, pk2, pk12);
+    if (rc != BLS_OK)
+    {
+        fprintf(stderr, "ERROR pqnist_bls_addg1 rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("pk12: ");
+    amcl_print_hex(pk12, G2LEN);
+    printf("sig12: ");
+    amcl_print_hex(sig12, SIGLEN);
+    printf("\n");
+
+    rc = pqnist_bls_verify(message, pk12, sig12);
+    if (rc != BLS_OK)
+    {
+        fprintf(stderr, "ERROR pqnist_bls_verify rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("TEST PASSED\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/examples/run_bls_bad.c b/libs/crypto/libpqnist/examples/run_bls_bad.c
new file mode 100644
index 0000000..a063609
--- /dev/null
+++ b/libs/crypto/libpqnist/examples/run_bls_bad.c
@@ -0,0 +1,158 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   BLS sign a message and verify the signature. Introduce errors.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/bls_BLS381.h>
+#include <amcl/pqnist.h>
+
+#define G2LEN 4*BFS_BLS381
+#define SIGLEN BFS_BLS381+1
+
+int main()
+{
+    int i,rc;
+
+    // Seed value for CSPRNG
+    char seed[PQNIST_SEED_LENGTH];
+
+    // Message to be sent to Bob
+    char p[] = "Hello Bob! This is a message from Alice";
+    octet P = {0, sizeof(p), p};
+
+    // non random seed value
+    for (i=0; i<PQNIST_SEED_LENGTH; i++) seed[i]=i+1;
+    printf("SEED: ");
+    amcl_print_hex(seed, PQNIST_AES_KEY_LENGTH);
+    printf("\n");
+
+    // Generate BLS keys
+
+    // Alice's BLS keys
+    char BLSsk[BGS_BLS381];
+    char BLSpk[G2LEN];
+
+    rc = pqnist_bls_keys(seed, BLSpk, BLSsk);
+    if (rc)
+    {
+        fprintf(stderr, "ERROR pqnist_keys rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("BLS pklen %d pk: ", G2LEN);
+    amcl_print_hex(BLSpk, G2LEN);
+    printf("BLS sklen %d BLS sk: ", BGS_BLS381);
+    amcl_print_hex(BLSsk, BGS_BLS381);
+    printf("\n");
+
+    // BLS signature
+    char S[SIGLEN];
+
+    // Alice signs message
+    rc = pqnist_bls_sign(P.val, BLSsk, S);
+    if(rc != BLS_OK)
+    {
+        fprintf(stderr, "ERROR pqnist_bls_sign rc: %d\n", rc);
+        printf("FAILURE\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("Alice Slen %d SIG", SIGLEN);
+    amcl_print_hex(S, SIGLEN);
+    printf("\n");
+
+    // Bob verifies message
+    rc = pqnist_bls_verify(P.val, BLSpk, S);
+    if (rc == BLS_OK)
+    {
+        printf("SUCCESS pqnist_bls_verify rc: %d\n", rc);
+    }
+    else
+    {
+        fprintf(stderr, "ERROR pqnist_bls_verify rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+
+    printf("Bob P ");
+    OCT_output(&P);
+    printf("\n");
+
+    // Bob verifies corrupted message. This should fail
+    char tmp = P.val[0];
+    P.val[0] = 5;
+    rc = pqnist_bls_verify(P.val, BLSpk, S);
+    if (rc == BLS_FAIL)
+    {
+        fprintf(stderr, "ERROR pqnist_bls_verify rc: %d\n", rc);
+    }
+    else
+    {
+        printf("SUCCESS pqnist_bls_verify rc: %d\n", rc);
+        printf("TEST FAILED\n");
+        exit(EXIT_FAILURE);
+    }
+
+    // Fix message
+    P.val[0] = tmp;
+    printf("Bob P ");
+    OCT_output(&P);
+    printf("\n");
+
+    // Check signature is correct
+    rc = pqnist_bls_verify(P.val, BLSpk, S);
+    if (rc == BLS_OK)
+    {
+        printf("SUCCESS pqnist_bls_verify rc: %d\n", rc);
+    }
+    else
+    {
+        fprintf(stderr, "ERROR pqnist_bls_verify rc: %d\n", rc);
+        printf("TEST FAILED\n");
+        exit(EXIT_FAILURE);
+    }
+
+    // Bob verifies corrupted signature. This should fail
+    S[0] = 0;
+    rc = pqnist_bls_verify(P.val, BLSpk, S);
+    if (rc == BLS_INVALID_G1)
+    {
+
+        fprintf(stderr, "ERROR pqnist_bls_verify rc: %d\n", rc);
+    }
+    else
+    {
+        printf("SUCCESS pqnist_bls_verify rc: %d\n", rc);
+        printf("TEST FAILED\n");
+        exit(EXIT_FAILURE);
+    }
+
+    // clear memory
+    OCT_clear(&P);
+
+    printf("TEST PASSED\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/examples/run_bls_sss.c b/libs/crypto/libpqnist/examples/run_bls_sss.c
new file mode 100644
index 0000000..53b880b
--- /dev/null
+++ b/libs/crypto/libpqnist/examples/run_bls_sss.c
@@ -0,0 +1,176 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   BLS SSS example
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/bls_BLS381.h>
+#include <amcl/pqnist.h>
+
+#define G2LEN 4*BFS_BLS381
+#define SIGLEN BFS_BLS381+1
+
+int main()
+{
+    int rc;
+    int n=4;
+    int k=3;
+
+    // Message to be signed
+    char message[] = "test message";
+
+    // Seed value for CSPRNG
+    char seed1[PQNIST_SEED_LENGTH];
+    char seed2[PQNIST_SEED_LENGTH];
+
+    // seed values
+    char* seed1Hex = "3370f613c4fe81130b846483c99c032c17dcc1904806cc719ed824351c87b0485c05089aa34ba1e1c6bfb6d72269b150";
+    char* seed2Hex = "46389f32b7cdebbbc46b7165d8fae888c9de444898390a939977e1a066256a6f465e7d76307178aef81ae0c6841f9b7c";
+    amcl_hex2bin(seed1Hex, seed1, PQNIST_SEED_LENGTH*2);
+    amcl_hex2bin(seed2Hex, seed2, PQNIST_SEED_LENGTH*2);
+    printf("seed1: ");
+    amcl_print_hex(seed1, PQNIST_SEED_LENGTH);
+    printf("\n");
+    printf("seed2: ");
+    amcl_print_hex(seed2, PQNIST_SEED_LENGTH);
+    printf("\n");
+
+    // BLS keys
+    char ski[BGS_BLS381];
+    char sko[BGS_BLS381];
+    char skr[BGS_BLS381];
+    char pki[G2LEN];
+
+    rc = pqnist_bls_keys(seed1, pki, ski);
+    if (rc)
+    {
+        fprintf(stderr, "ERROR pqnist_keys rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("pki: ");
+    amcl_print_hex(pki, G2LEN);
+    printf("ski: ");
+    amcl_print_hex(ski, BGS_BLS381);
+    printf("\n");
+
+    // BLS signature
+    char sigi[SIGLEN];
+
+    // Sign message
+    rc = pqnist_bls_sign(message, ski, sigi);
+    if(rc != BLS_OK)
+    {
+        fprintf(stderr, "ERROR pqnist_bls_sign rc: %d\n", rc);
+        printf("FAILURE\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("sigi ");
+    amcl_print_hex(sigi, SIGLEN);
+    printf("\n");
+
+    // Verify signature
+    rc = pqnist_bls_verify(message, pki, sigi);
+    if (rc == BLS_OK)
+    {
+        printf("SUCCESS pqnist_bls_verify rc: %d\n", rc);
+    }
+    else
+    {
+        fprintf(stderr, "ERROR pqnist_bls_verify rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    // Secret shares
+    char x[BGS_BLS381*n];
+    char y[BGS_BLS381*n];
+
+    // Make shares of BLS secret key
+    rc = pqnist_bls_make_shares(k, n, seed2, x, y, ski, sko);
+    if (rc!=BLS_OK)
+    {
+        fprintf(stderr, "ERROR pqnist_bls_make_shares rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("ski: ");
+    amcl_print_hex(ski, BGS_BLS381);
+    printf("sko: ");
+    amcl_print_hex(sko, BGS_BLS381);
+    printf("\n");
+
+    for(int i=0; i<n; i++)
+    {
+        printf("x[%d] ", i);
+        amcl_print_hex(&x[i*BGS_BLS381], BGS_BLS381);
+        printf("y[%d] ", i);
+        amcl_print_hex(&y[i*BGS_BLS381], BGS_BLS381);
+        printf("\n");
+    }
+
+    // Recover BLS secret key
+    rc = pqnist_bls_recover_secret(k, x, y, skr);
+    if (rc!=BLS_OK)
+    {
+        fprintf(stderr, "ERROR pqnist_bls_recover_secret rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+    printf("skr: ");
+    amcl_print_hex(skr, BGS_BLS381);
+    printf("\n");
+
+    // Generate public keys and signatures using shares
+    char sigs[(SIGLEN)*n];
+    char sigr[SIGLEN];
+    for(int i=0; i<n; i++)
+    {
+        rc = pqnist_bls_sign(message, &y[BFS_BLS381*i], &sigs[(SIGLEN)*i]);
+        if(rc != BLS_OK)
+        {
+            fprintf(stderr, "ERROR pqnist_bls_sign rc: %d\n", rc);
+            printf("FAILURE\n");
+            exit(EXIT_FAILURE);
+        }
+
+    }
+
+    for(int i=0; i<n; i++)
+    {
+        printf("sigs[%d] ", i);
+        amcl_print_hex(&sigs[i*(SIGLEN)], SIGLEN);
+        printf("\n");
+    }
+
+    // Recover BLS signature
+    pqnist_bls_recover_signature(k, x, sigs, sigr);
+
+    printf("sigr ");
+    amcl_print_hex(sigr, SIGLEN);
+    printf("\n");
+
+    printf("TEST PASSED\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/examples/run_encap_decap.c b/libs/crypto/libpqnist/examples/run_encap_decap.c
new file mode 100644
index 0000000..e35691a
--- /dev/null
+++ b/libs/crypto/libpqnist/examples/run_encap_decap.c
@@ -0,0 +1,204 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   Encapsulate a secret and use the secret to encrypt a message
+   Decapsulate the secret and use the secret to decrypt the encrypted message
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/bls_BLS381.h>
+#include <oqs/oqs.h>
+#include <amcl/pqnist.h>
+
+#define NTHREADS 8
+#define MAXSIZE 256
+
+#define G2LEN 4*BFS_BLS381
+
+int main()
+{
+    int i,rc;
+
+    // Seed value for CSPRNG
+    char seed[PQNIST_SEED_LENGTH];
+    octet SEED = {sizeof(seed),sizeof(seed),seed};
+
+    // Seed value for key generation
+    char seedkeys[NTHREADS][PQNIST_SEED_LENGTH];
+
+    csprng RNG;
+
+    // Initialization vector
+    char iv[PQNIST_AES_IV_LENGTH];
+    octet IV= {sizeof(iv),sizeof(iv),iv};
+
+    // Message to be sent to Bob
+    char p[NTHREADS][MAXSIZE];
+    octet P[NTHREADS];
+
+    // AES CBC ciphertext
+    char c[NTHREADS][MAXSIZE];
+    octet C[NTHREADS];
+
+    // non random seed value
+    for (i=0; i<PQNIST_SEED_LENGTH; i++) SEED.val[i]=i+1;
+    printf("SEED: ");
+    OCT_output(&SEED);
+    printf("\n");
+
+    // initialise random number generator
+    CREATE_CSPRNG(&RNG,&SEED);
+
+    // Initialise key generation seed
+    for(i=0; i<NTHREADS; i++)
+    {
+        for(int j=0; j<PQNIST_SEED_LENGTH; j++)
+        {
+            seedkeys[i][j] = i;
+        }
+    }
+
+    // Bob's SIKE keys
+    uint8_t SIKEpk[NTHREADS][OQS_KEM_sike_p751_length_public_key];
+    uint8_t SIKEsk[NTHREADS][OQS_KEM_sike_p751_length_secret_key];
+
+    #pragma omp parallel for
+    for(i=0; i<NTHREADS; i++)
+    {
+        rc = pqnist_sike_keys(seedkeys[i], SIKEpk[i], SIKEsk[i]);
+        if (rc)
+        {
+            fprintf(stderr, "ERROR pqnist_sike_keys rc: %d\n", rc);
+            exit(EXIT_FAILURE);
+        }
+
+        int j = OQS_KEM_sike_p751_length_public_key;
+        printf("Bob SIKE pklen %d pk: ", j);
+        amcl_print_hex(SIKEpk[i], j);
+        j = OQS_KEM_sike_p751_length_secret_key;
+        printf("Bob SIKE sklen %d sk: ", j);
+        amcl_print_hex(SIKEsk[i], j);
+
+    }
+
+    // Alice
+
+    for(i=0; i<NTHREADS; i++)
+    {
+        bzero(p[i],sizeof(p[i]));
+        P[i].max = MAXSIZE;
+        P[i].len = sprintf(p[i], "Hello Bob! This is a message from Alice %d", i);
+        P[i].val = p[i];
+        // Pad message
+        int l = 16 - (P[i].len % 16);
+        if (l < 16)
+        {
+            OCT_jbyte(&P[i],0,l);
+        }
+    }
+
+    // Random initialization value
+    generateRandom(&RNG,&IV);
+    printf("Alice IV: ");
+    OCT_output(&IV);
+
+    // Copy plaintext
+    for(i=0; i<NTHREADS; i++)
+    {
+        C[i].val = c[i];
+        C[i].max = MAXSIZE;
+        OCT_copy(&C[i],&P[i]);
+        printf("Alice Plaintext: ");
+        OCT_output_string(&C[i]);
+        printf("\n");
+    }
+
+    // SIKE encapsulated key
+    uint8_t ek[NTHREADS][OQS_KEM_sike_p751_length_ciphertext];
+
+    #pragma omp parallel for
+    for(i=0; i<NTHREADS; i++)
+    {
+
+        // Generate an AES which is ecapsulated using SIKE. Use this key to
+        // AES encrypt the K parameter.
+        rc = pqnist_encapsulate_encrypt(C[i].val, C[i].len, IV.val, SIKEpk[i], ek[i]);
+        if(rc)
+        {
+            fprintf(stderr, "ERROR pqnist_encapsulate_encrypt rc: %d\n", rc);
+            exit(EXIT_FAILURE);
+        }
+
+        printf("Alice ciphertext: ");
+        OCT_output(&C[i]);
+
+        printf("Alice ek %lu ek: ", sizeof(ek[i]));
+        amcl_print_hex(ek[i], sizeof(ek[i]));
+        printf("\n");
+
+    }
+
+    // Bob
+
+    #pragma omp parallel for
+    for(i=0; i<NTHREADS; i++)
+    {
+        // Obtain encapsulated AES key and decrypt C
+        rc = pqnist_decapsulate_decrypt(C[i].val, C[i].len, IV.val, SIKEsk[i], ek[i]);
+        if(rc)
+        {
+            fprintf(stderr, "ERROR pqnist_decapsulate_decrypt rc: %d\n", rc);
+            exit(EXIT_FAILURE);
+        }
+
+        printf("Bob Plaintext: ");
+        OCT_output(&C[i]);
+
+        printf("Bob Plaintext: ");
+        OCT_output_string(&C[i]);
+        printf("\n");
+
+        // Compare sent and recieved message (returns 0 for failure)
+        rc = OCT_comp(&P[i],&C[i]);
+        if(!rc)
+        {
+            fprintf(stderr, "ERROR OCT_comp rc: %d\n", rc);
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    // clear memory
+
+    OCT_clear(&IV);
+    for(i=0; i<NTHREADS; i++)
+    {
+        OQS_MEM_cleanse(SIKEsk[i], OQS_KEM_sike_p751_length_secret_key);
+        OCT_clear(&P[i]);
+        OCT_clear(&C[i]);
+    }
+
+    KILL_CSPRNG(&RNG);
+
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/examples/run_pqnist.c b/libs/crypto/libpqnist/examples/run_pqnist.c
new file mode 100644
index 0000000..f5e9a1c
--- /dev/null
+++ b/libs/crypto/libpqnist/examples/run_pqnist.c
@@ -0,0 +1,314 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   Run through the flow of encrypting, ecapsulating and signing a message
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/bls_BLS381.h>
+#include <oqs/oqs.h>
+#include <amcl/pqnist.h>
+
+#define G2LEN 4*BFS_BLS381
+#define SIGLEN BFS_BLS381+1
+
+int main()
+{
+    int i,rc;
+
+    // Seed value for CSPRNG
+    char seed[PQNIST_SEED_LENGTH];
+    octet SEED = {sizeof(seed),sizeof(seed),seed};
+
+    csprng RNG;
+
+    // AES Key
+    char k[PQNIST_AES_KEY_LENGTH];
+    octet K= {0,sizeof(k),k};
+
+    // Initialization vectors
+    char iv[PQNIST_AES_IV_LENGTH];
+    octet IV= {sizeof(iv),sizeof(iv),iv};
+    char iv2[PQNIST_AES_IV_LENGTH];
+    octet IV2= {sizeof(iv2),sizeof(iv2),iv2};
+
+    // Message to be sent to Bob
+    char p[256];
+    octet P = {0, sizeof(p), p};
+    OCT_jstring(&P,"Hello Bob! This is a message from Alice");
+
+    printf("Alice Pliantext hex:");
+    OCT_output(&P);
+
+    printf("PLAINTEXTLen = %d blocks %0.2f \n", P.len, (float) P.len/16);
+
+    // Pad message
+    int l = 16 - (P.len % 16);
+    if (l < 16)
+    {
+        OCT_jbyte(&P,0,l);
+    }
+
+    printf("Alice Plaintext: ");
+    OCT_output_string(&P);
+    printf("\n");
+    printf("Alice Pliantext hex:");
+    OCT_output(&P);
+
+    printf("PLAINTEXTLen = %d blocks %0.2f \n", P.len, (float) P.len/16);
+
+    // AES CBC ciphertext
+    char c[256];
+    octet C = {0, sizeof(c), c};
+
+    // non random seed value
+    for (i=0; i<PQNIST_SEED_LENGTH; i++) SEED.val[i]=i+1;
+    printf("SEED: ");
+    OCT_output(&SEED);
+    printf("\n");
+
+    // initialise random number generator
+    CREATE_CSPRNG(&RNG,&SEED);
+
+    // Generate 256 bit AES Key
+    K.len=PQNIST_AES_KEY_LENGTH;
+    generateRandom(&RNG,&K);
+
+    // Generate SIKE and BLS keys
+
+    // Bob's SIKE keys
+    uint8_t SIKEpk[OQS_KEM_sike_p751_length_public_key];
+    uint8_t SIKEsk[OQS_KEM_sike_p751_length_secret_key];
+
+    // Alice's BLS keys
+    char BLSsk[BGS_BLS381];
+    char BLSpk[G2LEN];
+
+    rc = pqnist_sike_keys(seed, SIKEpk, SIKEsk);
+    if (rc)
+    {
+        fprintf(stderr, "ERROR pqnist_sike_keys rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = pqnist_bls_keys(seed, BLSpk, BLSsk);
+    if (rc)
+    {
+        fprintf(stderr, "ERROR pqnist_bls_keys rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    i = OQS_KEM_sike_p751_length_public_key;
+    printf("Bob SIKE pklen %d pk: ", i);
+    amcl_print_hex(SIKEpk, i);
+    i = OQS_KEM_sike_p751_length_secret_key;
+    printf("Bob SIKE sklen %d sk: ", i);
+    amcl_print_hex(SIKEsk, i);
+    printf("BLS pklen %d pk: ", G2LEN);
+    amcl_print_hex(BLSpk, G2LEN);
+    printf("BLS sklen %d BLS sk: ", BGS_BLS381);
+    amcl_print_hex(BLSsk, BGS_BLS381);
+    printf("\n");
+
+    // BLS signature
+    char S[SIGLEN];
+
+    // SIKE encapsulated key
+    uint8_t ek[OQS_KEM_sike_p751_length_ciphertext];
+
+    // Alice
+
+    printf("Alice Key: ");
+    amcl_print_hex(K.val, K.len);
+
+    // Random initialization value
+    generateRandom(&RNG,&IV);
+    printf("Alice IV: ");
+    OCT_output(&IV);
+
+    printf("Alice Plaintext: ");
+    OCT_output(&P);
+
+    printf("Alice Plaintext: ");
+    OCT_output_string(&P);
+    printf("\n");
+
+    // Copy plaintext
+    OCT_copy(&C,&P);
+
+    printf("Alice Plaintext: ");
+    OCT_output_string(&C);
+    printf("\n");
+
+    // Encrypt plaintext
+    pqnist_aes_cbc_encrypt(K.val, K.len, IV.val, C.val, C.len);
+
+    printf("Alice Ciphertext: ");
+    OCT_output(&C);
+
+    generateRandom(&RNG,&IV2);
+    printf("Alice IV2: ");
+    OCT_output(&IV2);
+
+    // Generate an AES which is ecapsulated using SIKE. Use this key to
+    // AES encrypt the K parameter.
+    rc = pqnist_encapsulate_encrypt(K.val, K.len, IV2.val, SIKEpk, ek);
+    if(rc)
+    {
+        fprintf(stderr, "ERROR pqnist_encapsulate_encrypt rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("Alice encrypted key: ");
+    OCT_output(&K);
+
+    i = OQS_KEM_sike_p751_length_ciphertext;
+    printf("Alice ek1 %d ek1: ", i);
+    amcl_print_hex(ek, i);
+    printf("Alice ek2 %d ek2: ", i);
+    amcl_print_hex(&ek[OQS_KEM_sike_p751_length_ciphertext], i);
+    printf("\n");
+
+    // Bob
+
+    // Obtain encapsulated AES key and decrypt K
+    rc = pqnist_decapsulate_decrypt(K.val, K.len, IV2.val, SIKEsk, ek);
+    if(rc)
+    {
+        fprintf(stderr, "ERROR pqnist_decapsulate_decrypt rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("Bob Key: ");
+    amcl_print_hex(K.val, K.len);
+
+    printf("Bob IV ");
+    OCT_output(&IV);
+
+    printf("Bob Ciphertext: ");
+    OCT_output(&C);
+
+    pqnist_aes_cbc_decrypt(K.val, K.len, IV.val, C.val, C.len);
+
+    printf("Bob Plaintext: ");
+    OCT_output(&C);
+
+    printf("Bob Plaintext: ");
+    OCT_output_string(&C);
+    printf("\n");
+
+    // Compare sent and recieved message (returns 0 for failure)
+    rc = OCT_comp(&P,&C);
+    if(!rc)
+    {
+        fprintf(stderr, "ERROR OCT_comp rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+
+    // Sign message
+
+    // Alice signs message
+    rc = pqnist_bls_sign(P.val, BLSsk, S);
+    if(rc)
+    {
+        fprintf(stderr, "ERROR pqnist_bls_sign rc: %d\n", rc);
+        printf("FAILURE\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("Alice Slen %d SIG", SIGLEN);
+    amcl_print_hex(S, SIGLEN);
+    printf("\n");
+
+    // Bob verifies message
+    rc = pqnist_bls_verify(P.val, BLSpk, S);
+    if (rc == BLS_OK)
+    {
+        printf("BOB SUCCESS: signature verified\n");
+    }
+    else
+    {
+        fprintf(stderr, "BOB ERROR: verify failed!\n errorCode %d", rc);
+        exit(EXIT_FAILURE);
+    }
+
+
+    printf("Bob P ");
+    OCT_output(&P);
+    printf("\n");
+
+    // Bob verifies corrupted message
+    char tmp = P.val[0];
+    P.val[0] = 0;
+    rc = pqnist_bls_verify(P.val, BLSpk, S);
+    if (rc == BLS_OK)
+    {
+        printf("BOB SUCCESS: signature verified\n");
+    }
+    else
+    {
+        fprintf(stderr, "BOB ERROR verify failed! errorCode: %d\n", rc);
+    }
+
+    // Fix message
+    P.val[0] = tmp;
+    printf("Bob P ");
+    OCT_output(&P);
+    printf("\n");
+
+    // Check signature is correct
+    rc = pqnist_bls_verify(P.val, BLSpk, S);
+    if (rc == BLS_OK)
+    {
+        printf("BOB SUCCESS: signature verified\n");
+    }
+    else
+    {
+        fprintf(stderr, "BOB ERROR verify failed! errorCode: %d\n", rc);
+    }
+
+    // Bob verifies corrupted signature
+    S[0] = 0;
+    rc = pqnist_bls_verify(P.val, BLSpk, S);
+    if (rc == BLS_OK)
+    {
+        printf("BOB SUCCESS: signature verified\n");
+    }
+    else
+    {
+        fprintf(stderr, "BOB ERROR verify failed! errorCode: %d\n", rc);
+    }
+
+    // clear memory
+    OQS_MEM_cleanse(SIKEsk, OQS_KEM_sike_p751_length_secret_key);
+    OQS_MEM_cleanse(BLSsk, OQS_SIG_picnic_L5_FS_length_secret_key);
+    OCT_clear(&K);
+    OCT_clear(&IV);
+    OCT_clear(&P);
+
+    KILL_CSPRNG(&RNG);
+
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/examples/run_sike.c b/libs/crypto/libpqnist/examples/run_sike.c
new file mode 100644
index 0000000..d3ef49f
--- /dev/null
+++ b/libs/crypto/libpqnist/examples/run_sike.c
@@ -0,0 +1,146 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/**
+ * @file run_sike.c
+ * @author Kealan McCusker
+ * @brief Encapsulate and decapsulate a secret using SIKE
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <oqs/oqs.h>
+
+// Set to have fixed values for the key pair
+#define FIXED
+
+/* Print encoded binary string in hex */
+static void printHex(uint8_t *src, int src_len)
+{
+    int i;
+    for (i = 0; i < src_len; i++)
+    {
+        printf("%02x", (unsigned char) src[i]);
+    }
+    printf("\n");
+}
+
+/* Cleaning up memory etc */
+static void cleanup(uint8_t *secret_key, size_t secret_key_len,
+                    uint8_t *shared_secret_e, uint8_t *shared_secret_d,
+                    size_t shared_secret_len);
+
+/* This function gives an example of the operations performed by both
+ * the decapsulator and the encapsulator in a single KEM session,
+ * using only compile-time macros and allocating variables
+ * statically on the stack, calling a specific algorithm's functions
+ * directly.
+ */
+static OQS_STATUS example()
+{
+    uint8_t public_key[OQS_KEM_sike_p751_length_public_key];
+    uint8_t secret_key[OQS_KEM_sike_p751_length_secret_key];
+    uint8_t ciphertext[OQS_KEM_sike_p751_length_ciphertext];
+    uint8_t shared_secret_e[OQS_KEM_sike_p751_length_shared_secret];
+    uint8_t shared_secret_d[OQS_KEM_sike_p751_length_shared_secret];
+
+#ifdef FIXED
+    uint8_t entropy_input[48];
+    for (size_t i = 0; i < 48; i++)
+    {
+        entropy_input[i] = i;
+    }
+
+    OQS_STATUS rc = OQS_randombytes_switch_algorithm(OQS_RAND_alg_nist_kat);
+    if (rc != OQS_SUCCESS)
+    {
+        return rc;
+    }
+    OQS_randombytes_nist_kat_init(entropy_input, NULL, 256);
+#endif
+
+    rc = OQS_KEM_sike_p751_keypair(public_key, secret_key);
+    if (rc != OQS_SUCCESS)
+    {
+        fprintf(stderr, "ERROR: OQS_KEM_sike_p751_keypair failed!\n");
+        cleanup(secret_key, OQS_KEM_sike_p751_length_secret_key,
+                shared_secret_e, shared_secret_d,
+                OQS_KEM_sike_p751_length_shared_secret);
+
+        return OQS_ERROR;
+    }
+    int i = OQS_KEM_sike_p751_length_public_key;
+    printf("pklen %d pk: ", i);
+    printHex(public_key, i);
+    i = OQS_KEM_sike_p751_length_secret_key;
+    printf("sklen %d sk: ", i);
+    printHex(secret_key, i);
+
+    rc = OQS_KEM_sike_p751_encaps(ciphertext, shared_secret_e, public_key);
+    if (rc != OQS_SUCCESS)
+    {
+        fprintf(stderr, "ERROR: OQS_KEM_sike_p751_encaps failed!\n");
+        cleanup(secret_key, OQS_KEM_sike_p751_length_secret_key,
+                shared_secret_e, shared_secret_d,
+                OQS_KEM_sike_p751_length_shared_secret);
+
+        return OQS_ERROR;
+    }
+    i = OQS_KEM_sike_p751_length_ciphertext;
+    printf("ciphertextlen %d ciphertext: ", i);
+    printHex(ciphertext, i);
+
+    rc = OQS_KEM_sike_p751_decaps(shared_secret_d, ciphertext, secret_key);
+    if (rc != OQS_SUCCESS)
+    {
+        fprintf(stderr, "ERROR: OQS_KEM_sike_p751_decaps failed!\n");
+        cleanup(secret_key, OQS_KEM_sike_p751_length_secret_key,
+                shared_secret_e, shared_secret_d,
+                OQS_KEM_sike_p751_length_shared_secret);
+
+        return OQS_ERROR;
+    }
+    i = OQS_KEM_sike_p751_length_shared_secret;
+    printf("shared_secret_elen %d shared_secret_e: ", i);
+    printHex(shared_secret_e, i);
+    printf("shared_secret_dlen %d shared_secret_d: ", i);
+    printHex(shared_secret_d, i);
+
+    printf("OQS_KEM_sike_p751 operations completed.\n");
+
+    return OQS_SUCCESS; // success!
+}
+
+
+int main(void)
+{
+    example();
+}
+
+static void cleanup(uint8_t *secret_key, size_t secret_key_len,
+                    uint8_t *shared_secret_e, uint8_t *shared_secret_d,
+                    size_t shared_secret_len)
+{
+    OQS_MEM_cleanse(secret_key, secret_key_len);
+    OQS_MEM_cleanse(shared_secret_e, shared_secret_len);
+    OQS_MEM_cleanse(shared_secret_d, shared_secret_len);
+}
+
diff --git a/libs/crypto/libpqnist/include/CMakeLists.txt b/libs/crypto/libpqnist/include/CMakeLists.txt
new file mode 100644
index 0000000..194970c
--- /dev/null
+++ b/libs/crypto/libpqnist/include/CMakeLists.txt
@@ -0,0 +1,9 @@
+# List of headers
+file(GLOB headers "amcl/*.h")
+
+install(FILES ${headers}
+        DESTINATION ${INSTALL_INCLUDESUBDIR})
+
+# Copy header to golang binary directory
+file(COPY ${headers} DESTINATION ${PROJECT_BINARY_DIR}/go/amcl)
+      
diff --git a/libs/crypto/libpqnist/include/amcl/pqnist.h b/libs/crypto/libpqnist/include/amcl/pqnist.h
new file mode 100644
index 0000000..aaa0461
--- /dev/null
+++ b/libs/crypto/libpqnist/include/amcl/pqnist.h
@@ -0,0 +1,230 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/**
+ * @file pqnist.h
+ * @author Kealan McCusker
+ * @brief crypto function declarations
+ *
+ */
+
+
+#ifndef PQNIST_H
+#define PQNIST_H
+
+#define PQNIST_AES_KEY_LENGTH 32  //!< AES-256 key length
+#define PQNIST_AES_IV_LENGTH 16   //!< AES-256 initialization vector length
+#define PQNIST_SEED_LENGTH 48   //!< CSPRNG seed length
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**  @brief Generate BLS keys
+
+     Generate BLS public and private key
+
+     @param seed             seed value for CSPRNG
+     @param BLSpk            BLS public key
+     @param BLSsk            BLS secret key. Generated externally if seed set to NULL
+     @return                 Zero for success or else an error code
+ */
+int pqnist_bls_keys(char* seed, char* BLSpk, char* BLSsk);
+
+
+/**  @brief Sign a message
+
+     The message is signed using the BLS algorithm
+
+     @param M            Message to be signed
+     @param sk           BLS secret key
+     @param S            Signature
+     @return             Zero for success or else an error code
+ */
+int pqnist_bls_sign(char* M, char* sk, char* S);
+
+/**  @brief Verify a signature
+
+     Verify a signature using the BLS algorithm
+
+     @param M            Message that was signed
+     @param pk           BLS public key
+     @param S            Signature
+     @return             Zero for success or else an error code
+ */
+int pqnist_bls_verify(char* M, char* pk, char* S);
+
+/**	@brief Add two members from the group G1
+ *
+	@param  r1  member of G1
+	@param  r2  member of G1
+	@param  r   member of G1. r = r1+r2
+	@return     Zero for success or else an error code
+ */
+int pqnist_bls_addg1(char* r1, char* r2, char* r);
+
+/**	@brief Add two members from the group G2
+ *
+	@param  r1  member of G2
+	@param  r2  member of G2
+	@param  r   member of G2. r = r1+r2
+	@return     Zero for success or else an error code
+ */
+int pqnist_bls_addg2(char* r1, char* r2, char* r);
+
+
+/**	@brief Use Shamir's secret sharing to distribute BLS secret keys
+ *
+	@param  k       Threshold
+	@param  n       Number of shares
+        @param  pSEED   seed value for CSPRNG - 48 bytes
+	@param  pX      X values
+	@param  pY      Y values. Valid BLS secret keys
+	@param  pSKI    Input secret key to be shared. Ignored if set to NULL
+	@param  pSKO    Secret key that is shared
+	@return         Zero for success or else an error code
+ */
+int pqnist_bls_make_shares(int k, int n,  char* pSEED, char* pX, char* pY, char* pSKI, char* pSKO);
+
+/**	@brief Use Shamir's secret sharing to recover a BLS secret key
+ *
+	@param  k    Threshold
+	@param  pX   X values
+	@param  pY   Y values. Valid BLS secret keys
+	@param  pSK  Secret key that is recovered
+	@return      Zero for success or else an error code
+ */
+int pqnist_bls_recover_secret(int k, char* pX, char* pY, char* pSK);
+
+/**	@brief Use Shamir's secret sharing to recover a BLS signature
+ *
+	@param  k     Threshold
+	@param  pX    X values
+	@param  pY    Y values. Valid BLS signatures
+	@param  pSIG  Signature that is recovered
+	@return       Zero for success or else an error code
+ */
+int pqnist_bls_recover_signature(int k, char* pX, char* pY, char* pSIG);
+
+/**  @brief AES-GCM Encryption
+
+     AES encryption using GCM mode
+
+     @param K            Key
+     @param Klen         Key length in bytes
+     @param IV           Initialization vector IV
+     @param IVlen        IV length in bytes
+     @param A            Additional authenticated data (AAD)
+     @param Alen         AAD length in bytes
+     @param P            Plaintext
+     @param Plen         Plaintext length in bytes
+     @param C            Ciphertext (same length as P)
+     @param T            Authentication tag
+ */
+void pqnist_aes_gcm_encrypt(char* K, int Klen, char* IV, int IVlen, char* A, int Alen, char* P, int Plen, char* C, char* T);
+
+/**  @brief AES-GCM Decryption
+
+     AES decryption using GCM mode
+
+     @param K            Key
+     @param Klen         Key length in bytes
+     @param IV           Initialization vector IV
+     @param IVlen        IV length in bytes
+     @param A            Additional authenticated data (AAD)
+     @param Alen         AAD length in bytes
+     @param C            Ciphertext
+     @param Clen         Ciphertext length in bytes
+     @param P            Plaintext  (same length as C)
+     @param T            Authentication tag
+ */
+void pqnist_aes_gcm_decrypt(char* K, int Klen, char* IV, int IVlen, char* A, int Alen, char* C, int Clen, char* P, char* T);
+
+/**  @brief AES-CBC Encryption
+
+     AES encryption using CBC mode
+
+     @param K            Key
+     @param Klen         Key length in bytes
+     @param IV           Initialization vector IV (16 bytes)
+     @param P            Plaintext / Ciphertext must be a multiple of the block size (16)
+     @param Plen         Plaintext length in bytes
+ */
+void pqnist_aes_cbc_encrypt(char* K, int Klen, char* IV, char* P, int Plen);
+
+/**  @brief AES-CBC Decryption
+
+     AES decryption using CBC mode
+
+     @param K            Key
+     @param Klen         Key length in bytes
+     @param IV           Initialization vector IV (16 bytes)
+     @param C            Ciphertext / Plaintext must be a multiple of the block size (16)
+     @param Clen         Ciphertext length in bytes
+ */
+void pqnist_aes_cbc_decrypt(char* K, int Klen, char* IV, char* C, int Clen);
+
+/**  @brief Generate SIKE keys
+
+     Generate SIKE public and private key
+
+     @param seed             seed value for CSPRNG - 48 bytes
+     @param SIKEpk           SIKE public key
+     @param SIKEsk           SIKE secret key
+     @return                 Zero for success or else an error code
+ */
+int pqnist_sike_keys(char* seed, char* SIKEpk, char* SIKEsk);
+
+/**  @brief Encrypt a message and encapsulate the AES Key for
+     a recipient.
+
+     The  message is encrypted using AES-256. The key
+     is generated inside this function as an output
+     from the encapsulation function. The ciphertext
+     is returned using the P paramter.
+
+     @param P            Plaintext to be encrypted / Ciphertext. Padded with zero.
+     @param Plen         Plaintext length in bytes must be a multiple of the block size (16)
+     @param IV           Initialization vector IV (16 bytes)
+     @param pk           SIKE public key
+     @param ek           Encapsulated key
+     @return             Zero for success or else an error code
+ */
+int pqnist_encapsulate_encrypt(char* P, int Plen, char* IV, char* pk, char* ek);
+
+/**  @brief Decapsulate the AES Key and decrypt the message
+
+     Decapsulate the AES key and use it to decrypt the
+     ciphertext. The plaintext is returned using the C
+     parameter.
+
+     @param C            Ciphertext to be decrypted / Plaintext
+     @param Clen         Ciphertext length in bytes must be a multiple of the block size (16)
+     @param IV           Initialization vector IV
+     @param sk           SIKE secret key
+     @param ek           Encapsulated key
+     @return             Zero for success or else an error code
+ */
+int pqnist_decapsulate_decrypt(char* C, int Clen, char* IV, char* sk, char* ek);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libs/crypto/libpqnist/src/CMakeLists.txt b/libs/crypto/libpqnist/src/CMakeLists.txt
new file mode 100644
index 0000000..1480553
--- /dev/null
+++ b/libs/crypto/libpqnist/src/CMakeLists.txt
@@ -0,0 +1,30 @@
+file(GLOB_RECURSE SOURCES *.c)
+
+set(target "pqnist")
+
+link_directories(${CMAKE_CURRENT_BINARY_DIR}
+                 /usr/local/lib)
+
+include_directories (${PROJECT_SOURCE_DIR}/include
+                     /usr/local/include)
+
+add_library(${target} ${LIB_TYPE} ${SOURCES})
+
+target_link_libraries (${target} amcl_bls_BLS381 amcl_pairing_BLS381 amcl_curve_BLS381 amcl_core oqs)
+
+set_target_properties(${target}
+                      PROPERTIES VERSION
+                                 ${BUILD_VERSION}
+                                 SOVERSION
+                                 ${VERSION_MAJOR})
+
+install(TARGETS ${target} DESTINATION lib PERMISSIONS
+        OWNER_WRITE OWNER_READ OWNER_EXECUTE
+        GROUP_READ GROUP_EXECUTE
+        WORLD_READ WORLD_EXECUTE)
+
+message(STATUS "Copy ${target} library to go for testing")
+add_custom_command(TARGET ${target} POST_BUILD
+                   COMMAND ${CMAKE_COMMAND} -E copy
+                          "${CMAKE_CURRENT_BINARY_DIR}/lib*"
+                          "${PROJECT_BINARY_DIR}/go/")
diff --git a/libs/crypto/libpqnist/src/pqnist.c b/libs/crypto/libpqnist/src/pqnist.c
new file mode 100644
index 0000000..2bb4565
--- /dev/null
+++ b/libs/crypto/libpqnist/src/pqnist.c
@@ -0,0 +1,482 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <oqs/oqs.h>
+#include <amcl/pqnist.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/bls_BLS381.h>
+
+#define G2LEN 4*BFS_BLS381
+#define SIGLEN BFS_BLS381+1
+
+//  Generate BLS public and private key
+int pqnist_bls_keys(char* seed, char* BLSpk, char* BLSsk)
+{
+    int rc;
+
+    octet PK = {0,G2LEN,BLSpk};
+    octet SK = {0,BGS_BLS381,BLSsk};
+
+    if (seed==NULL)
+    {
+        rc =  BLS_BLS381_KEY_PAIR_GENERATE(NULL,&SK,&PK);
+    }
+    else
+    {
+        octet SEED = {PQNIST_SEED_LENGTH,PQNIST_SEED_LENGTH,seed};
+
+        // CSPRNG
+        csprng RNG;
+
+        // initialise strong RNG
+        CREATE_CSPRNG(&RNG,&SEED);
+
+        // Generate BLS key pair
+        rc =  BLS_BLS381_KEY_PAIR_GENERATE(&RNG,&SK,&PK);
+    }
+
+    if (rc)
+    {
+        return rc;
+    }
+
+#ifdef DEBUG
+    printf("pqnist_keys BLSpklen %d BLSpk ", PK.len);
+    OCT_output(&PK);
+    printf("pqnist_keys BLSsklen %d BLSsk ", SK.len);
+    OCT_output(&SK);
+#endif
+
+    return 0;
+}
+
+
+//  Sign message using the BLS algorithm
+int pqnist_bls_sign(char* M, char* sk, char* S)
+{
+    octet SIG = {0,SIGLEN,S};
+    octet SK = {BGS_BLS381,BGS_BLS381,sk};
+
+#ifdef DEBUG
+    printf("pqnist_bls_sign SK: ");
+    OCT_output(&SK);
+#endif
+
+    int rc = BLS_BLS381_SIGN(&SIG,M,&SK);
+    if (rc!=BLS_OK)
+    {
+        return rc;
+    }
+
+#ifdef DEBUG
+    printf("pqnist_bls_sign SIG: ");
+    OCT_output(&SIG);
+#endif
+
+    return 0;
+}
+
+//  Verify a signature using the BLS algorithm
+int pqnist_bls_verify(char* M, char* pk, char* S)
+{
+    octet SIG = {SIGLEN,SIGLEN,S};
+    octet PK = {G2LEN,G2LEN,pk};
+
+#ifdef DEBUG
+    printf("pqnist_bls_verify M %s\n", M);
+    printf("pqnist_bls_verify PK: ");
+    OCT_output(&PK);
+    printf("pqnist_bls_verify SIG: ");
+    OCT_output(&SIG);
+#endif
+
+    int rc=BLS_BLS381_VERIFY(&SIG,M,&PK);
+    if (rc!=BLS_OK)
+    {
+        return rc;
+    }
+
+    return 0;
+}
+
+//  Add two members from the group G1
+int pqnist_bls_addg1(char* r1, char* r2, char* r)
+{
+    octet R1 = {BGS_BLS381,BGS_BLS381,r1};
+    octet R2 = {BGS_BLS381,BGS_BLS381,r2};
+    octet R = {BGS_BLS381,BGS_BLS381,r};
+
+    int rc=BLS_BLS381_ADD_G1(&R1,&R2,&R);
+    if (rc!=BLS_OK)
+    {
+        return rc;
+    }
+
+#ifdef DEBUG
+    printf("pqnist_bls_addg1 R1: ");
+    OCT_output(&R1);
+    printf("pqnist_bls_addg1 R2: ");
+    OCT_output(&R2);
+    printf("pqnist_bls_addg1 R: ");
+    OCT_output(&R);
+#endif
+
+    return 0;
+}
+
+//  Add two members from the group G2
+int pqnist_bls_addg2(char* r1, char* r2, char* r)
+{
+    octet R1 = {G2LEN,G2LEN,r1};
+    octet R2 = {G2LEN,G2LEN,r2};
+    octet R = {G2LEN,G2LEN,r};
+
+    int rc=BLS_BLS381_ADD_G2(&R1,&R2,&R);
+    if (rc!=BLS_OK)
+    {
+        return rc;
+    }
+
+#ifdef DEBUG
+    printf("pqnist_bls_addg2 R1: ");
+    OCT_output(&R1);
+    printf("pqnist_bls_addg2 R2: ");
+    OCT_output(&R2);
+    printf("pqnist_bls_addg2 R: ");
+    OCT_output(&R);
+#endif
+
+    return 0;
+}
+
+// Use Shamir's secret sharing to distribute BLS secret keys
+int pqnist_bls_make_shares(int k, int n,  char* pSEED, char* pX, char* pY, char* pSKI, char* pSKO)
+{
+    int rc;
+
+    octet SEED = {PQNIST_SEED_LENGTH,PQNIST_SEED_LENGTH,pSEED};
+    octet SKI = {BGS_BLS381,BGS_BLS381,pSKI};
+    octet SKO = {BGS_BLS381,BGS_BLS381,pSKO};
+    octet X[n];
+    octet Y[n];
+    for(int i=0; i<n; i++)
+    {
+        Y[i].max = BGS_BLS381;
+        Y[i].len = BGS_BLS381;
+        Y[i].val = &pY[i*BGS_BLS381];
+        X[i].max = BGS_BLS381;
+        X[i].len = BGS_BLS381;
+        X[i].val = &pX[i*BGS_BLS381];
+    }
+
+    // CSPRNG
+    csprng RNG;
+
+    // initialise strong RNG
+    CREATE_CSPRNG(&RNG,&SEED);
+
+    // Make shares of BLS secret key
+    rc = BLS_BLS381_MAKE_SHARES(k, n, &RNG, X, Y, &SKI, &SKO);
+    if (rc)
+    {
+        return rc;
+    }
+
+#ifdef DEBUG
+    printf("pqnist_keys SEED: ");
+    OCT_output(&SEED);
+    printf("\n");
+
+    for(int i=0; i<n; i++)
+    {
+        printf("X[%d] ", i);
+        OCT_output(&X[i]);
+        printf("Y[%d] ", i);
+        OCT_output(&Y[i]);
+        printf("\n");
+    }
+
+    printf("SKI: ");
+    OCT_output(&SKI);
+    printf("SKO: ");
+    OCT_output(&SKO);
+#endif
+
+    return 0;
+}
+
+// Use Shamir's secret sharing to recover a BLS secret key
+int pqnist_bls_recover_secret(int k, char* pX, char* pY, char* pSK)
+{
+    int rc;
+
+    octet SK = {BGS_BLS381,BGS_BLS381,pSK};
+    octet X[k];
+    octet Y[k];
+    for(int i=0; i<k; i++)
+    {
+        Y[i].max = BGS_BLS381;
+        Y[i].len = BGS_BLS381;
+        Y[i].val = &pY[i*BGS_BLS381];
+        X[i].max = BGS_BLS381;
+        X[i].len = BGS_BLS381;
+        X[i].val = &pX[i*BGS_BLS381];
+    }
+
+    // Recover BLS secret key
+    rc = BLS_BLS381_RECOVER_SECRET(k, X, Y, &SK);
+    if (rc)
+    {
+        return rc;
+    }
+
+#ifdef DEBUG
+    printf("SK: ");
+    OCT_output(&SK);
+#endif
+
+    return 0;
+}
+
+// Use Shamir's secret sharing to recover a BLS signature
+int pqnist_bls_recover_signature(int k, char* pX, char* pY, char* pSIG)
+{
+    int rc;
+
+    octet SIG = {SIGLEN,SIGLEN,pSIG};
+
+    octet X[k];
+    octet Y[k];
+    for(int i=0; i<k; i++)
+    {
+        Y[i].max = SIGLEN;
+        Y[i].len = SIGLEN;
+        Y[i].val = &pY[(SIGLEN)*i];
+        X[i].max = BGS_BLS381;
+        X[i].len = BGS_BLS381;
+        X[i].val = &pX[BGS_BLS381*i];
+    }
+
+    // Recover BLS signature
+    rc = BLS_BLS381_RECOVER_SIGNATURE(k, X, Y, &SIG);
+    if (rc)
+    {
+        return rc;
+    }
+
+#ifdef DEBUG
+    printf("pqnist_bls_recover_signature SIG: ");
+    OCT_output(&SIG);
+#endif
+
+    return 0;
+}
+
+
+// Generate SIKE and BLS public and private key pairs
+int pqnist_sike_keys(char* seed, char* SIKEpk, char* SIKEsk)
+{
+    int rc;
+
+    // Initialise KAT RNG
+    rc = OQS_randombytes_switch_algorithm(OQS_RAND_alg_nist_kat);
+    if (rc != OQS_SUCCESS)
+    {
+        return rc;
+    }
+    OQS_randombytes_nist_kat_init(seed, NULL, 256);
+
+    // Generate SIKE key pair
+    rc = OQS_KEM_sike_p751_keypair(SIKEpk, SIKEsk);
+    if (rc != OQS_SUCCESS)
+    {
+        return rc;
+    }
+
+
+#ifdef DEBUG
+    int i = OQS_KEM_sike_p751_length_public_key;
+    printf("pqnist_keys SIKEpklen %d SIKEpk: ", i);
+    amcl_print_hex(SIKEpk, i);
+    i = OQS_KEM_sike_p751_length_secret_key;
+    printf("pqnist_keys SIKE sklen %d SIKEsk: ", i);
+    amcl_print_hex(SIKEsk, i);
+    printf("\n");
+#endif
+
+    return 0;
+}
+
+
+/*   The  message is encrypted using AES-256. The key
+     is generated inside this function as an output
+     from the encapsulation function.
+*/
+int pqnist_encapsulate_encrypt(char* P, int Plen, char* IV, char* pk, char* ek)
+{
+    // AES-256 key
+    uint8_t K[OQS_KEM_sike_p751_length_shared_secret];
+
+#ifdef DEBUG
+    printf("Plaintext %d P: ", Plen);
+    amcl_print_hex(P, Plen);
+    int i = OQS_KEM_sike_p751_length_public_key;
+    printf("pklen %d pk: ", i);
+    amcl_print_hex(pk, i);
+#endif
+
+    OQS_STATUS rc = OQS_KEM_sike_p751_encaps(ek, K, pk);
+    if (rc != OQS_SUCCESS)
+    {
+        OQS_MEM_cleanse(K, OQS_KEM_sike_p751_length_shared_secret);
+        return rc;
+    }
+
+#ifdef DEBUG
+    i = OQS_KEM_sike_p751_length_ciphertext;
+    printf("ek1 %d ek1: ", i);
+    amcl_print_hex(ek, i);
+    i = OQS_KEM_sike_p751_length_shared_secret;
+    printf("K %d K: ", i);
+    amcl_print_hex(K, i);
+#endif
+
+    // Encrypt plaintext
+    pqnist_aes_cbc_encrypt(K, PQNIST_AES_KEY_LENGTH, IV, P, Plen);
+
+#ifdef DEBUG
+    printf("K: ");
+    amcl_print_hex(K, PQNIST_AES_KEY_LENGTH);
+    printf("IV: ");
+    amcl_print_hex((uint8_t*)IV, PQNIST_AES_IV_LENGTH);
+    // Ciphertext
+    printf("C: ");
+    amcl_print_hex((uint8_t*)P, Plen);
+#endif
+
+    return 0;
+}
+
+/*   Decapsulate the AES key and use it to decrypt the
+     ciphertext. The plaintext is returned using the C
+     parameter.
+*/
+int pqnist_decapsulate_decrypt(char* C, int Clen, char* IV, char* sk, char* ek)
+{
+    char sec[OQS_KEM_sike_p751_length_shared_secret*2];
+
+    // Encapsulated secret is 24 byte therefore needs to be run twice to
+    // generate 32 byte AES Key
+    OQS_STATUS rc = OQS_KEM_sike_p751_decaps(sec, ek, sk);
+    if (rc != OQS_SUCCESS)
+    {
+        OQS_MEM_cleanse(sec, OQS_KEM_sike_p751_length_secret_key);
+        return rc;
+    }
+
+#ifdef DEBUG
+    int i = OQS_KEM_sike_p751_length_shared_secret;
+    printf("sec1 %d sec1: ", i);
+    amcl_print_hex(sec, i);
+    printf("sec2 %d sec2: ", i);
+    amcl_print_hex(&sec[OQS_KEM_sike_p751_length_shared_secret], i);
+#endif
+
+    // Decrypt the ciphertext
+    pqnist_aes_cbc_decrypt(sec, PQNIST_AES_KEY_LENGTH, IV, C, Clen);
+
+    return 0;
+}
+
+//  AES encryption using GCM mode
+void pqnist_aes_gcm_encrypt(char* K, int Klen, char* IV, int IVlen, char* A, int Alen, char* P, int Plen, char* C, char* T)
+{
+    gcm g;
+    GCM_init(&g,Klen,K,IVlen,IV);
+    GCM_add_header(&g,A,Alen);
+    GCM_add_plain(&g,C,P,Plen);
+    GCM_finish(&g,T);
+}
+
+// AES Decryption using GCM mode
+void pqnist_aes_gcm_decrypt(char* K, int Klen, char* IV, int IVlen, char* A, int Alen, char* C, int Clen, char* P, char* T)
+{
+    gcm g;
+    GCM_init(&g,Klen,K,IVlen,IV);
+    GCM_add_header(&g,A,Alen);
+    GCM_add_cipher(&g,P,C,Clen);
+    GCM_finish(&g,T);
+}
+
+//   AES encryption using CBC mode
+void pqnist_aes_cbc_encrypt(char* K, int Klen, char* IV, char* P, int Plen)
+{
+#ifdef DEBUG
+    printf("pqnist_aes_cbc_encrypt Klen %d K: \n", Klen);
+    amcl_print_hex(K, Klen);
+    printf("pqnist_aes_cbc_encrypt IVlen %d IV: \n", PQNIST_AES_IV_LENGTH);
+    amcl_print_hex(IV, PQNIST_AES_IV_LENGTH);
+    printf("pqnist_aes_cbc_encrypt Plen %d P: \n", Plen);
+    amcl_print_hex(P, Plen);
+#endif
+
+    int blockSize=16;
+    amcl_aes a;
+    AES_init(&a,CBC,Klen,K,IV);
+    for (int i=0; i<(Plen/blockSize); i++)
+    {
+        AES_encrypt(&a,&P[i*blockSize]);
+    }
+
+#ifdef DEBUG
+    printf("pqnist_aes_cbc_encrypt Clen %d C: \n", Plen);
+    amcl_print_hex(P, Plen);
+#endif
+
+}
+
+//   AES decryption using CBC mode
+void pqnist_aes_cbc_decrypt(char* K, int Klen, char* IV, char* C, int Clen)
+{
+#ifdef DEBUG
+    printf("pqnist_aes_cbc_decrypt Klen %d K: \n", Klen);
+    amcl_print_hex(K, Klen);
+    printf("pqnist_aes_cbc_decrypt IVlen %d IV: \n", PQNIST_AES_IV_LENGTH);
+    amcl_print_hex(IV, PQNIST_AES_IV_LENGTH);
+    printf("pqnist_aes_cbc_decrypt Clen %d C: \n", Clen);
+    amcl_print_hex(C, Clen);
+#endif
+
+    int blockSize=16;
+    amcl_aes a;
+    AES_init(&a,CBC,Klen,K,IV);
+    for (int i=0; i<(Clen/blockSize); i++)
+    {
+        AES_decrypt(&a,&C[i*blockSize]);
+    }
+
+#ifdef DEBUG
+    printf("pqnist_aes_cbc_decrypt Plen %d P: \n", Clen);
+    amcl_print_hex(C, Clen);
+#endif
+}
diff --git a/libs/crypto/libpqnist/test/smoke/CMakeLists.txt b/libs/crypto/libpqnist/test/smoke/CMakeLists.txt
new file mode 100644
index 0000000..82fc259
--- /dev/null
+++ b/libs/crypto/libpqnist/test/smoke/CMakeLists.txt
@@ -0,0 +1,46 @@
+# List of tests
+file(GLOB_RECURSE SRCS *.c)
+
+# List of multithreaded examples 
+SET (SRCSTHREAD test_encap_decap.c test_bls.c)
+
+# Add the binary tree directory to the search path for linking and include files
+link_directories (${PROJECT_BINARY_DIR}/src
+                  /usr/local/lib)
+
+include_directories (${PROJECT_SOURCE_DIR}/include
+                     /usr/local/include)
+
+# define macro to simplify adding tests
+macro(do_test arg result)
+  add_test(${arg} ${TARGET_SYSTEM_EMULATOR} ${arg}${CMAKE_EXECUTABLE_SUFFIX})
+  set_tests_properties(${arg} PROPERTIES PASS_REGULAR_EXPRESSION ${result})
+endmacro()
+
+foreach(test ${SRCS})
+  # Extract the filename without an extension
+  get_filename_component(target ${test} NAME_WE)
+
+  add_executable(${target} ${test})
+
+  target_link_libraries(${target} pqnist)
+
+  do_test(${target} "SUCCESS")
+endforeach(test)
+
+# Multi threading tests
+if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+  foreach(test ${SRCSTHREAD})
+    # Extract the filename without an extension
+    get_filename_component(base ${test} NAME_WE)
+    set(target ${base}_threads)
+
+    add_executable(${target} ${test})
+
+    target_compile_options(${target} PUBLIC -fopenmp)
+
+    target_link_libraries(${target} pqnist -fopenmp)
+
+    do_test(${target} "SUCCESS")
+  endforeach(test)
+endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
diff --git a/libs/crypto/libpqnist/test/smoke/test_aescbc.c b/libs/crypto/libpqnist/test/smoke/test_aescbc.c
new file mode 100644
index 0000000..e814291
--- /dev/null
+++ b/libs/crypto/libpqnist/test/smoke/test_aescbc.c
@@ -0,0 +1,139 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   Test AES-256 encryption and decryption in CBC mode
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/pqnist.h>
+
+int main()
+{
+    int i;
+
+    // Seed value for CSPRNG
+    char seed[PQNIST_SEED_LENGTH];
+    octet SEED = {sizeof(seed),sizeof(seed),seed};
+
+    csprng RNG;
+
+    // AES Key
+    char k[PQNIST_AES_KEY_LENGTH];
+    octet K= {sizeof(k),sizeof(k),k};
+
+    // Initialization vector
+    char iv[PQNIST_AES_IV_LENGTH];
+    octet IV= {sizeof(iv),sizeof(iv),iv};
+
+    // Message to be sent to Bob
+    char p1[256];
+    octet P1 = {0, sizeof(p1), p1};
+    OCT_jstring(&P1,"Hello Bob! This is a message from Alice");
+
+    // Recovered plaintext
+    char p2[256];
+    octet P2= {0,sizeof(p2),p2};
+
+    // non random seed value
+    for (i=0; i<PQNIST_SEED_LENGTH; i++) SEED.val[i]=i+1;
+    printf("SEED: ");
+    OCT_output(&SEED);
+    printf("\n");
+
+    // initialise random number generator
+    CREATE_CSPRNG(&RNG,&SEED);
+
+    // Generate 256 bit AES Key
+    generateRandom(&RNG,&K);
+
+    // Alice
+
+    printf("Alice Key: ");
+    amcl_print_hex(K.val, K.len);
+
+    // Random initialization value
+    generateRandom(&RNG,&IV);
+    printf("Alice IV: ");
+    OCT_output(&IV);
+
+    printf("Alice Plaintext: ");
+    OCT_output(&P1);
+
+    printf("Alice Plaintext: ");
+    OCT_output_string(&P1);
+    printf("\n");
+
+    // Encrypt plaintext
+    pqnist_aes_cbc_encrypt(K.val, K.len, IV.val, P1.val, P1.len);
+
+    printf("Alice: Ciphertext: ");
+    OCT_output(&P1);
+
+    // Bob
+
+    printf("Bob Key: ");
+    amcl_print_hex(K.val, K.len);
+
+    printf("Bob IV ");
+    OCT_output(&IV);
+
+    OCT_copy(&P2,&P1);
+    printf("Bob Ciphertext: ");
+    OCT_output(&P2);
+
+    pqnist_aes_cbc_decrypt(K.val, K.len, IV.val, P2.val, P2.len);
+
+    printf("Bob Plaintext: ");
+    OCT_output(&P2);
+
+    printf("Bob Plaintext: ");
+    OCT_output_string(&P2);
+    printf("\n");
+
+    // Expected message
+    char p[256];
+    octet P = {0, sizeof(p), p};
+    OCT_jstring(&P,"Hello Bob! This is a message from Alice");
+
+    if (!OCT_comp(&P,&P2))
+    {
+        printf("FAILURE Decryption\n");
+        printf("P: ");
+        OCT_output(&P);
+        printf("P2: ");
+        OCT_output(&P2);
+        exit(EXIT_FAILURE);
+    }
+
+    /* clear memory */
+    OCT_clear(&K);
+    OCT_clear(&IV);
+    OCT_clear(&P1);
+    OCT_clear(&P2);
+
+    KILL_CSPRNG(&RNG);
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/test/smoke/test_aesgcm.c b/libs/crypto/libpqnist/test/smoke/test_aesgcm.c
new file mode 100644
index 0000000..e4b7e82
--- /dev/null
+++ b/libs/crypto/libpqnist/test/smoke/test_aesgcm.c
@@ -0,0 +1,179 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   Test AES-256 encryption and decryption in GCM mode
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/pqnist.h>
+
+#define Keylen 32
+#define IVlen 12
+#define Taglen 12
+
+int main()
+{
+    int i;
+
+    // Seed value for CSPRNG
+    // Seed value for CSPRNG
+    char seed[PQNIST_SEED_LENGTH];
+    octet SEED = {sizeof(seed),sizeof(seed),seed};
+
+    csprng RNG;
+
+    // Alice's authentication Tag
+    char t1[Taglen];
+    octet T1= {sizeof(t1),sizeof(t1),t1};
+
+    // Bob's authentication Tag
+    char t2[Taglen];
+    octet T2= {sizeof(t2),sizeof(t2),t2};
+
+    // AES Key
+    char k[Keylen];
+    octet K= {0,sizeof(k),k};
+
+    // Initialization vector
+    char iv[IVlen];
+    octet IV= {0,sizeof(iv),iv};
+
+    // Ciphertext
+    char c[256];
+    octet C= {0,sizeof(c),c};
+
+    // Recovered plaintext
+    char p2[256];
+    octet P2= {0,sizeof(p2),p2};
+
+    // Message to be sent to Bob
+    char p1[256];
+    octet P1 = {0, sizeof(p1), p1};
+    OCT_jstring(&P1,"Hello Bob!");
+
+    // Additional authenticated data (AAD)
+    char aad[256];
+    octet AAD = {0, sizeof(aad), aad};
+    OCT_jstring(&AAD,"Header info");
+
+    // non random seed value
+    for (i=0; i<PQNIST_SEED_LENGTH; i++) SEED.val[i]=i+1;
+    printf("SEED: ");
+    OCT_output(&SEED);
+    printf("\n");
+
+    // initialise random number generator
+    CREATE_CSPRNG(&RNG,&SEED);
+
+    // Generate 256 bit AES Key
+    K.len=Keylen;
+    generateRandom(&RNG,&K);
+
+    // Alice
+
+    printf("Alice Key: ");
+    amcl_print_hex(K.val, K.len);
+
+    // Random initialization value
+    IV.len=IVlen;
+    generateRandom(&RNG,&IV);
+    printf("Alice IV: ");
+    OCT_output(&IV);
+
+    printf("Alice AAD: ");
+    OCT_output(&AAD);
+
+    printf("Alice Plaintext: ");
+    OCT_output(&P1);
+
+    printf("Alice Plaintext: ");
+    OCT_output_string(&P1);
+    printf("\n");
+
+    // Encrypt plaintext
+    pqnist_aes_gcm_encrypt(K.val, K.len, IV.val, IV.len, AAD.val, AAD.len, P1.val, P1.len, C.val, T1.val);
+
+    C.len = P1.len;
+    printf("Alice: Ciphertext: ");
+    OCT_output(&C);
+
+    T1.len = Taglen;
+    printf("Alice Tag: ");
+    OCT_output(&T1);
+    printf("\n");
+
+    // Bob
+
+    printf("Bob Key: ");
+    amcl_print_hex(K.val, K.len);
+
+    printf("Bob IV ");
+    OCT_output(&IV);
+
+    printf("Bob AAD: ");
+    OCT_output(&AAD);
+
+    printf("Bob Ciphertext: ");
+    OCT_output(&C);
+
+    pqnist_aes_gcm_decrypt(K.val, K.len, IV.val, IVlen, AAD.val, AAD.len, C.val, C.len, P2.val, T2.val);
+
+    printf("Bob Plaintext: ");
+    P2.len = C.len;
+    OCT_output(&P2);
+
+    printf("Bob Plaintext: ");
+    OCT_output_string(&P2);
+    printf("\n");
+
+    printf("Bob Tag: ");
+    T2.len = Taglen;
+    OCT_output(&T2);
+
+    if (!OCT_comp(&P1,&P2))
+    {
+        printf("FAILURE Decryption");
+        exit(EXIT_FAILURE);
+    }
+
+    if (!OCT_comp(&T1,&T2))
+    {
+        printf("FAILURE TAG mismatch");
+        exit(EXIT_FAILURE);
+    }
+
+    /* clear memory */
+    OCT_clear(&T1);
+    OCT_clear(&T2);
+    OCT_clear(&K);
+    OCT_clear(&IV);
+    OCT_clear(&C);
+    OCT_clear(&P1);
+    OCT_clear(&P2);
+
+    KILL_CSPRNG(&RNG);
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/test/smoke/test_bls.c b/libs/crypto/libpqnist/test/smoke/test_bls.c
new file mode 100644
index 0000000..8923da9
--- /dev/null
+++ b/libs/crypto/libpqnist/test/smoke/test_bls.c
@@ -0,0 +1,149 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   Sign a message and verify the signature
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/bls_BLS381.h>
+#include <amcl/pqnist.h>
+
+#define NTHREADS 8
+#define MAXSIZE 256
+
+#define G2LEN 4*BFS_BLS381
+#define SIGLEN BFS_BLS381+1
+
+int main()
+{
+    int i,rc;
+
+    // Seed value for CSPRNG
+    char seed[NTHREADS][PQNIST_SEED_LENGTH];
+
+    // Message to be sent to Bob
+    char p[NTHREADS][MAXSIZE];
+    octet P[NTHREADS];
+
+    // BLS signature
+    char s[NTHREADS][SIGLEN];
+    octet S[NTHREADS];
+
+    // Initialise seed
+    for(i=0; i<NTHREADS; i++)
+    {
+        for(int j=0; j<PQNIST_SEED_LENGTH; j++)
+        {
+            seed[i][j] = i;
+        }
+    }
+
+    // Generate BLS keys
+
+    // Alice's BLS keys
+    char BLSsk[NTHREADS][BGS_BLS381];
+    char BLSpk[NTHREADS][G2LEN];
+
+    #pragma omp parallel for
+    for(i=0; i<NTHREADS; i++)
+    {
+
+        rc = pqnist_bls_keys(seed[i], BLSpk[i], BLSsk[i]);
+        if (rc)
+        {
+            fprintf(stderr, "FAILURE pqnist_keys rc: %d\n", rc);
+            exit(EXIT_FAILURE);
+        }
+
+        printf("BLS pklen %d pk: ", G2LEN);
+        amcl_print_hex(BLSpk[i], G2LEN);
+        printf("BLS sklen %d BLS sk: ", BGS_BLS381);
+        amcl_print_hex(BLSsk[i], BGS_BLS381);
+        printf("\n");
+    }
+
+    // Alice
+
+    for(i=0; i<NTHREADS; i++)
+    {
+        bzero(p[i],sizeof(p[i]));
+        P[i].max = MAXSIZE;
+        P[i].len = sprintf(p[i], "Hello Bob! This is a message from Alice %d", i);
+        P[i].val = p[i];
+        printf("Alice Plaintext: ");
+        OCT_output_string(&P[i]);
+        printf("\n");
+    }
+
+    for(i=0; i<NTHREADS; i++)
+    {
+        bzero(s[i],sizeof(s[i]));
+        S[i].max = SIGLEN;
+        S[i].len = SIGLEN;
+        S[i].val = s[i];
+    }
+
+    #pragma omp parallel for
+    for(i=0; i<NTHREADS; i++)
+    {
+        // Alice signs message
+        rc = pqnist_bls_sign(P[i].val, BLSsk[i], S[i].val);
+        if(rc)
+        {
+            fprintf(stderr, "FAILURE pqnist_bls_sign rc: %d\n", rc);
+            exit(EXIT_FAILURE);
+        }
+        printf("Alice SIGlen %d  SIG", S[i].len);
+        OCT_output(&S[i]);
+        printf("\n");
+    }
+
+    #pragma omp parallel for
+    for(i=0; i<NTHREADS; i++)
+    {
+        // Bob verifies message
+        rc = pqnist_bls_verify(P[i].val, BLSpk[i], S[i].val);
+        if (rc)
+        {
+            fprintf(stderr, "FAILURE pqnist_bls_verify rc: %d\n", rc);
+            exit(EXIT_FAILURE);
+        }
+        else
+        {
+            printf("Test %d pqnist_bls_verify rc: %d\n", i, rc);
+            OCT_output_string(&P[i]);
+            printf("\n");
+        }
+    }
+
+    // clear memory
+    for(i=0; i<NTHREADS; i++)
+    {
+        OCT_clear(&P[i]);
+        OCT_clear(&S[i]);
+    }
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/test/smoke/test_bls_add.c b/libs/crypto/libpqnist/test/smoke/test_bls_add.c
new file mode 100644
index 0000000..956f455
--- /dev/null
+++ b/libs/crypto/libpqnist/test/smoke/test_bls_add.c
@@ -0,0 +1,216 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   Sign a message and verify the signature. 
+   Generate a public key from externally generated secret key
+   Add public keys and signatures.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/bls_BLS381.h>
+#include <amcl/pqnist.h>
+
+#define G2LEN 4*BFS_BLS381
+#define SIGLEN BFS_BLS381+1
+
+int main()
+{
+    int rc;
+
+    // Seed values for CSPRNG
+    char seed1[PQNIST_SEED_LENGTH];
+    char seed2[PQNIST_SEED_LENGTH];
+
+    // Message to be signed
+    char message[] = "test message";
+
+    // seed values
+    char* seed1Hex = "3370f613c4fe81130b846483c99c032c17dcc1904806cc719ed824351c87b0485c05089aa34ba1e1c6bfb6d72269b150";
+    char* seed2Hex = "46389f32b7cdebbbc46b7165d8fae888c9de444898390a939977e1a066256a6f465e7d76307178aef81ae0c6841f9b7c";
+    amcl_hex2bin(seed1Hex, seed1, PQNIST_SEED_LENGTH*2);
+    amcl_hex2bin(seed2Hex, seed2, PQNIST_SEED_LENGTH*2);
+    printf("seed1: ");
+    amcl_print_hex(seed1, PQNIST_SEED_LENGTH);
+    printf("seed2: ");
+    amcl_print_hex(seed2, PQNIST_SEED_LENGTH);
+    printf("\n");
+
+    // BLS keys
+    char sk1[BGS_BLS381];
+    char pktmp[G2LEN];    
+    char pk1[G2LEN];
+    char sk2[BGS_BLS381];
+    char pk2[G2LEN];
+    char pk12[G2LEN];
+
+    // BLS signature
+    char sig1[SIGLEN];
+    char sig2[SIGLEN];
+    char sig12[SIGLEN];
+
+    rc = pqnist_bls_keys(seed1, pktmp, sk1);
+    if (rc)
+    {
+        fprintf(stderr, "FAILURE pqnist_keys rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = pqnist_bls_keys(seed2, pk2, sk2);
+    if (rc)
+    {
+        fprintf(stderr, "FAILURE pqnist_keys rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    // Generate pk from sk 
+    rc = pqnist_bls_keys(NULL, pk1, sk1);
+    if (rc)
+    {
+        fprintf(stderr, "ERROR pqnist_keys rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }    
+
+    printf("sk1: ");
+    amcl_print_hex(sk1, BGS_BLS381);    
+    printf("pktmp: ");
+    amcl_print_hex(pktmp, G2LEN);
+    printf("pk1: ");
+    amcl_print_hex(pk1, G2LEN);
+    printf("sk2: ");
+    amcl_print_hex(sk2, BGS_BLS381);    
+    printf("pk2: ");
+    amcl_print_hex(pk2, G2LEN);
+    printf("\n");
+
+    octet PK1 = {sizeof(pk1),sizeof(pk1),pk1};
+    octet PKTMP = {sizeof(pktmp),sizeof(pktmp),pktmp};    
+    rc = OCT_comp(&PK1,&PKTMP);
+    if(!rc)
+    {
+        fprintf(stderr, "FAILURE PK1 != PKTMP rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+    
+    // Sign message
+    rc = pqnist_bls_sign(message, sk1, sig1);
+    if(rc != BLS_OK)
+    {
+        fprintf(stderr, "FAILURE pqnist_bls_sign rc: %d\n", rc);
+        printf("FAILURE\n");
+        exit(EXIT_FAILURE);
+    }
+
+    rc = pqnist_bls_sign(message, sk2, sig2);
+    if(rc != BLS_OK)
+    {
+        fprintf(stderr, "FAILURE pqnist_bls_sign rc: %d\n", rc);
+        printf("FAILURE\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("sig1: ");
+    amcl_print_hex(sig1, SIGLEN);
+    printf("sig2: ");
+    amcl_print_hex(sig2, SIGLEN);
+    printf("\n");
+
+    // Verify message
+    rc = pqnist_bls_verify(message, pk1, sig1);
+    if (rc != BLS_OK)
+    {
+        fprintf(stderr, "FAILURE pqnist_bls_verify rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = pqnist_bls_verify(message, pk2, sig2);
+    if (rc != BLS_OK)
+    {
+        fprintf(stderr, "FAILURE pqnist_bls_verify rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = pqnist_bls_addg1(sig1, sig2, sig12);
+    if (rc != BLS_OK)
+    {
+        fprintf(stderr, "FAILURE pqnist_bls_addg1 rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = pqnist_bls_addg2(pk1, pk2, pk12);
+    if (rc != BLS_OK)
+    {
+        fprintf(stderr, "FAILURE pqnist_bls_addg1 rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("pk12: ");
+    amcl_print_hex(pk12, G2LEN);
+    printf("sig12: ");
+    amcl_print_hex(sig12, SIGLEN);
+    printf("\n");
+
+    rc = pqnist_bls_verify(message, pk12, sig12);
+    if (rc != BLS_OK)
+    {
+        fprintf(stderr, "FAILURE pqnist_bls_verify rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    char* pk12GoldenHex = "0fff41dc3b28fee38f564158f9e391a5c6ac42179fcccdf5ee4513030b6d59900a832f9a886b2407dc8b0a3b51921326123d3974bd1864fb22f5a84e83f1f9f611ee082ed5bd6ca896d464f12907ba8acdf15c44f9cff2a2dbb3b32259a1fe4f11d470158066087363df20a11144d6521cf72dca1a7514154a95c7fe73b219989cc40d7fc7e0b97854fc3123c0cf50ae0452730996a5cb24641aff7102fcbb2af705d0f32d5787ca1c3654e4ae6aa59106e1e22e29018ba7c341f1e6472f800f";
+    char* sig12GoldenHex = "0203799dc2941b810985d9eb694a5be4a1ad5817f9e5d7c31870bb9fb471f7353eafacdc548544f9e7b78a0a9372c63ab0";
+
+    char pk12golden[G2LEN];
+    octet PK12GOLDEN = {sizeof(pk12golden),sizeof(pk12golden),pk12golden};
+
+    char sig12golden[SIGLEN];
+    octet SIG12GOLDEN = {sizeof(sig12golden),sizeof(sig12golden),sig12golden};
+
+    OCT_fromHex(&PK12GOLDEN,pk12GoldenHex);
+    printf("PK12GOLDEN: ");
+    OCT_output(&PK12GOLDEN);
+
+    OCT_fromHex(&SIG12GOLDEN,sig12GoldenHex);
+    printf("SIG12GOLDEN: ");
+    OCT_output(&SIG12GOLDEN);
+
+    octet PK12 = {sizeof(pk12),sizeof(pk12),pk12};
+    octet SIG12 = {sizeof(sig12),sizeof(sig12),sig12};
+
+    rc = OCT_comp(&PK12GOLDEN,&PK12);
+    if(!rc)
+    {
+        fprintf(stderr, "FAILURE PK12 != PK12GOLDEN rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = OCT_comp(&SIG12GOLDEN,&SIG12);
+    if(!rc)
+    {
+        fprintf(stderr, "FAILURE SIG12 != SIG12GOLDEN rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/test/smoke/test_bls_sss.c b/libs/crypto/libpqnist/test/smoke/test_bls_sss.c
new file mode 100644
index 0000000..21d44ae
--- /dev/null
+++ b/libs/crypto/libpqnist/test/smoke/test_bls_sss.c
@@ -0,0 +1,187 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   BLS SSS example
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/bls_BLS381.h>
+#include <amcl/pqnist.h>
+
+#define G2LEN 4*BFS_BLS381
+#define SIGLEN BFS_BLS381+1
+
+int main()
+{
+    int rc;
+    int n=4;
+    int k=3;
+
+    // Seed value for CSPRNG
+    char seed[PQNIST_SEED_LENGTH];
+
+    // Message to be sent to Bob
+    char p[] = "This is a test message";
+    octet P = {0, sizeof(p), p};
+
+    // non random seed value
+    for (int i=0; i<PQNIST_SEED_LENGTH; i++) seed[i]=i+1;
+    printf("SEED: ");
+    amcl_print_hex(seed, PQNIST_SEED_LENGTH);
+    printf("\n");
+
+    // BLS keys
+    char ski[BGS_BLS381];
+    char sko[BGS_BLS381];
+    char skr[BGS_BLS381];
+    char pki[G2LEN];
+
+    // BLS signature
+    char sigi[SIGLEN];
+    char sigr[SIGLEN];
+
+    // Octets for testing
+    octet SKI = {BGS_BLS381, BGS_BLS381, ski};
+    octet SKR = {BGS_BLS381, BGS_BLS381, skr};
+    octet SIGI = {SIGLEN, SIGLEN, sigi};
+    octet SIGR = {SIGLEN, SIGLEN, sigr};
+
+    rc = pqnist_bls_keys(seed, pki, ski);
+    if (rc)
+    {
+        fprintf(stderr, "FAILURE pqnist_keys rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("pki: ");
+    amcl_print_hex(pki, G2LEN);
+    printf("ski: ");
+    amcl_print_hex(ski, BGS_BLS381);
+    printf("\n");
+
+    // Alice signs message
+    rc = pqnist_bls_sign(P.val, ski, sigi);
+    if(rc != BLS_OK)
+    {
+        fprintf(stderr, "FAILURE pqnist_bls_sign rc: %d\n", rc);
+        printf("FAILURE\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("sigi ");
+    amcl_print_hex(sigi, SIGLEN);
+    printf("\n");
+
+    // Bob verifies message
+    rc = pqnist_bls_verify(P.val, pki, sigi);
+    if (rc != BLS_OK)
+    {
+        fprintf(stderr, "FAILURE pqnist_bls_verify rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    // Secret shares
+    char x[BGS_BLS381*n];
+    char y[BGS_BLS381*n];
+
+    // Make shares of BLS secret key
+    rc = pqnist_bls_make_shares(k, n, seed, x, y, ski, sko);
+    if (rc!=BLS_OK)
+    {
+        fprintf(stderr, "FAILURE pqnist_bls_make_shares rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("ski: ");
+    amcl_print_hex(ski, BGS_BLS381);
+    printf("sko: ");
+    amcl_print_hex(sko, BGS_BLS381);
+    printf("\n");
+
+    for(int i=0; i<n; i++)
+    {
+        printf("x[%d] ", i);
+        amcl_print_hex(&x[i*BGS_BLS381], BGS_BLS381);
+        printf("y[%d] ", i);
+        amcl_print_hex(&y[i*BGS_BLS381], BGS_BLS381);
+        printf("\n");
+    }
+
+    // Recover BLS secret key
+    rc = pqnist_bls_recover_secret(k, x, y, skr);
+    if (rc!=BLS_OK)
+    {
+        fprintf(stderr, "FAILURE pqnist_bls_recover_secret rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+    printf("skr: ");
+    amcl_print_hex(skr, BGS_BLS381);
+    printf("\n");
+
+    rc = OCT_comp(&SKI,&SKR);
+    if(!rc)
+    {
+        fprintf(stderr, "FAILURE SKI != SKR rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+
+    // Generate public keys and signatures using shares
+    char sigs[(SIGLEN)*n];
+    for(int i=0; i<n; i++)
+    {
+        rc = pqnist_bls_sign(P.val, &y[BFS_BLS381*i], &sigs[(SIGLEN)*i]);
+        if(rc != BLS_OK)
+        {
+            fprintf(stderr, "FAILURE pqnist_bls_sign rc: %d\n", rc);
+            printf("FAILURE\n");
+            exit(EXIT_FAILURE);
+        }
+
+    }
+
+    for(int i=0; i<n; i++)
+    {
+        printf("sigs[%d] ", i);
+        amcl_print_hex(&sigs[i*(SIGLEN)], SIGLEN);
+        printf("\n");
+    }
+
+    // Recover BLS signature
+    pqnist_bls_recover_signature(k, x, sigs, sigr);
+
+    printf("sigr ");
+    amcl_print_hex(sigr, SIGLEN);
+    printf("\n");
+
+    rc = OCT_comp(&SIGI,&SIGR);
+    if(!rc)
+    {
+        fprintf(stderr, "FAILURE SIGI != SIGR rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/test/smoke/test_encap_decap.c b/libs/crypto/libpqnist/test/smoke/test_encap_decap.c
new file mode 100644
index 0000000..51ca608
--- /dev/null
+++ b/libs/crypto/libpqnist/test/smoke/test_encap_decap.c
@@ -0,0 +1,205 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   Encapsulate a secret and use the secret to encrypt a message
+   Decapsulate the secret and use the secret to decrypt the encrypted message
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/bls_BLS381.h>
+#include <oqs/oqs.h>
+#include <amcl/pqnist.h>
+
+#define NTHREADS 8
+#define MAXSIZE 256
+#define G2LEN 4*BFS_BLS381
+
+int main()
+{
+    int i,rc;
+
+    // Seed value for CSPRNG
+    char seed[PQNIST_SEED_LENGTH];
+    octet SEED = {sizeof(seed),sizeof(seed),seed};
+
+    // Seed value for key generation
+    char seedkeys[NTHREADS][PQNIST_SEED_LENGTH];
+
+    csprng RNG;
+
+    // Initialization vector
+    char iv[PQNIST_AES_IV_LENGTH];
+    octet IV= {sizeof(iv),sizeof(iv),iv};
+
+    // Message to be sent to Bob
+    char p[NTHREADS][MAXSIZE];
+    octet P[NTHREADS];
+
+    // AES CBC ciphertext
+    char c[NTHREADS][MAXSIZE];
+    octet C[NTHREADS];
+
+    // non random seed value
+    for (i=0; i<32; i++) SEED.val[i]=i+1;
+    printf("SEED: ");
+    OCT_output(&SEED);
+    printf("\n");
+
+    // initialise random number generator
+    CREATE_CSPRNG(&RNG,&SEED);
+
+    // Initialise key generation seed
+    for(i=0; i<NTHREADS; i++)
+    {
+        for(int j=0; j<PQNIST_SEED_LENGTH; j++)
+        {
+            seedkeys[i][j] = i;
+        }
+    }
+
+    // Bob's SIKE keys
+    uint8_t SIKEpk[NTHREADS][OQS_KEM_sike_p751_length_public_key];
+    uint8_t SIKEsk[NTHREADS][OQS_KEM_sike_p751_length_secret_key];
+
+    #pragma omp parallel for
+    for(i=0; i<NTHREADS; i++)
+    {
+        rc = pqnist_sike_keys(seedkeys[i], SIKEpk[i], SIKEsk[i]);
+        if (rc)
+        {
+            fprintf(stderr, "FAILURE pqnist_keys rc: %d\n", rc);
+            OQS_MEM_cleanse(SIKEsk[i], OQS_KEM_sike_p751_length_secret_key);
+            exit(EXIT_FAILURE);
+        }
+
+        int j = OQS_KEM_sike_p751_length_public_key;
+        printf("Bob SIKE pklen %d pk: ", j);
+        amcl_print_hex(SIKEpk[i], j);
+        j = OQS_KEM_sike_p751_length_secret_key;
+        printf("Bob SIKE sklen %d sk: ", j);
+        amcl_print_hex(SIKEsk[i], j);
+
+    }
+
+    // Alice
+
+    for(i=0; i<NTHREADS; i++)
+    {
+        bzero(p[i],sizeof(p[i]));
+        P[i].max = MAXSIZE;
+        P[i].len = sprintf(p[i], "Hello Bob! This is a message from Alice %d", i);
+        P[i].val = p[i];
+        // Pad message
+        int l = 16 - (P[i].len % 16);
+        if (l < 16)
+        {
+            OCT_jbyte(&P[i],0,l);
+        }
+    }
+
+    // Random initialization value
+    generateRandom(&RNG,&IV);
+    printf("Alice IV: ");
+    OCT_output(&IV);
+
+    // Copy plaintext
+    for(i=0; i<NTHREADS; i++)
+    {
+        C[i].val = c[i];
+        C[i].max = MAXSIZE;
+        OCT_copy(&C[i],&P[i]);
+        printf("Alice Plaintext: ");
+        OCT_output_string(&C[i]);
+        printf("\n");
+    }
+
+    // SIKE encapsulated key
+    uint8_t ek[NTHREADS][OQS_KEM_sike_p751_length_ciphertext];
+
+    #pragma omp parallel for
+    for(i=0; i<NTHREADS; i++)
+    {
+
+        // Generate an AES which is ecapsulated using SIKE. Use this key to
+        // AES encrypt the K parameter.
+        rc = pqnist_encapsulate_encrypt(C[i].val, C[i].len, IV.val, SIKEpk[i], ek[i]);
+        if(rc)
+        {
+            fprintf(stderr, "FAILURE pqnist_encapsulate_encrypt rc: %d\n", rc);
+            exit(EXIT_FAILURE);
+        }
+
+        printf("Alice ciphertext: ");
+        OCT_output(&C[i]);
+
+        printf("Alice ek %lu ek: ", sizeof(ek[i]));
+        amcl_print_hex(ek[i], sizeof(ek[i]));
+        printf("\n");
+
+    }
+
+    // Bob
+
+    #pragma omp parallel for
+    for(i=0; i<NTHREADS; i++)
+    {
+        // Obtain encapsulated AES key and decrypt C
+        rc = pqnist_decapsulate_decrypt(C[i].val, C[i].len, IV.val, SIKEsk[i], ek[i]);
+        if(rc)
+        {
+            fprintf(stderr, "FAILURE pqnist_decapsulate_decrypt rc: %d\n", rc);
+            exit(EXIT_FAILURE);
+        }
+
+        printf("Bob Plaintext: ");
+        OCT_output(&C[i]);
+
+        printf("Bob Plaintext: ");
+        OCT_output_string(&C[i]);
+        printf("\n");
+
+        // Compare sent and recieved message (returns 0 for failure)
+        rc = OCT_comp(&P[i],&C[i]);
+        if(!rc)
+        {
+            fprintf(stderr, "FAILURE OCT_comp rc: %d\n", rc);
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    // clear memory
+
+    OCT_clear(&IV);
+    for(i=0; i<NTHREADS; i++)
+    {
+        OQS_MEM_cleanse(SIKEsk[i], OQS_KEM_sike_p751_length_secret_key);
+        OCT_clear(&P[i]);
+        OCT_clear(&C[i]);
+    }
+
+    KILL_CSPRNG(&RNG);
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/test/smoke/test_pqnist.c b/libs/crypto/libpqnist/test/smoke/test_pqnist.c
new file mode 100644
index 0000000..69f1dae
--- /dev/null
+++ b/libs/crypto/libpqnist/test/smoke/test_pqnist.c
@@ -0,0 +1,225 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/*
+   Run through the flow of encrypting, ecapsulating and signing a message
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/bls_BLS381.h>
+#include <oqs/oqs.h>
+#include <amcl/pqnist.h>
+
+#define G2LEN 4*BFS_BLS381
+#define SIGLEN BFS_BLS381+1
+
+int main()
+{
+    int i,rc;
+
+    // Seed value for CSPRNG
+    char seed[PQNIST_SEED_LENGTH];
+    octet SEED = {sizeof(seed),sizeof(seed),seed};
+
+    csprng RNG;
+
+    // AES Key
+    char k[PQNIST_AES_KEY_LENGTH];
+    octet K= {0,sizeof(k),k};
+
+    // Initialization vectors
+    char iv[PQNIST_AES_IV_LENGTH];
+    octet IV= {0,sizeof(iv),iv};
+    char iv2[PQNIST_AES_IV_LENGTH];
+    octet IV2= {0,sizeof(iv2),iv2};
+
+    // Message to be sent to Bob
+    char p[256];
+    octet P = {0, sizeof(p), p};
+    OCT_jstring(&P,"Hello Bob! This is a message from Alice");
+
+    // Pad message
+    int l = 16 - (P.len % 16);
+    if (l < 16)
+    {
+        OCT_jbyte(&P,0,l);
+    }
+
+    // AES CBC ciphertext
+    char c[256];
+    octet C = {0, sizeof(c), c};
+
+    // non random seed value
+    for (i=0; i<PQNIST_SEED_LENGTH; i++) SEED.val[i]=i+1;
+    printf("SEED: ");
+    OCT_output(&SEED);
+    printf("\n");
+
+    // initialise random number generator
+    CREATE_CSPRNG(&RNG,&SEED);
+
+    // Generate 256 bit AES Key
+    K.len=PQNIST_AES_KEY_LENGTH;
+    generateRandom(&RNG,&K);
+
+    // Generate SIKE and BLS keys
+
+    // Bob's SIKE keys
+    uint8_t SIKEpk[OQS_KEM_sike_p751_length_public_key];
+    uint8_t SIKEsk[OQS_KEM_sike_p751_length_secret_key];
+
+    // Alice's BLS keys
+    char BLSsk[BGS_BLS381];
+    char BLSpk[G2LEN];
+
+    rc = pqnist_sike_keys(seed, SIKEpk, SIKEsk);
+    if (rc)
+    {
+        fprintf(stderr, "FAILURE pqnist_sike_keys rc: %d\n", rc);
+        printf("FAILURE\n");
+        exit(EXIT_FAILURE);
+    }
+
+    rc = pqnist_bls_keys(seed, BLSpk, BLSsk);
+    if (rc)
+    {
+        fprintf(stderr, "FAILURE pqnist_bls_keys rc: %d\n", rc);
+        printf("FAILURE\n");
+        exit(EXIT_FAILURE);
+    }
+
+    // BLS signature
+    char S[SIGLEN];
+
+    // SIKE encapsulated key
+    uint8_t ek[OQS_KEM_sike_p751_length_ciphertext];
+
+    // Alice
+
+    printf("Alice Key: ");
+    amcl_print_hex(K.val, K.len);
+
+    // Random initialization value
+    IV.len=PQNIST_AES_IV_LENGTH;
+    generateRandom(&RNG,&IV);
+    printf("Alice IV: ");
+    OCT_output(&IV);
+
+    printf("Alice Plaintext: ");
+    OCT_output(&P);
+
+    printf("Alice Plaintext: ");
+    OCT_output_string(&P);
+    printf("\n");
+
+    // Copy plaintext
+    OCT_copy(&C,&P);
+
+    // Encrypt plaintext
+    pqnist_aes_cbc_encrypt(K.val, K.len, IV.val, C.val, C.len);
+
+    printf("Alice Ciphertext: ");
+    OCT_output(&C);
+
+    generateRandom(&RNG,&IV2);
+    printf("Alice IV2: ");
+    OCT_output(&IV2);
+
+    // Generate an AES which is ecapsulated using SIKE. Use this key to
+    // AES encrypt the K parameter.
+    rc = pqnist_encapsulate_encrypt(K.val, K.len, IV2.val, SIKEpk, ek);
+    if(rc)
+    {
+        fprintf(stderr, "FAILURE pqnist_encapsulate_encrypt rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("Alice encrypted key: ");
+    OCT_output(&K);
+
+    // Bob
+
+    // Obtain encapsulated AES key and decrypt K
+    rc = pqnist_decapsulate_decrypt(K.val, K.len, IV2.val, SIKEsk, ek);
+    if(rc)
+    {
+        fprintf(stderr, "FAILURE pqnist_decapsulate_decrypt rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("Bob Key: ");
+    amcl_print_hex(K.val, K.len);
+
+    printf("Bob IV ");
+    OCT_output(&IV);
+
+    printf("Bob Ciphertext: ");
+    OCT_output(&P);
+
+    pqnist_aes_cbc_decrypt(K.val, K.len, IV.val, C.val, C.len);
+
+    printf("Bob Plaintext: ");
+    OCT_output(&C);
+
+    printf("Bob Plaintext: ");
+    OCT_output_string(&C);
+    printf("\n");
+
+    // Compare sent and recieved message (returns 0 for failure)
+    rc = OCT_comp(&P,&C);
+    if(!rc)
+    {
+        fprintf(stderr, "FAILURE OCT_comp rc: %d\n", rc);
+        printf("FAILURE\n");
+        exit(EXIT_FAILURE);
+    }
+
+    // Sign message
+
+    // Alice signs message
+    rc = pqnist_bls_sign(P.val, BLSsk, S);
+    if(rc)
+    {
+        fprintf(stderr, "FAILURE pqnist_bls_sign rc: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    // Bob verifies message
+    rc = pqnist_bls_verify(P.val, BLSpk, S);
+    if (rc)
+    {
+        fprintf(stderr, "FAILURE: verify failed!\n errorCode %d", rc);
+        printf("FAILURE\n");
+        exit(EXIT_FAILURE);
+    }
+
+    // clear memory
+    OQS_MEM_cleanse(SIKEsk, OQS_KEM_sike_p751_length_secret_key);
+    OCT_clear(&K);
+    OCT_clear(&IV);
+    OCT_clear(&P);
+    KILL_CSPRNG(&RNG);
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/test/unit/CMakeLists.txt b/libs/crypto/libpqnist/test/unit/CMakeLists.txt
new file mode 100644
index 0000000..9f233cc
--- /dev/null
+++ b/libs/crypto/libpqnist/test/unit/CMakeLists.txt
@@ -0,0 +1,42 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Add the binary tree directory to the search path for linking and include files
+link_directories (${PROJECT_BINARY_DIR}/src
+                  /usr/local/lib)
+
+include_directories (${PROJECT_SOURCE_DIR}/include
+                     /usr/local/include)
+
+function(amcl_test name source dependencies expected_response)
+  add_executable(${name} "${source}")
+
+  target_link_libraries(${name} PRIVATE ${dependencies})
+
+  add_test(NAME ${name}
+    COMMAND ${TARGET_SYSTEM_EMULATOR} $<TARGET_FILE:${name}> ${ARGN}
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/testVectors
+  )
+
+  set_tests_properties(${name} PROPERTIES
+    PASS_REGULAR_EXPRESSION "${expected_response}"
+  )
+endfunction()
+
+amcl_test(test_aes_encrypt_CBC_256  test_aes_encrypt.c pqnist "SUCCESS" "aes/CBCMMT256.rsp")
+amcl_test(test_aes_decrypt_CBC_256  test_aes_decrypt.c pqnist "SUCCESS" "aes/CBCMMT256.rsp")
+
diff --git a/libs/crypto/libpqnist/test/unit/test_aes_decrypt.c b/libs/crypto/libpqnist/test/unit/test_aes_decrypt.c
new file mode 100644
index 0000000..8f36a2f
--- /dev/null
+++ b/libs/crypto/libpqnist/test/unit/test_aes_decrypt.c
@@ -0,0 +1,229 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/**
+ * @file test_aes_decrypto.c
+ * @author Kealan McCusker
+ * @brief Test function for AES decryption,
+ *
+ * LICENSE
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/pqnist.h>
+
+#define LINE_LEN 500
+//#define DEBUG
+
+int main(int argc, char** argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_aes_decrypt [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    bool readLine;
+    FILE * fp = NULL;
+    char line[LINE_LEN];
+    char * linePtr = NULL;
+    int l1=0;
+
+    char * KEY = NULL;
+    int KEYLen = 0;
+    const char* KEYStr = "KEY = ";
+
+    char * IV = NULL;
+    int IVLen = 0;
+    const char* IVStr = "IV = ";
+
+    char * CIPHERTEXT = NULL;
+    int CIPHERTEXTLen = 0;
+    const char* CIPHERTEXTStr = "CIPHERTEXT = ";
+
+    char * PLAINTEXT1 = NULL;
+    const char* PLAINTEXTStr = "PLAINTEXT = ";
+    const char* DECRYPTStr = "[DECRYPT]";
+
+    // Open file
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int lineNo=0;
+    readLine = false;
+    while ( (fgets(line, LINE_LEN, fp) != NULL))
+    {
+        if (!strncmp(line, DECRYPTStr,strlen(DECRYPTStr)))
+        {
+#ifdef DEBUG
+            printf("line %d %s\n", lineNo,line);
+#endif
+            readLine = true;
+        }
+
+        if(!readLine)
+            continue;
+
+        if (!strncmp(line, KEYStr, strlen(KEYStr)))
+        {
+#ifdef DEBUG
+            printf("line %d %s\n", lineNo,line);
+#endif
+            // Find hex value in string
+            linePtr = line + strlen(KEYStr);
+
+            // Allocate memory
+            l1 = strlen(linePtr)-1;
+            KEYLen = l1/2;
+            KEY = (char*) malloc (KEYLen);
+            if (KEY==NULL)
+                exit(EXIT_FAILURE);
+
+            // KEY binary value
+            amcl_hex2bin(linePtr, KEY, l1);
+        }
+
+        if (!strncmp(line, IVStr, strlen(IVStr)))
+        {
+#ifdef DEBUG
+            printf("line %d %s\n", lineNo,line);
+#endif
+            // Find hex value in string
+            linePtr = line + strlen(IVStr);
+
+            // Allocate memory
+            l1 = strlen(linePtr)-1;
+            IVLen = l1/2;
+            IV = (char*) malloc (IVLen);
+            if (IV==NULL)
+                exit(EXIT_FAILURE);
+
+            // IV binary value
+            amcl_hex2bin(linePtr, IV, l1);
+        }
+
+        if (!strncmp(line, CIPHERTEXTStr, strlen(CIPHERTEXTStr)))
+        {
+#ifdef DEBUG
+            printf("line %d %s\n", lineNo,line);
+#endif
+            // Find hex value in string
+            linePtr = line + strlen(CIPHERTEXTStr);
+
+            // Allocate memory
+            l1 = strlen(linePtr)-1;
+            CIPHERTEXTLen = l1/2;
+            CIPHERTEXT = (char*) malloc (CIPHERTEXTLen);
+            if (CIPHERTEXT==NULL)
+                exit(EXIT_FAILURE);
+
+            // CIPHERTEXT binary value
+            amcl_hex2bin(linePtr, CIPHERTEXT, l1);
+        }
+
+        if (!strncmp(line, PLAINTEXTStr, strlen(PLAINTEXTStr)))
+        {
+#ifdef DEBUG
+            printf("line %d %s\n", lineNo,line);
+#endif
+            // Find hex value in string
+            linePtr = line + strlen(PLAINTEXTStr);
+
+            // Allocate memory
+            l1 = strlen(linePtr);
+            PLAINTEXT1 = (char*) malloc(CIPHERTEXTLen+1);
+            if (PLAINTEXT1==NULL)
+                exit(EXIT_FAILURE);
+
+            // Golden PLAINTEXT value
+            octet PLAINTEXT1Oct= {CIPHERTEXTLen,CIPHERTEXTLen,PLAINTEXT1};
+            amcl_hex2bin(linePtr, PLAINTEXT1, l1);
+
+#ifdef DEBUG
+            printf("KEY = ");
+            amcl_print_hex(KEY, KEYLen);
+            printf("IV = ");
+            amcl_print_hex(IV, IVLen);
+            printf("CIPHERTEXT = ");
+            amcl_print_hex(CIPHERTEXT, CIPHERTEXTLen);
+            printf("CIPHERTEXTLen = %d  blocks %0.2f \n", CIPHERTEXTLen, (float) CIPHERTEXTLen/16);
+#endif
+
+            // Decrypt
+            pqnist_aes_cbc_decrypt(KEY, KEYLen, IV, CIPHERTEXT, CIPHERTEXTLen);
+            octet PLAINTEXTOct= {CIPHERTEXTLen,CIPHERTEXTLen,CIPHERTEXT};
+
+#ifdef DEBUG
+            printf("PLAINTEXT = ");
+            amcl_print_hex(CIPHERTEXT, CIPHERTEXTLen);
+            printf("\n\n");
+#endif
+
+            int rc = OCT_comp(&PLAINTEXTOct,&PLAINTEXT1Oct);
+            if (!rc)
+            {
+                printf("TEST AES DECRYPT FAILED COMPARE PLAINTEXT LINE %d\n",lineNo);
+                exit(EXIT_FAILURE);
+            }
+
+            free(KEY);
+            KEY = NULL;
+            free(IV);
+            IV = NULL;
+            free(CIPHERTEXT);
+            CIPHERTEXT = NULL;
+            free(PLAINTEXT1);
+            PLAINTEXT1 = NULL;
+        }
+        lineNo++;
+    }
+    fclose(fp);
+    if (!readLine)
+    {
+        printf("ERROR Empty test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+    printf("SUCCESS TEST AES %s DECRYPT PASSED\n", argv[2]);
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/test/unit/test_aes_encrypt.c b/libs/crypto/libpqnist/test/unit/test_aes_encrypt.c
new file mode 100644
index 0000000..1b1ae0e
--- /dev/null
+++ b/libs/crypto/libpqnist/test/unit/test_aes_encrypt.c
@@ -0,0 +1,230 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/**
+ * @file test_aes_encrypt.c
+ * @author Kealan McCusker
+ * @brief Test function for AES encryption,
+ *
+ * LICENSE
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/pqnist.h>
+
+#define LINE_LEN 500
+//#define DEBUG
+
+int main(int argc, char** argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_aes_encrypt [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    bool readLine;
+    FILE * fp = NULL;
+    char line[LINE_LEN];
+    char * linePtr = NULL;
+    int l1=0;
+
+    char * KEY = NULL;
+    int KEYLen = 0;
+    const char* KEYStr = "KEY = ";
+
+    char * IV = NULL;
+    int IVLen = 0;
+    const char* IVStr = "IV = ";
+
+    char * PLAINTEXT = NULL;
+    int PLAINTEXTLen = 0;
+    const char* PLAINTEXTStr = "PLAINTEXT = ";
+
+    char * CIPHERTEXT1 = NULL;
+    const char* CIPHERTEXTStr = "CIPHERTEXT = ";
+    const char* DECRYPTStr = "[DECRYPT]";
+
+    // Open file
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int lineNo=0;
+    readLine = true;
+    while ( (fgets(line, LINE_LEN, fp) != NULL))
+    {
+        if (!strncmp(line, DECRYPTStr,strlen(DECRYPTStr)))
+        {
+#ifdef DEBUG
+            printf("line %d %s\n", lineNo,line);
+#endif
+            readLine = false;
+        }
+
+        if(!readLine)
+            continue;
+
+        if (!strncmp(line, KEYStr, strlen(KEYStr)))
+        {
+#ifdef DEBUG
+            printf("line %d %s\n", lineNo,line);
+#endif
+            // Find hex value in string
+            linePtr = line + strlen(KEYStr);
+
+            // Allocate memory
+            l1 = strlen(linePtr)-1;
+            KEYLen = l1/2;
+            KEY = (char*) malloc (KEYLen);
+            if (KEY==NULL)
+                exit(EXIT_FAILURE);
+
+            // KEY binary value
+            amcl_hex2bin(linePtr, KEY, l1);
+        }
+
+        if (!strncmp(line, IVStr, strlen(IVStr)))
+        {
+#ifdef DEBUG
+            printf("line %d %s\n", lineNo,line);
+#endif
+            // Find hex value in string
+            linePtr = line + strlen(IVStr);
+
+            // Allocate memory
+            l1 = strlen(linePtr)-1;
+            IVLen = l1/2;
+            IV = (char*) malloc (IVLen);
+            if (IV==NULL)
+                exit(EXIT_FAILURE);
+
+            // IV binary value
+            amcl_hex2bin(linePtr, IV, l1);
+        }
+
+        if (!strncmp(line, PLAINTEXTStr, strlen(PLAINTEXTStr)))
+        {
+#ifdef DEBUG
+            printf("line %d %s\n", lineNo,line);
+#endif
+            // Find hex value in string
+            linePtr = line + strlen(PLAINTEXTStr);
+
+            // Allocate memory
+            l1 = strlen(linePtr)-1;
+            PLAINTEXTLen = l1/2;
+            PLAINTEXT = (char*) malloc(PLAINTEXTLen);
+            if (PLAINTEXT==NULL)
+                exit(EXIT_FAILURE);
+
+            // PLAINTEXT binary value
+            amcl_hex2bin(linePtr, PLAINTEXT, l1);
+        }
+
+        if (!strncmp(line, CIPHERTEXTStr, strlen(CIPHERTEXTStr)))
+        {
+#ifdef DEBUG
+            printf("line %d %s\n", lineNo,line);
+#endif
+            // Find hex value in string
+            linePtr = line + strlen(CIPHERTEXTStr);
+
+            // Allocate memory
+            l1 = strlen(linePtr);
+            CIPHERTEXT1 = (char*) malloc(PLAINTEXTLen+1);
+            if (CIPHERTEXT1==NULL)
+                exit(EXIT_FAILURE);
+
+            // Golden CIPHERTEXT value
+            octet CIPHERTEXT1Oct= {PLAINTEXTLen,PLAINTEXTLen,CIPHERTEXT1};
+            amcl_hex2bin(linePtr, CIPHERTEXT1, l1);
+
+#ifdef DEBUG
+            printf("KEY = ");
+            amcl_print_hex(KEY, KEYLen);
+            printf("KEYLen = %d\n", KEYLen);
+            printf("IV = ");
+            amcl_print_hex(IV, IVLen);
+            printf("PLAINTEXT = ");
+            amcl_print_hex(PLAINTEXT, PLAINTEXTLen);
+            printf("PLAINTEXTLen = %d  blocks %0.2f \n", PLAINTEXTLen, (float) PLAINTEXTLen/16);
+#endif
+
+            // Encrypt
+            pqnist_aes_cbc_encrypt(KEY, KEYLen, IV, PLAINTEXT, PLAINTEXTLen);
+            octet CIPHERTEXTOct= {PLAINTEXTLen,PLAINTEXTLen,PLAINTEXT};
+
+#ifdef DEBUG
+            printf("CIPHERTEXT = ");
+            amcl_print_hex(PLAINTEXT, PLAINTEXTLen);
+            printf("\n\n");
+#endif
+
+            int rc = OCT_comp(&CIPHERTEXTOct,&CIPHERTEXT1Oct);
+            if (!rc)
+            {
+                printf("TEST AES ENCRYPT FAILED COMPARE CIPHERTEXT LINE %d\n",lineNo);
+                exit(EXIT_FAILURE);
+            }
+
+            free(KEY);
+            KEY = NULL;
+            free(IV);
+            IV = NULL;
+            free(PLAINTEXT);
+            PLAINTEXT = NULL;
+            free(CIPHERTEXT1);
+            CIPHERTEXT1 = NULL;
+        }
+        lineNo++;
+    }
+    fclose(fp);
+    if (readLine)
+    {
+        printf("ERROR No test vectors\n");
+        exit(EXIT_FAILURE);
+    }
+    printf("SUCCESS TEST ENCRYPT PASSED\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/libs/crypto/libpqnist/testVectors/aes/CBCMMT256.rsp b/libs/crypto/libpqnist/testVectors/aes/CBCMMT256.rsp
new file mode 100644
index 0000000..8f15f1a
--- /dev/null
+++ b/libs/crypto/libpqnist/testVectors/aes/CBCMMT256.rsp
@@ -0,0 +1,131 @@
+# CAVS 11.1
+# Config info for aes_values
+# AESVS MMT test data for CBC
+# State : Encrypt and Decrypt
+# Key Length : 256
+# Generated on Fri Apr 22 15:11:38 2011
+
+[ENCRYPT]
+
+COUNT = 0
+KEY = 6ed76d2d97c69fd1339589523931f2a6cff554b15f738f21ec72dd97a7330907
+IV = 851e8764776e6796aab722dbb644ace8
+PLAINTEXT = 6282b8c05c5c1530b97d4816ca434762
+CIPHERTEXT = 6acc04142e100a65f51b97adf5172c41
+
+COUNT = 1
+KEY = dce26c6b4cfb286510da4eecd2cffe6cdf430f33db9b5f77b460679bd49d13ae
+IV = fdeaa134c8d7379d457175fd1a57d3fc
+PLAINTEXT = 50e9eee1ac528009e8cbcd356975881f957254b13f91d7c6662d10312052eb00
+CIPHERTEXT = 2fa0df722a9fd3b64cb18fb2b3db55ff2267422757289413f8f657507412a64c
+
+COUNT = 2
+KEY = fe8901fecd3ccd2ec5fdc7c7a0b50519c245b42d611a5ef9e90268d59f3edf33
+IV = bd416cb3b9892228d8f1df575692e4d0
+PLAINTEXT = 8d3aa196ec3d7c9b5bb122e7fe77fb1295a6da75abe5d3a510194d3a8a4157d5c89d40619716619859da3ec9b247ced9
+CIPHERTEXT = 608e82c7ab04007adb22e389a44797fed7de090c8c03ca8a2c5acd9e84df37fbc58ce8edb293e98f02b640d6d1d72464
+
+COUNT = 3
+KEY = 0493ff637108af6a5b8e90ac1fdf035a3d4bafd1afb573be7ade9e8682e663e5
+IV = c0cd2bebccbb6c49920bd5482ac756e8
+PLAINTEXT = 8b37f9148df4bb25956be6310c73c8dc58ea9714ff49b643107b34c9bff096a94fedd6823526abc27a8e0b16616eee254ab4567dd68e8ccd4c38ac563b13639c
+CIPHERTEXT = 05d5c77729421b08b737e41119fa4438d1f570cc772a4d6c3df7ffeda0384ef84288ce37fc4c4c7d1125a499b051364c389fd639bdda647daa3bdadab2eb5594
+
+COUNT = 4
+KEY = 9adc8fbd506e032af7fa20cf5343719de6d1288c158c63d6878aaf64ce26ca85
+IV = 11958dc6ab81e1c7f01631e9944e620f
+PLAINTEXT = c7917f84f747cd8c4b4fedc2219bdbc5f4d07588389d8248854cf2c2f89667a2d7bcf53e73d32684535f42318e24cd45793950b3825e5d5c5c8fcd3e5dda4ce9246d18337ef3052d8b21c5561c8b660e
+CIPHERTEXT = 9c99e68236bb2e929db1089c7750f1b356d39ab9d0c40c3e2f05108ae9d0c30b04832ccdbdc08ebfa426b7f5efde986ed05784ce368193bb3699bc691065ac62e258b9aa4cc557e2b45b49ce05511e65
+
+COUNT = 5
+KEY = 73b8faf00b3302ac99855cf6f9e9e48518690a5906a4869d4dcf48d282faae2a
+IV = b3cb97a80a539912b8c21f450d3b9395
+PLAINTEXT = 3adea6e06e42c4f041021491f2775ef6378cb08824165edc4f6448e232175b60d0345b9f9c78df6596ec9d22b7b9e76e8f3c76b32d5d67273f1d83fe7a6fc3dd3c49139170fa5701b3beac61b490f0a9e13f844640c4500f9ad3087adfb0ae10
+CIPHERTEXT = ac3d6dbafe2e0f740632fd9e820bf6044cd5b1551cbb9cc03c0b25c39ccb7f33b83aacfca40a3265f2bbff879153448acacb88fcfb3bb7b10fe463a68c0109f028382e3e557b1adf02ed648ab6bb895df0205d26ebbfa9a5fd8cebd8e4bee3dc
+
+COUNT = 6
+KEY = 9ddf3745896504ff360a51a3eb49c01b79fccebc71c3abcb94a949408b05b2c9
+IV = e79026639d4aa230b5ccffb0b29d79bc
+PLAINTEXT = cf52e5c3954c51b94c9e38acb8c9a7c76aebdaa9943eae0a1ce155a2efdb4d46985d935511471452d9ee64d2461cb2991d59fc0060697f9a671672163230f367fed1422316e52d29eceacb8768f56d9b80f6d278093c9a8acd3cfd7edd8ebd5c293859f64d2f8486ae1bd593c65bc014
+CIPHERTEXT = 34df561bd2cfebbcb7af3b4b8d21ca5258312e7e2e4e538e35ad2490b6112f0d7f148f6aa8d522a7f3c61d785bd667db0e1dc4606c318ea4f26af4fe7d11d4dcff0456511b4aed1a0d91ba4a1fd6cd9029187bc5881a5a07fe02049d39368e83139b12825bae2c7be81e6f12c61bb5c5
+
+COUNT = 7
+KEY = 458b67bf212d20f3a57fce392065582dcefbf381aa22949f8338ab9052260e1d
+IV = 4c12effc5963d40459602675153e9649
+PLAINTEXT = 256fd73ce35ae3ea9c25dd2a9454493e96d8633fe633b56176dce8785ce5dbbb84dbf2c8a2eeb1e96b51899605e4f13bbc11b93bf6f39b3469be14858b5b720d4a522d36feed7a329c9b1e852c9280c47db8039c17c4921571a07d1864128330e09c308ddea1694e95c84500f1a61e614197e86a30ecc28df64ccb3ccf5437aa
+CIPHERTEXT = 90b7b9630a2378f53f501ab7beff039155008071bc8438e789932cfd3eb1299195465e6633849463fdb44375278e2fdb1310821e6492cf80ff15cb772509fb426f3aeee27bd4938882fd2ae6b5bd9d91fa4a43b17bb439ebbe59c042310163a82a5fe5388796eee35a181a1271f00be29b852d8fa759bad01ff4678f010594cd
+
+COUNT = 8
+KEY = d2412db0845d84e5732b8bbd642957473b81fb99ca8bff70e7920d16c1dbec89
+IV = 51c619fcf0b23f0c7925f400a6cacb6d
+PLAINTEXT = 026006c4a71a180c9929824d9d095b8faaa86fc4fa25ecac61d85ff6de92dfa8702688c02a282c1b8af4449707f22d75e91991015db22374c95f8f195d5bb0afeb03040ff8965e0e1339dba5653e174f8aa5a1b39fe3ac839ce307a4e44b4f8f1b0063f738ec18acdbff2ebfe07383e734558723e741f0a1836dafdf9de82210a9248bc113b3c1bc8b4e252ca01bd803
+CIPHERTEXT = 0254b23463bcabec5a395eb74c8fb0eb137a07bc6f5e9f61ec0b057de305714f8fa294221c91a159c315939b81e300ee902192ec5f15254428d8772f79324ec43298ca21c00b370273ee5e5ed90e43efa1e05a5d171209fe34f9f29237dba2a6726650fd3b1321747d1208863c6c3c6b3e2d879ab5f25782f08ba8f2abbe63e0bedb4a227e81afb36bb6645508356d34
+
+COUNT = 9
+KEY = 48be597e632c16772324c8d3fa1d9c5a9ecd010f14ec5d110d3bfec376c5532b
+IV = d6d581b8cf04ebd3b6eaa1b53f047ee1
+PLAINTEXT = 0c63d413d3864570e70bb6618bf8a4b9585586688c32bba0a5ecc1362fada74ada32c52acfd1aa7444ba567b4e7daaecf7cc1cb29182af164ae5232b002868695635599807a9a7f07a1f137e97b1e1c9dabc89b6a5e4afa9db5855edaa575056a8f4f8242216242bb0c256310d9d329826ac353d715fa39f80cec144d6424558f9f70b98c920096e0f2c855d594885a00625880e9dfb734163cecef72cf030b8
+CIPHERTEXT = fc5873e50de8faf4c6b84ba707b0854e9db9ab2e9f7d707fbba338c6843a18fc6facebaf663d26296fb329b4d26f18494c79e09e779647f9bafa87489630d79f4301610c2300c19dbf3148b7cac8c4f4944102754f332e92b6f7c5e75bc6179eb877a078d4719009021744c14f13fd2a55a2b9c44d18000685a845a4f632c7c56a77306efa66a24d05d088dcd7c13fe24fc447275965db9e4d37fbc9304448cd
+
+[DECRYPT]
+
+COUNT = 0
+KEY = 43e953b2aea08a3ad52d182f58c72b9c60fbe4a9ca46a3cb89e3863845e22c9e
+IV = ddbbb0173f1e2deb2394a62aa2a0240e
+CIPHERTEXT = d51d19ded5ca4ae14b2b20b027ffb020
+PLAINTEXT = 07270d0e63aa36daed8c6ade13ac1af1
+
+COUNT = 1
+KEY = addf88c1ab997eb58c0455288c3a4fa320ada8c18a69cc90aa99c73b174dfde6
+IV = 60cc50e0887532e0d4f3d2f20c3c5d58
+CIPHERTEXT = 6cb4e2f4ddf79a8e08c96c7f4040e8a83266c07fc88dd0074ee25b00d445985a
+PLAINTEXT = 98a8a9d84356bf403a9ccc384a06fe043dfeecb89e59ce0cb8bd0a495ef76cf0
+
+COUNT = 2
+KEY = 54682728db5035eb04b79645c64a95606abb6ba392b6633d79173c027c5acf77
+IV = 2eb94297772851963dd39a1eb95d438f
+CIPHERTEXT = e4046d05385ab789c6a72866e08350f93f583e2a005ca0faecc32b5cfc323d461c76c107307654db5566a5bd693e227c
+PLAINTEXT = 0faa5d01b9afad3bb519575daaf4c60a5ed4ca2ba20c625bc4f08799addcf89d19796d1eff0bd790c622dc22c1094ec7
+
+COUNT = 3
+KEY = 7482c47004aef406115ca5fd499788d582efc0b29dc9e951b1f959406693a54f
+IV = 485ebf2215d20b816ea53944829717ce
+CIPHERTEXT = 6c24f19b9c0b18d7126bf68090cb8ae72db3ca7eabb594f506aae7a2493e5326a5afae4ec4d109375b56e2b6ff4c9cf639e72c63dc8114c796df95b3c6b62021
+PLAINTEXT = 82fec664466d585023821c2e39a0c43345669a41244d05018a23d7159515f8ff4d88b01cd0eb83070d0077e065d74d7373816b61505718f8d4f270286a59d45e
+
+COUNT = 4
+KEY = 3ae38d4ebf7e7f6dc0a1e31e5efa7ca123fdc321e533e79fedd5132c5999ef5b
+IV = 36d55dc9edf8669beecd9a2a029092b9
+CIPHERTEXT = d50ea48c8962962f7c3d301fa9f877245026c204a7771292cddca1e7ffebbef00e86d72910b7d8a756dfb45c9f1040978bb748ca537edd90b670ecee375e15d98582b9f93b6355adc9f80f4fb2108fb9
+PLAINTEXT = 8d22db30c4253c3e3add9685c14d55b05f7cf7626c52cccfcbe9b99fd8913663b8b1f22e277a4cc3d0e7e978a34782eb876867556ad4728486d5e890ea738243e3700a696d6eb58cd81c0e60eb121c50
+
+COUNT = 5
+KEY = d30bfc0b2a19d5b8b6f8f46ab7f444ee136a7fa3fbdaf530cc3e8976339afcc4
+IV = 80be76a7f885d2c06b37d6a528fae0cd
+CIPHERTEXT = 31e4677a17aed120bd3af69fbb0e4b645b9e8c104e280b799ddd49f1e241c3ccb7d40e1c6ff226bf04f8049c51a86e2981cf1331c824d7d451746ccf77fc22fd3717001ee51913d81f7a06fb0037f309957579f695670f2c4c7397d2d990374e
+PLAINTEXT = 0b6e2a8213169b3b78db6de324e286f0366044e035c6970afbf0a1a5c32a05b24ba706cd9c6609737651a81b2bcf4c681dc0861983a5aec76e6c8b244112d64d489e84328974737394b83a39459011727162652b7aa793bfb1b71488b7dec96b
+
+COUNT = 6
+KEY = 64a256a663527ebea71f8d770990b4cee4a2d3afbfd33fb12c7ac300ef59e49a
+IV = 18cce9147f295c5c00dbe0424089d3b4
+CIPHERTEXT = d99771963b7ae5202e382ff8c06e035367909cd24fe5ada7f3d39bfaeb5de98b04eaf4989648e00112f0d2aadb8c5f2157b64581450359965140c141e5fb631e43469d65d1b7370eb3b396399fec32cced294a5eee46d6547f7bbd49dee148b4bc31d6c493cfd28f3908e36cb698629d
+PLAINTEXT = f7e0f79cfddd15ed3600ab2d29c56ba3c8e96d1a896aff6dec773e6ea4710a77f2f4ec646b76efda6428c175d007c84aa9f4b18c5e1bac5f27f7307b737655eee813f7e1f5880a37ac63ad1666e7883083b648454d45786f53ea3db1b5129291138abe40c79fcb7ab7c6f6b9ea133b5f
+
+COUNT = 7
+KEY = 31358e8af34d6ac31c958bbd5c8fb33c334714bffb41700d28b07f11cfe891e7
+IV = 144516246a752c329056d884daf3c89d
+CIPHERTEXT = b32e2b171b63827034ebb0d1909f7ef1d51c5f82c1bb9bc26bc4ac4dccdee8357dca6154c2510ae1c87b1b422b02b621bb06cac280023894fcff3406af08ee9be1dd72419beccddff77c722d992cdcc87e9c7486f56ab406ea608d8c6aeb060c64cf2785ad1a159147567e39e303370da445247526d95942bf4d7e88057178b0
+PLAINTEXT = cfc155a3967de347f58fa2e8bbeb4183d6d32f7427155e6ab39cddf2e627c572acae02f1f243f3b784e73e21e7e520eacd3befafbee814867334c6ee8c2f0ee7376d3c72728cde7813173dbdfe3357deac41d3ae2a04229c0262f2d109d01f5d03e7f848fb50c28849146c02a2f4ebf7d7ffe3c9d40e31970bf151873672ef2b
+
+COUNT = 8
+KEY = 5b4b69339891db4e3337c3486f439dfbd0fb2a782ca71ef0059819d51669d93c
+IV = 2b28a2d19ba9ecd149dae96622c21769
+CIPHERTEXT = ba21db8ec170fa4d73cfc381687f3fa188dd2d012bef48007f3dc88329e22ba32fe235a315be362546468b9db6af6705c6e5d4d36822f42883c08d4a994cc454a7db292c4ca1f4b62ebf8e479a5d545d6af9978d2cfee7bc80999192c2c8662ce9b4be11af40bd68f3e2d5685bb28c0f3dc08017c0aba8263e6fdc45ed7f9893bf14fd3a86c418a35c5667e642d59985
+PLAINTEXT = a0bb1d2fdeb7e6bf34c690fe7b72a5e9d65796aa57982fe340c286d6923dbddb426566ff58e9c0b3af52e4db446f6cc5daa5bfcf4e3c85db5a5638e670c370cce128db22c97542a64a63846f18a228d3462a11376dcb71f66ec52ebda474f7b6752915b0801797974bc51eb1218127fed60f1009430eb5089fb3ba5f28fad24c518ccddc2501393ceb6dffc46a159421
+
+COUNT = 9
+KEY = 87725bd43a45608814180773f0e7ab95a3c859d83a2130e884190e44d14c6996
+IV = e49651988ebbb72eb8bb80bb9abbca34
+CIPHERTEXT = 5b97a9d423f4b97413f388d9a341e727bb339f8e18a3fac2f2fb85abdc8f135deb30054a1afdc9b6ed7da16c55eba6b0d4d10c74e1d9a7cf8edfaeaa684ac0bd9f9d24ba674955c79dc6be32aee1c260b558ff07e3a4d49d24162011ff254db8be078e8ad07e648e6bf5679376cb4321a5ef01afe6ad8816fcc7634669c8c4389295c9241e45fff39f3225f7745032daeebe99d4b19bcb215d1bfdb36eda2c24
+PLAINTEXT = bfe5c6354b7a3ff3e192e05775b9b75807de12e38a626b8bf0e12d5fff78e4f1775aa7d792d885162e66d88930f9c3b2cdf8654f56972504803190386270f0aa43645db187af41fcea639b1f8026ccdd0c23e0de37094a8b941ecb7602998a4b2604e69fc04219585d854600e0ad6f99a53b2504043c08b1c3e214d17cde053cbdf91daa999ed5b47c37983ba3ee254bc5c793837daaa8c85cfc12f7f54f699f
+
diff --git a/libs/crypto/pqnist.go b/libs/crypto/pqnist.go
new file mode 100644
index 0000000..551f31a
--- /dev/null
+++ b/libs/crypto/pqnist.go
@@ -0,0 +1,404 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package crypto - wrapper for encryption libraries required by service
+*/
+package crypto
+
+/*
+#cgo CFLAGS:  -O2 -I/amcl -I/usr/local/include/amcl
+#cgo LDFLAGS: -L. -lpqnist -lamcl_bls_BLS381 -lamcl_pairing_BLS381 -lamcl_curve_BLS381 -lamcl_core -loqs
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/utils.h>
+#include <amcl/randapi.h>
+#include <amcl/bls_BLS381.h>
+#include <oqs/oqs.h>
+#include <amcl/pqnist.h>
+*/
+import "C"
+import "unsafe"
+
+// AES
+const pqnistAesKeyLength int = int(C.PQNIST_AES_KEY_LENGTH)
+const pqnistAesIvLength int = int(C.PQNIST_AES_IV_LENGTH)
+
+// CSPRNG
+const pqnistSeedLength int = int(C.PQNIST_SEED_LENGTH)
+
+// SIKE
+const oqsKemSikeP751LengthPublicKey int = int(C.OQS_KEM_sike_p751_length_public_key)
+const oqsKemSikeP751LengthSecretKey int = int(C.OQS_KEM_sike_p751_length_secret_key)
+const oqsKemSikeP751LengthCiphertext int = int(C.OQS_KEM_sike_p751_length_ciphertext)
+
+// BFSBLS381 Field size
+const BFSBLS381 int = int(C.BFS_BLS381)
+
+// BGSBLS381 Group size
+const BGSBLS381 int = int(C.BGS_BLS381)
+
+// G2Len G2 point size
+const G2Len int = 4 * BFSBLS381
+
+// SIGLen Signature length
+const SIGLen int = BFSBLS381 + 1
+
+/*BLSKeys Generate BLS keys
+
+Generate public and private key pair. If the seed value is nil then
+generate the public key using the input secret key.
+
+@param seed             seed value for CSPRNG.
+@param ski              input secret key
+@param pk               public key
+@param sko              output secret key
+@param rc               Return code. Zero for success or else an error code
+*/
+func BLSKeys(seed []byte, ski []byte) (rc int, pk []byte, sko []byte) {
+
+	// Allocate memory
+	ppk := C.malloc(C.size_t(G2Len))
+	defer C.free(ppk)
+	var sk []byte
+
+	if seed == nil {
+		rtn := C.pqnist_bls_keys(nil, (*C.char)(ppk), (*C.char)(unsafe.Pointer(&ski[0])))
+		rc = int(rtn)
+
+		pk = C.GoBytes(ppk, C.int(G2Len))
+		sk = ski
+
+	} else {
+		psk := C.malloc(C.size_t(BGSBLS381))
+		defer C.free(psk)
+
+		rtn := C.pqnist_bls_keys((*C.char)(unsafe.Pointer(&seed[0])), (*C.char)(ppk), (*C.char)(psk))
+		rc = int(rtn)
+
+		pk = C.GoBytes(ppk, C.int(G2Len))
+		sko = C.GoBytes(psk, C.int(BGSBLS381))
+		sk = sko
+	}
+	return rc, pk, sk
+}
+
+/*BLSSign Sign a message
+
+  The message is signed using the BLS algorithm
+
+  @param M            Message to be signed
+  @param sk           secret key
+  @param S            Signature
+  @param rc           Return code. Zero for success or else an error code
+*/
+func BLSSign(m []byte, sk []byte) (rc int, s []byte) {
+	// Allocate memory
+	pS := C.malloc(C.size_t(SIGLen))
+	defer C.free(pS)
+
+	rtn := C.pqnist_bls_sign(
+		(*C.char)(unsafe.Pointer(&m[0])),
+		(*C.char)(unsafe.Pointer(&sk[0])),
+		(*C.char)(pS))
+
+	rc = int(rtn)
+
+	s = C.GoBytes(pS, C.int(SIGLen))
+
+	return rc, s
+}
+
+/*BLSVerify Verify a signature
+
+  Verify a signature using the BLS algorithm
+
+  @param M            Message that was signed
+  @param pk           public key
+  @param S            Signature
+  @param rc           Return code. Zero for success or else an error code
+*/
+func BLSVerify(m []byte, pk []byte, s []byte) (rc int) {
+
+	rtn := C.pqnist_bls_verify(
+		(*C.char)(unsafe.Pointer(&m[0])),
+		(*C.char)(unsafe.Pointer(&pk[0])),
+		(*C.char)(unsafe.Pointer(&s[0])))
+
+	rc = int(rtn)
+
+	return rc
+}
+
+/*BLSAddG1 Add two members from the group G1
+
+  Add two members from the group G1
+
+  @param R1           member of G1
+  @param R2           member of G1
+  @param R            member of G1. r = r1+r2
+  @param rc           Return code. Zero for success or else an error code
+*/
+func BLSAddG1(R1 []byte, R2 []byte) (rc int, R []byte) {
+
+	// Allocate memory
+	pR := C.malloc(C.size_t(SIGLen))
+	defer C.free(pR)
+
+	rtn := C.pqnist_bls_addg1(
+		(*C.char)(unsafe.Pointer(&R1[0])),
+		(*C.char)(unsafe.Pointer(&R2[0])),
+		(*C.char)(pR))
+
+	rc = int(rtn)
+
+	R = C.GoBytes(pR, C.int(SIGLen))
+
+	return rc, R
+}
+
+/*BLSAddG2 Add two members from the group G2
+
+  Add two members from the group G2
+
+  @param R1           member of G2
+  @param R2           member of G2
+  @param R            member of G2. r = r1+r2
+  @param rc           Return code. Zero for success or else an error code
+*/
+func BLSAddG2(R1 []byte, R2 []byte) (rc int, R []byte) {
+
+	// Allocate memory
+	pR := C.malloc(C.size_t(G2Len))
+	defer C.free(pR)
+
+	rtn := C.pqnist_bls_addg2(
+		(*C.char)(unsafe.Pointer(&R1[0])),
+		(*C.char)(unsafe.Pointer(&R2[0])),
+		(*C.char)(pR))
+
+	rc = int(rtn)
+
+	R = C.GoBytes(pR, C.int(G2Len))
+
+	return rc, R
+}
+
+/*BLSMakeShares Use Shamir's secret sharing to distribute BLS secret keys
+
+Use Shamir's secret sharing to distribute BLS secret keys
+
+@param  k       Threshold
+@param  n       Number of shares
+@param  seed    seed value for CSPRNG
+@param  ski     Secret key to be shared.
+@param  x       x values
+@param  y       y values. Valid BLS secret keys
+@param  rc      Zero for success or else an error code
+*/
+func BLSMakeShares(k int, n int, seed []byte, ski []byte) (rc int, x []byte, y []byte, sko []byte) {
+
+	// Allocate memory
+	pX := C.malloc(C.size_t(BGSBLS381 * n))
+	defer C.free(pX)
+	pY := C.malloc(C.size_t(BGSBLS381 * n))
+	defer C.free(pY)
+	pSKO := C.malloc(C.size_t(BGSBLS381))
+	defer C.free(pSKO)
+
+	rtn := C.pqnist_bls_make_shares(C.int(k), C.int(n), (*C.char)(unsafe.Pointer(&seed[0])), (*C.char)(pX), (*C.char)(pY), (*C.char)(unsafe.Pointer(&ski[0])), (*C.char)(pSKO))
+	rc = int(rtn)
+
+	sko = C.GoBytes(pSKO, C.int(BGSBLS381))
+	x = C.GoBytes(pX, C.int(BGSBLS381*n))
+	y = C.GoBytes(pY, C.int(BGSBLS381*n))
+	return rc, x, y, sko
+}
+
+/*BLSRecoverSecret Use Shamir's secret sharing to recover a BLS secret key
+
+Use Shamir's secret sharing to recover a BLS secret key
+
+@param  k       Threshold
+@param  x       x values
+@param  y       y values. Valid BLS secret keys
+@param  sk      Secret key that is recovered
+@param  rc      Zero for success or else an error code
+*/
+func BLSRecoverSecret(k int, x []byte, y []byte) (rc int, sk []byte) {
+
+	// Allocate memory
+	pSK := C.malloc(C.size_t(BGSBLS381))
+	defer C.free(pSK)
+
+	rtn := C.pqnist_bls_recover_secret(C.int(k), (*C.char)(unsafe.Pointer(&x[0])), (*C.char)(unsafe.Pointer(&y[0])), (*C.char)(pSK))
+	rc = int(rtn)
+
+	sk = C.GoBytes(pSK, C.int(BGSBLS381))
+
+	return rc, sk
+}
+
+/*BLSRecoverSignature Use Shamir's secret sharing to recover a BLS signature
+
+Use Shamir's secret sharing to recover a BLS signature
+
+@param  k       Threshold
+@param  x       x values
+@param  y       y values. Valid BLS signatures
+@param  sig     Signature that is recovered
+@param  rc      Zero for success or else an error code
+*/
+func BLSRecoverSignature(k int, x []byte, y []byte) (rc int, sig []byte) {
+
+	// Allocate memory
+	pSIG := C.malloc(C.size_t(SIGLen))
+	defer C.free(pSIG)
+
+	rtn := C.pqnist_bls_recover_signature(C.int(k), (*C.char)(unsafe.Pointer(&x[0])), (*C.char)(unsafe.Pointer(&y[0])), (*C.char)(pSIG))
+	rc = int(rtn)
+
+	sig = C.GoBytes(pSIG, C.int(SIGLen))
+
+	return rc, sig
+}
+
+/*AESCBCEncrypt AES-CBC Encryption
+
+  AES encryption using CBC mode
+
+  @param K            Key
+  @param IV           Initialization vector IV (16 bytes)
+  @param P            Plaintext
+  @param C            Ciphertext
+*/
+func AESCBCEncrypt(k []byte, iv []byte, p []byte) (c []byte) {
+	C.pqnist_aes_cbc_encrypt(
+		(*C.char)(unsafe.Pointer(&k[0])),
+		C.int(len(k)),
+		(*C.char)(unsafe.Pointer(&iv[0])),
+		(*C.char)(unsafe.Pointer(&p[0])),
+		C.int(len(p)))
+
+	return p
+}
+
+/*AESCBCDecrypt AES-CBC Decryption
+
+  AES decryption using CBC mode
+
+  @param K            Key
+  @param IV           Initialization vector IV (16 bytes)
+  @param C            Ciphertext
+  @param P            Plaintext
+*/
+func AESCBCDecrypt(k []byte, iv []byte, c []byte) (p []byte) {
+
+	C.pqnist_aes_cbc_decrypt(
+		(*C.char)(unsafe.Pointer(&k[0])),
+		C.int(len(k)),
+		(*C.char)(unsafe.Pointer(&iv[0])),
+		(*C.char)(unsafe.Pointer(&c[0])),
+		C.int(len(c)))
+
+	return c
+}
+
+/*SIKEKeys Generate SIKE keys
+
+Generate SIKE public and private key pair
+
+@param seed             seed value for CSPRNG
+@param sikePK           SIKE public key
+@param sikeSK           SIKE secret key
+@param rc               Return code. Zero for success or else an error code
+*/
+func SIKEKeys(seed []byte) (rc int, sikePK []byte, sikeSK []byte) {
+
+	// Allocate memory
+	psikePK := C.malloc(C.size_t(oqsKemSikeP751LengthPublicKey))
+	defer C.free(psikePK)
+	psikeSK := C.malloc(C.size_t(oqsKemSikeP751LengthSecretKey))
+	defer C.free(psikeSK)
+
+	rtn := C.pqnist_sike_keys((*C.char)(unsafe.Pointer(&seed[0])), (*C.char)(psikePK), (*C.char)(psikeSK))
+	rc = int(rtn)
+
+	sikePK = C.GoBytes(psikePK, C.int(oqsKemSikeP751LengthPublicKey))
+	sikeSK = C.GoBytes(psikeSK, C.int(oqsKemSikeP751LengthSecretKey))
+	return rc, sikePK, sikeSK
+}
+
+/*EncapsulateEncrypt Encrypt a message and encapsulate the AES Key for a recipient.
+
+  The  message is encrypted using AES-256. The key
+  is generated inside this function as an output
+  from the encapsulation function. The ciphertext
+  is returned using the P paramter.
+
+  @param P            Plaintext to be encrypted
+  @param IV           Initialization vector IV (16 bytes)
+  @param sikePK       SIKE public key
+  @param C            Ciphertext
+  @param EK           Encapsulated key
+  @param rc           Return code. Zero for success or else an error code
+*/
+func EncapsulateEncrypt(p []byte, iv []byte, sikePK []byte) (rc int, c []byte, ek []byte) {
+
+	// Allocate memory
+	pEK := C.malloc(C.size_t(oqsKemSikeP751LengthCiphertext))
+	defer C.free(pEK)
+
+	rtn := C.pqnist_encapsulate_encrypt(
+		(*C.char)(unsafe.Pointer(&p[0])),
+		C.int(len(p)),
+		(*C.char)(unsafe.Pointer(&iv[0])),
+		(*C.char)(unsafe.Pointer(&sikePK[0])),
+		(*C.char)(pEK))
+	rc = int(rtn)
+
+	ek = C.GoBytes(pEK, C.int(oqsKemSikeP751LengthCiphertext))
+
+	return rc, p, ek
+}
+
+/*DecapsulateDecrypt Decapsulate the AES Key and decrypt the message
+
+Decapsulate the AES key and use it to decrypt the
+ciphertext. The plaintext is returned using the C
+parameter.
+
+@param C            Ciphertext to be decrypted
+@param IV           Initialization vector IV
+@param sikeSK       SIKE secret key
+@param EK           Encapsulated key
+@param P            Plaintext
+@param rc           Return code. Zero for success or else an error code
+*/
+func DecapsulateDecrypt(c []byte, iv []byte, sikeSK []byte, ek []byte) (rc int, p []byte) {
+
+	rtn := C.pqnist_decapsulate_decrypt(
+		(*C.char)(unsafe.Pointer(&c[0])),
+		C.int(len(c)),
+		(*C.char)(unsafe.Pointer(&iv[0])),
+		(*C.char)(unsafe.Pointer(&sikeSK[0])),
+		(*C.char)(unsafe.Pointer(&ek[0])))
+	rc = int(rtn)
+
+	return rc, c
+}
diff --git a/libs/crypto/pqnist_test.go b/libs/crypto/pqnist_test.go
new file mode 100644
index 0000000..febe2f9
--- /dev/null
+++ b/libs/crypto/pqnist_test.go
@@ -0,0 +1,431 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package crypto
+
+import (
+	"encoding/hex"
+	"fmt"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func Test_Mine2(t *testing.T) {
+
+	// Generate keys
+
+	sikePK, _ := hex.DecodeString("f013ed197f8d2756eb7fb237bfe6714ec0d3f12ddc7431b8881f4bece686cafa67e9cfcfc75d5117114e857b379b1fe6b0e67f11dc7936d4ed4e8c3488b2300a80b12e3bee303b2d1e5d24c2c9b3e5855aeddfa45508e587f71a95c23d643523bf8385a7d830254b6ac7f231cf945795311ad8915da9605ff5e6543a01b923e924b37d7d2e464d7a9d78cc5ad4b456fc735ff7d60bd9225558bbad053a3d724a82d3a77348d4aac4296c6f79e0db21a49695e158abf16724e635b930e2704620eccdc1aab49d0655f7ca1eb36ba8c99129b2de8bee6e843a849b802b90775090a7617dc6e4a9ef289c0eac292cc00a80f9a76df2471695e9c433337c649acacc4ba0a2a5f80ccb594553861161cb4771bceabc4cb430bf233307e54f3ebbc0291e75db9cac6d9760e39cd39f373d8e852cac56585bbdf0167c62f728e2889d8387abc0b25f40f990dc7efd93d17839f04ad1e8f3dbe6b518f4f629d69ac7ce04ea614b977a60deb2148fd8e32dfe690da6bfd2aa614dd60688a86989e80cb718f69fa0d02d1ee9796510a9cb523e03fa3ad2a083fb42d11df0e5584873a80b86725d806fbaee92bd35ba2548a79a1a477ea1b1c5d4e33434db2b25ffd6713c887d25e774a0b7c6ca039fcf9e527739449a918d9c884dadf6ac1f11d9cc235a44ff9f69d568c7e5e1999d0353f37710ce71d5f59f756c9a89cd7fe318ebecb1ba7e408171da3e516a1e0e6bef2379e6b519986d6e75e720be3a8892ade537926760a60b011ef627db482a7edfce13fcc767f1eb1c")
+	sikeSK, _ := hex.DecodeString("5a8ac3a8704ac0b906f905cbfbf62acf81046b9f7f24e7f95b43a62c37d483c7110fd01e31fe6961421b50a0672a0450153894a9a221bb62d059d7e5589e4765e93c6d5bc713fc822f44276b2eab4700f013ed197f8d2756eb7fb237bfe6714ec0d3f12ddc7431b8881f4bece686cafa67e9cfcfc75d5117114e857b379b1fe6b0e67f11dc7936d4ed4e8c3488b2300a80b12e3bee303b2d1e5d24c2c9b3e5855aeddfa45508e587f71a95c23d643523bf8385a7d830254b6ac7f231cf945795311ad8915da9605ff5e6543a01b923e924b37d7d2e464d7a9d78cc5ad4b456fc735ff7d60bd9225558bbad053a3d724a82d3a77348d4aac4296c6f79e0db21a49695e158abf16724e635b930e2704620eccdc1aab49d0655f7ca1eb36ba8c99129b2de8bee6e843a849b802b90775090a7617dc6e4a9ef289c0eac292cc00a80f9a76df2471695e9c433337c649acacc4ba0a2a5f80ccb594553861161cb4771bceabc4cb430bf233307e54f3ebbc0291e75db9cac6d9760e39cd39f373d8e852cac56585bbdf0167c62f728e2889d8387abc0b25f40f990dc7efd93d17839f04ad1e8f3dbe6b518f4f629d69ac7ce04ea614b977a60deb2148fd8e32dfe690da6bfd2aa614dd60688a86989e80cb718f69fa0d02d1ee9796510a9cb523e03fa3ad2a083fb42d11df0e5584873a80b86725d806fbaee92bd35ba2548a79a1a477ea1b1c5d4e33434db2b25ffd6713c887d25e774a0b7c6ca039fcf9e527739449a918d9c884dadf6ac1f11d9cc235a44ff9f69d568c7e5e1999d0353f37710ce71d5f59f756c9a89cd7fe318ebecb1ba7e408171da3e516a1e0e6bef2379e6b519986d6e75e720be3a8892ade537926760a60b011ef627db482a7edfce13fcc767f1eb1c")
+	secret, _ := hex.DecodeString("5a8ac3a8704ac0b906f905cbfbf62acf81046b9f7f24e7f95b43a62c37d483c7110fd01e31fe6961421")
+	final, _ := hex.DecodeString("5a8ac3a8704ac0b906f905cbfbf62acf81046b9f7f24e7f95b43a62c37d483c7110fd01e31fe6961421")
+	iv, _ := hex.DecodeString("9640061f9e3c29fdd52945feb678de83")
+
+	_, cipherText, encapsulatedKey := EncapsulateEncrypt(secret, iv, sikePK)
+
+	println(encapsulatedKey)
+	println(cipherText)
+	encapsulatedKeyHex := hex.EncodeToString(encapsulatedKey)
+	cipherTextHex := hex.EncodeToString(cipherText)
+	fmt.Printf("encapsulatedKey : %s \n", encapsulatedKeyHex)
+	fmt.Printf("BLSscipherTextk : %s \n", cipherTextHex)
+
+	_, aes := DecapsulateDecrypt(cipherText, iv, sikeSK, encapsulatedKey)
+
+	print(hex.EncodeToString(aes))
+	assert.Equal(t, aes, final, "Secret doesnt match")
+}
+
+func Test_Mine(t *testing.T) {
+	SEEDHex := "2c82c5a6b14f6ce0fca9b83e929f6ca091fb25b6648676b3c387e8a13b0f4cee92a54d42e388db3fbb0e906b32e880f4"
+	SEED, _ := hex.DecodeString(SEEDHex)
+
+	// Generate SIKE keys
+	RC1, SIKEpk, SIKEsk := SIKEKeys(SEED)
+	if RC1 != 0 {
+		fmt.Println("Panicking!")
+		panic("Failed to create SIKE keys")
+	}
+
+	// Generate BLS keys
+	RC1, BLSpk, BLSsk := BLSKeys(SEED, nil)
+	if RC1 != 0 {
+		fmt.Println("Panicking!")
+		panic("Failed to create BLS keys")
+	}
+
+	SIKEpkHex := hex.EncodeToString(SIKEpk)
+	SIKEskHex := hex.EncodeToString(SIKEsk)
+	fmt.Printf("SIKEpk : %s \n", SIKEpkHex)
+	fmt.Printf("SIKEsk : %s \n", SIKEskHex)
+
+	BLSpkHex := hex.EncodeToString(BLSpk)
+	BLSskHex := hex.EncodeToString(BLSsk)
+	fmt.Printf("BLSpk : %s \n", BLSpkHex)
+	fmt.Printf("BLSsk : %s \n", BLSskHex)
+
+	secret, _ := hex.DecodeString("79e54957d823668872b41f6bd6394a2132935902bc9c9192474562d58225e129")
+	iv, _ := hex.DecodeString("f7427ca6749f696c0dab97582b96222f")
+
+	_, cipherText, encapsulatedKey := EncapsulateEncrypt(secret, iv, SIKEpk)
+
+	println(encapsulatedKey)
+	println(cipherText)
+	encapsulatedKeyHex := hex.EncodeToString(encapsulatedKey)
+	cipherTextHex := hex.EncodeToString(cipherText)
+	fmt.Printf("encapsulatedKey : %s \n", encapsulatedKeyHex)
+	fmt.Printf("BLSscipherTextk : %s \n", cipherTextHex)
+
+	_, aes := DecapsulateDecrypt(cipherText, iv, SIKEsk, encapsulatedKey)
+
+	print(hex.EncodeToString(aes))
+	assert.Equal(t, aes, secret, "Secret doesnt match")
+}
+
+func Test_Smoke_Test(t *testing.T) {
+	SEEDHex := "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30"
+	SEED, _ := hex.DecodeString(SEEDHex)
+
+	// AES-256 Key
+	KHex := "af5f8452d644d131c35164fee8c8300fb29725b03b00eaef411c823293c469d8"
+
+	// AES IVs
+	IV1Hex := "de4724534df5f50160a28cf3b3caec80"
+	IV2Hex := "a08576336500e79b2593dc4c10b0f36c"
+
+	// Messsage to encrypt and sign. Note it is zero padded.
+	PHex := "48656c6c6f20426f622120546869732069732061206d6573736167652066726f6d20416c696365000000000000000000"
+
+	// Generate SIKE keys
+	RC1, SIKEpk, SIKEsk := SIKEKeys(SEED)
+	if RC1 != 0 {
+		fmt.Println("Panicking!")
+		panic("Failed to create SIKE keys")
+	}
+
+	// Generate BLS keys
+	RC1, BLSpk, BLSsk := BLSKeys(SEED, nil)
+	if RC1 != 0 {
+		fmt.Println("Panicking!")
+		panic("Failed to create BLS keys")
+	}
+
+	SIKEpkHex := hex.EncodeToString(SIKEpk)
+	SIKEskHex := hex.EncodeToString(SIKEsk)
+	fmt.Printf("SIKEpk : %s \n", SIKEpkHex)
+	fmt.Printf("SIKEsk : %s \n", SIKEskHex)
+
+	BLSpkHex := hex.EncodeToString(BLSpk)
+	BLSskHex := hex.EncodeToString(BLSsk)
+	fmt.Printf("BLSpk : %s \n", BLSpkHex)
+	fmt.Printf("BLSsk : %s \n", BLSskHex)
+
+	// Encrypt message
+	K, _ := hex.DecodeString(KHex)
+	IV1, _ := hex.DecodeString(IV1Hex)
+	P1, _ := hex.DecodeString(PHex)
+	fmt.Printf("P1 : %s \n", P1)
+	C1 := AESCBCEncrypt(K, IV1, P1)
+	C1Hex := hex.EncodeToString(C1)
+	fmt.Printf("C1Hex : %s \n", C1Hex)
+
+	// Encrypt AES Key, K, and returned encapsulated key used for
+	// encryption
+	IV2, _ := hex.DecodeString(IV2Hex)
+	P2 := K
+	P2Hex := hex.EncodeToString(P2)
+	fmt.Printf("P2Hex : %s \n", P2Hex)
+	RC2, C2, EK := EncapsulateEncrypt(P2, IV2, SIKEpk)
+	if RC2 != 0 {
+		fmt.Println("Panicking!")
+		panic("Failed to encrypt and encapsulate key")
+	}
+	C2Hex := hex.EncodeToString(C2)
+	fmt.Printf("C2Hex : %s \n", C2Hex)
+	EKHex := hex.EncodeToString(EK)
+	fmt.Printf("EKHex : %s \n", EKHex)
+
+	// Decapsulate the AES Key and use it to decrypt the ciphertext.
+	// P2 and P3 should be the same. This value is the AES-256 key
+	// used to encrypt the plaintext P1
+	RC3, P3 := DecapsulateDecrypt(C2, IV2, SIKEsk, EK)
+	if RC3 != 0 {
+		fmt.Println("Panicking!")
+		panic("Failed to decapsulate key and decrypt ciphertext")
+	}
+	P3Hex := hex.EncodeToString(P3)
+	fmt.Printf("P3Hex : %s \n", P3Hex)
+
+	// Decrypt the ciphertext to recover the orignal plaintext
+	// contained in P1
+	K2 := P3
+	P4 := AESCBCDecrypt(K2, IV1, C1)
+	fmt.Printf("P4 : %s \n", P4)
+
+	// BLS Sign a message
+	RC5, S := BLSSign(P1, BLSsk)
+	if RC5 != 0 {
+		fmt.Println("Panicking!")
+		panic("Failed to sign message")
+	}
+	SHex := hex.EncodeToString(S)
+	fmt.Printf("S : %s \n", SHex)
+
+	// BLS Verify signature
+	RC6 := BLSVerify(P1, BLSpk, S)
+	if RC6 != 0 {
+		fmt.Println("Panicking!")
+		panic("Failed to verify signature")
+	} else {
+		fmt.Println("Signature Verified")
+	}
+}
+
+func TestPQNIST_AES_CBC_ENCRYPT(t *testing.T) {
+	KHex := "6ed76d2d97c69fd1339589523931f2a6cff554b15f738f21ec72dd97a7330907"
+	IVHex := "851e8764776e6796aab722dbb644ace8"
+	PHex := "6282b8c05c5c1530b97d4816ca434762"
+	want := "6acc04142e100a65f51b97adf5172c41"
+
+	K, _ := hex.DecodeString(KHex)
+	IV, _ := hex.DecodeString(IVHex)
+	P, _ := hex.DecodeString(PHex)
+
+	C := AESCBCEncrypt(K, IV, P)
+	got := hex.EncodeToString(C)
+	fmt.Printf("C1 : %s \n", want)
+	fmt.Printf("C2 : %s \n", got)
+
+	// verify
+	assert.Equal(t, want, got, "Should be equal")
+}
+
+func TestPQNIST_AES_CBC_DECRYPT(t *testing.T) {
+	KHex := "43e953b2aea08a3ad52d182f58c72b9c60fbe4a9ca46a3cb89e3863845e22c9e"
+	IVHex := "ddbbb0173f1e2deb2394a62aa2a0240e"
+	CHex := "d51d19ded5ca4ae14b2b20b027ffb020"
+	want := "07270d0e63aa36daed8c6ade13ac1af1"
+
+	K, _ := hex.DecodeString(KHex)
+	IV, _ := hex.DecodeString(IVHex)
+	C, _ := hex.DecodeString(CHex)
+
+	P := AESCBCDecrypt(K, IV, C)
+	got := hex.EncodeToString(P)
+	fmt.Printf("P1 : %s \n", want)
+	fmt.Printf("P2 : %s \n", got)
+
+	// verify
+	assert.Equal(t, want, got, "Should be equal")
+}
+func TestENCAP_DECAP(t *testing.T) {
+	SEEDHex := "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30"
+	SEED, _ := hex.DecodeString(SEEDHex)
+
+	RC1, SIKEpk, SIKEsk := SIKEKeys(SEED)
+	assert.Equal(t, 0, RC1, "Should be equal")
+
+	SIKEpkHex := hex.EncodeToString(SIKEpk)
+	SIKEskHex := hex.EncodeToString(SIKEsk)
+	fmt.Printf("BLSpk : %s \n", SIKEpkHex)
+	fmt.Printf("BLSsk : %s \n", SIKEskHex)
+
+	IVHex := "851e8764776e6796aab722dbb644ace8"
+	want := "6282b8c05c5c1530b97d4816ca434762"
+	IV, _ := hex.DecodeString(IVHex)
+	P, _ := hex.DecodeString(want)
+
+	RC2, C, EK := EncapsulateEncrypt(P, IV, SIKEpk)
+	assert.Equal(t, 0, RC2, "Should be equal")
+	CHex := hex.EncodeToString(C)
+	fmt.Printf("C : %s \n", CHex)
+	EKHex := hex.EncodeToString(EK)
+	fmt.Printf("EK : %s \n", EKHex)
+
+	RC3, P2 := DecapsulateDecrypt(C, IV, SIKEsk, EK)
+	assert.Equal(t, 0, RC3, "Should be equal")
+	got := hex.EncodeToString(P2)
+	fmt.Printf("want : %s \n", want)
+	fmt.Printf("got : %s \n", got)
+
+	assert.Equal(t, want, got, "Should be equal")
+}
+
+func TestBLS(t *testing.T) {
+	seedHex := "3370f613c4fe81130b846483c99c032c17dcc1904806cc719ed824351c87b0485c05089aa34ba1e1c6bfb6d72269b150"
+	seed, _ := hex.DecodeString(seedHex)
+
+	messageStr := "test message"
+	message := []byte(messageStr)
+
+	RC1, pk1, sk1 := BLSKeys(seed, nil)
+	assert.Equal(t, 0, RC1, "Should be equal")
+
+	pk1Hex := hex.EncodeToString(pk1)
+	sk1Hex := hex.EncodeToString(sk1)
+	fmt.Printf("pk1: %s \n", pk1Hex)
+	fmt.Printf("sk1: %s \n", sk1Hex)
+
+	RC2, sig1 := BLSSign(message, sk1)
+	assert.Equal(t, 0, RC2, "Should be equal")
+
+	sig1Hex := hex.EncodeToString(sig1)
+	fmt.Printf("sig1: %s \n", sig1Hex)
+
+	want := 0
+	got := BLSVerify(message, pk1, sig1)
+
+	assert.Equal(t, want, got, "Should be equal")
+}
+
+func TestBLSADD(t *testing.T) {
+	seed1Hex := "3370f613c4fe81130b846483c99c032c17dcc1904806cc719ed824351c87b0485c05089aa34ba1e1c6bfb6d72269b150"
+	seed2Hex := "46389f32b7cdebbbc46b7165d8fae888c9de444898390a939977e1a066256a6f465e7d76307178aef81ae0c6841f9b7c"
+	seed1, _ := hex.DecodeString(seed1Hex)
+	seed2, _ := hex.DecodeString(seed2Hex)
+
+	messageStr := "test message"
+	message := []byte(messageStr)
+
+	pk12GoldenHex := "0fff41dc3b28fee38f564158f9e391a5c6ac42179fcccdf5ee4513030b6d59900a832f9a886b2407dc8b0a3b51921326123d3974bd1864fb22f5a84e83f1f9f611ee082ed5bd6ca896d464f12907ba8acdf15c44f9cff2a2dbb3b32259a1fe4f11d470158066087363df20a11144d6521cf72dca1a7514154a95c7fe73b219989cc40d7fc7e0b97854fc3123c0cf50ae0452730996a5cb24641aff7102fcbb2af705d0f32d5787ca1c3654e4ae6aa59106e1e22e29018ba7c341f1e6472f800f"
+	sig12GoldenHex := "0203799dc2941b810985d9eb694a5be4a1ad5817f9e5d7c31870bb9fb471f7353eafacdc548544f9e7b78a0a9372c63ab0"
+	pk12Golden, _ := hex.DecodeString(pk12GoldenHex)
+	sig12Golden, _ := hex.DecodeString(sig12GoldenHex)
+
+	RC1, pktmp, sktmp := BLSKeys(seed1, nil)
+	assert.Equal(t, 0, RC1, "Should be equal")
+
+	RC1, pk1, sk1 := BLSKeys(nil, sktmp)
+	assert.Equal(t, 0, RC1, "Should be equal")
+
+	assert.Equal(t, pktmp, pk1, "Should be equal")
+	assert.Equal(t, sktmp, sk1, "Should be equal")
+
+	RC2, pk2, sk2 := BLSKeys(seed2, nil)
+	assert.Equal(t, 0, RC2, "Should be equal")
+
+	RC3, sig1 := BLSSign(message, sk1)
+	assert.Equal(t, 0, RC3, "Should be equal")
+
+	RC4, sig2 := BLSSign(message, sk2)
+	assert.Equal(t, 0, RC4, "Should be equal")
+
+	RC5 := BLSVerify(message, pk1, sig1)
+	assert.Equal(t, 0, RC5, "Should be equal")
+
+	RC6 := BLSVerify(message, pk2, sig2)
+	assert.Equal(t, 0, RC6, "Should be equal")
+
+	RC7, sig12 := BLSAddG1(sig1, sig2)
+	assert.Equal(t, 0, RC7, "Should be equal")
+
+	RC8, pk12 := BLSAddG2(pk1, pk2)
+	assert.Equal(t, 0, RC8, "Should be equal")
+
+	RC9 := BLSVerify(message, pk12, sig12)
+	assert.Equal(t, 0, RC9, "Should be equal")
+
+	pk12Hex := hex.EncodeToString(pk12)
+	fmt.Printf("pk12Hex: %s \n", pk12Hex)
+	fmt.Printf("pk12GoldenHex: %s \n", pk12GoldenHex)
+
+	sig12Hex := hex.EncodeToString(sig12)
+	fmt.Printf("sig12Hex: %s \n", sig12Hex)
+	fmt.Printf("sig12GoldenHex: %s \n", sig12GoldenHex)
+
+	assert.Equal(t, pk12, pk12Golden, "Should be equal")
+	assert.Equal(t, sig12, sig12Golden, "Should be equal")
+}
+
+func TestBLSSSS(t *testing.T) {
+	seed1Hex := "3370f613c4fe81130b846483c99c032c17dcc1904806cc719ed824351c87b0485c05089aa34ba1e1c6bfb6d72269b150"
+	seed2Hex := "46389f32b7cdebbbc46b7165d8fae888c9de444898390a939977e1a066256a6f465e7d76307178aef81ae0c6841f9b7c"
+	seed1, _ := hex.DecodeString(seed1Hex)
+	seed2, _ := hex.DecodeString(seed2Hex)
+
+	messageStr := "test message"
+	message := []byte(messageStr)
+
+	const k int = 3
+	const n int = 4
+
+	sigGoldenHex := "03108b67f20b138e3080208efae105e31868ac34212bf03d80050d01de13a2c52b8bc3eafa3589045aebf11ec00dcf91f3 "
+	xGoldenHex := "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004"
+	yGoldenHex := "0000000000000000000000000000000069f67565fd82de218a8b743b5516f948a72500ac3beb3ba072908cad2a146a91000000000000000000000000000000005f6f919d81a63fd53406794ae714b95a705c51de8001ef16f3f869dc515dcb3d000000000000000000000000000000005ce9d01ed92320a6d7aa195ca74db9735cdbe1ed55a3d026b4736792ee08852500000000000000000000000000000000626530ea03f980967576547095c1f9936ca3b0d8bcd0decfb40185d100149849"
+	ysigsGoldenHex := "0202982b889c082f159a7d8720d8d33a42005f13af0906763383fdce13607d9c0a2672f04c4600b36dd8a7f272c03908760210c06e79b26ee842c31d4ff8ce68d30da4247c7ab1c6162c011dada87b211f7172628ef78a39e61549c9f7b05245a7010316518c690e15de48fdb512bd47180925da7b3320bc52bdb5a239fad77cb975ede4aea20bef0bd570c50dc27240864564030ad08e4a60a0f330588f60f0a6535e79a99dd3c74af22f7b1137a01db65c95bd100745a2c0d5968e1a8ea5b4f3ce3736"
+	sigGolden, _ := hex.DecodeString(sigGoldenHex)
+	xGolden, _ := hex.DecodeString(xGoldenHex)
+	yGolden, _ := hex.DecodeString(yGoldenHex)
+	ysigsGolden, _ := hex.DecodeString(ysigsGoldenHex)
+
+	RC1, pki, ski := BLSKeys(seed1, nil)
+	assert.Equal(t, 0, RC1, "Should be equal")
+
+	RC2, sigi := BLSSign(message, ski)
+	assert.Equal(t, 0, RC2, "Should be equal")
+
+	RC3 := BLSVerify(message, pki, sigi)
+	assert.Equal(t, 0, RC3, "Should be equal")
+
+	// y is an array of BLS secret keys
+	RC4, x, y, sko := BLSMakeShares(k, n, seed2, ski)
+	assert.Equal(t, 0, RC4, "Should be equal")
+
+	assert.Equal(t, ski, sko, "Should be equal")
+
+	xHex := hex.EncodeToString(x)
+	fmt.Printf("xHex: %s \n", xHex)
+	fmt.Printf("xGoldenHex: %s \n", xGoldenHex)
+
+	yHex := hex.EncodeToString(y)
+	fmt.Printf("yHex: %s \n", yHex)
+	fmt.Printf("yGoldenHex: %s \n", yGoldenHex)
+
+	assert.Equal(t, x, xGolden, "Should be equal")
+	assert.Equal(t, y, yGolden, "Should be equal")
+
+	var ys [n][]byte
+	for i := 0; i < n; i++ {
+		ys[i] = y[(i * BGSBLS381):((i + 1) * BGSBLS381)]
+		ysHex := hex.EncodeToString(ys[i])
+		fmt.Printf("ys[%d]: %s \n", i, ysHex)
+	}
+
+	// Generate signatures from shares
+	var sigs [n][]byte
+	var RC5 int
+	var ysigs []byte
+	for i := 0; i < n; i++ {
+		RC5, sigs[i] = BLSSign(message, ys[i])
+		assert.Equal(t, 0, RC5, "Should be equal")
+		sigsHex := hex.EncodeToString(sigs[i])
+		fmt.Printf("sigs[%d]: %s \n", i, sigsHex)
+		ysigs = append(ysigs, sigs[i]...)
+	}
+	ysigsHex := hex.EncodeToString(ysigs)
+	fmt.Printf("ysigs %s \n", ysigsHex)
+
+	assert.Equal(t, ysigs, ysigsGolden, "Should be equal")
+
+	RC7, sigr := BLSRecoverSignature(k, x, ysigs)
+	assert.Equal(t, 0, RC7, "Should be equal")
+
+	sigrHex := hex.EncodeToString(sigr)
+	fmt.Printf("sigr: %s \n", sigrHex)
+
+	assert.Equal(t, sigr, sigGolden, "Should be equal")
+}
diff --git a/libs/crypto/secp256k1.go b/libs/crypto/secp256k1.go
new file mode 100644
index 0000000..9419f89
--- /dev/null
+++ b/libs/crypto/secp256k1.go
@@ -0,0 +1,110 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package crypto
+
+/*
+#cgo CFLAGS: -O2
+#cgo LDFLAGS: -lamcl_curve_SECP256K1 -lamcl_core
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <amcl/amcl.h>
+#include <amcl/randapi.h>
+#include <amcl/ecdh_SECP256K1.h>
+*/
+import "C"
+import (
+	"crypto/rand"
+	"encoding/hex"
+
+	"github.com/pkg/errors"
+)
+
+const (
+	hashFunc = C.int(C.SHA256)
+)
+
+var (
+	paramP1 = CreateOctet([]byte{0, 1, 2})
+	paramP2 = CreateOctet([]byte{0, 1, 2, 3})
+)
+
+// Secp256k1Encrypt encrypts a message using ECP_SECP256K1_ECIES
+func Secp256k1Encrypt(message, publicKey string) (C, V, T string, err error) {
+	dec := &hexBatchDecoder{}
+	wOctet := dec.decodeOctet(publicKey)
+	if dec.err != nil {
+		err = dec.err
+		return
+	}
+
+	seed := make([]byte, 32)
+	rand.Read(seed)
+	rng := NewRand(seed)
+
+	mOctet := CreateOctet([]byte(message))
+
+	//Results
+	vPtr := NewOctet(65)
+	hmacPtr := NewOctet(32)
+	cypherPtr := NewOctet(len(message) + 16 - (len(message) % 16))
+
+	C.ECP_SECP256K1_ECIES_ENCRYPT(hashFunc, paramP1, paramP2, (*C.csprng)(rng), (*C.octet)(wOctet), (*C.octet)(mOctet), C.int(12), vPtr, cypherPtr, hmacPtr)
+
+	return hex.EncodeToString(cypherPtr.ToBytes()), hex.EncodeToString(vPtr.ToBytes()), hex.EncodeToString(hmacPtr.ToBytes()), nil
+}
+
+// Secp256k1Decrypt decrypts an encrypoted message using ECP_SECP256K1_ECIES
+func Secp256k1Decrypt(C, V, T, sK string) (message string, err error) {
+	dec := &hexBatchDecoder{}
+	cOct := dec.decodeOctet(C)
+	vOct := dec.decodeOctet(V)
+	tOct := dec.decodeOctet(T)
+	uOct := dec.decodeOctet(sK)
+	if dec.err != nil {
+		err = dec.err
+		return
+	}
+
+	//Cast the cypherText back to Octets
+	mOct := NewOctet(len(C) + 16 - (len(C) % 16))
+
+	if C.ECP_SECP256K1_ECIES_DECRYPT(hashFunc, paramP1, paramP2, vOct, cOct, tOct, uOct, mOct) != 1 {
+		return "", errors.New("Cannot decrypt cyphertext")
+	}
+
+	b := mOct.ToBytes()
+	return string(b), nil
+}
+
+type hexBatchDecoder struct {
+	err error
+}
+
+func (d *hexBatchDecoder) decodeOctet(s string) *Octet {
+	if d.err != nil {
+		return nil
+	}
+
+	b, err := hex.DecodeString(s)
+	if err != nil {
+		d.err = err
+		return nil
+	}
+	return CreateOctet(b)
+}
diff --git a/libs/crypto/secp256k1_test.go b/libs/crypto/secp256k1_test.go
new file mode 100644
index 0000000..89781fb
--- /dev/null
+++ b/libs/crypto/secp256k1_test.go
@@ -0,0 +1,64 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package crypto
+
+import (
+	"fmt"
+	"testing"
+)
+
+const (
+	//For a longer testString see below
+	testString     = "The Qu1ck Br0wn F0x Jumps 0v3r Th3 L@zy D0g"
+	secpPublicKey  = "041adb36d23c6d01a77d0c2064d491a948922718b848a5f422d17f64b19d65c195986e0ee28049d34e912b3f8022eeb5ec60bcd6562d0c1ee507427e183bdbdd66"
+	secpPrivateKey = "8ba005a4ab3b655205435cd61da3630655ccba3c5365e32207eb9bdad561b38f"
+
+	testCypherText = "16751918cf55801daf36e6e6e595a41f3e31d7ba2db55790693e90dfff61ba617fa5ad63fb5fd0c52ccf4b2a85c1f527"
+	testT          = "68d7e2c2a4dbceb4e7b885d3"
+	testV          = "04a68004e3de100c2b76537e0b3d6eb95ce4f03e4dfac2e01527f73f723b4387c956d1120c6b64a812ccde3658ceeed80cf062e6ea6bf6a95395315e0ef6f2140f"
+)
+
+//TestEncrypt - C.ECP_SECP256K1_ECIES_ENCRYPT & DECRYPT
+func TestEncrypt(t *testing.T) {
+	C, V, T, err := Secp256k1Encrypt(testString, secpPublicKey)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	plainText, err := Secp256k1Decrypt(C, V, T, secpPrivateKey)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if plainText != testString {
+		t.Fatal(fmt.Sprintf("Failed to decrypt string, expects %s got %s", testString, plainText))
+	}
+}
+
+func TestDecrypt(t *testing.T) {
+
+	plainText, err := Secp256k1Decrypt(testCypherText, testV, testT, secpPrivateKey)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if plainText != testString {
+		t.Fatal(fmt.Sprintf("Failed to decrypt string, expects %s got %s", testString, plainText))
+	}
+
+}
diff --git a/libs/crypto/wrap.go b/libs/crypto/wrap.go
new file mode 100644
index 0000000..92c6c94
--- /dev/null
+++ b/libs/crypto/wrap.go
@@ -0,0 +1,83 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package crypto
+
+/*
+#include <amcl/randapi.h>
+*/
+import "C"
+import (
+	"encoding/hex"
+	"unsafe"
+)
+
+// Octet adds functionality around C octet
+type Octet = C.octet
+
+// NewOctet creates an empty Octet with a given size
+func NewOctet(maxSize int) *Octet {
+	return &Octet{
+		len: C.int(maxSize),
+		max: C.int(maxSize),
+		val: (*C.char)(C.calloc(1, C.size_t(maxSize))),
+	}
+}
+
+// CreateOctet creates new Octet with a value
+func CreateOctet(val []byte) *Octet {
+	if val == nil {
+		return nil
+	}
+
+	return &Octet{
+		len: C.int(len(val)),
+		max: C.int(len(val)),
+		val: C.CString(string(val)),
+	}
+}
+
+// Free frees the allocated memory
+func (o *Octet) Free() {
+	if o == nil {
+		return
+	}
+	C.free(unsafe.Pointer(o.val))
+}
+
+// ToBytes returns the bytes representation of the Octet
+func (o *Octet) ToBytes() []byte {
+	return C.GoBytes(unsafe.Pointer(o.val), o.len)
+}
+
+// ToString returns the hex encoded representation of the Octet
+func (o *Octet) ToString() string {
+	return hex.EncodeToString(o.ToBytes())
+}
+
+// Rand is a cryptographically secure random number generator
+type Rand C.csprng
+
+// NewRand create new seeded Rand
+func NewRand(seed []byte) *Rand {
+	sOct := CreateOctet(seed)
+	defer sOct.Free()
+
+	var rand C.csprng
+	C.CREATE_CSPRNG(&rand, sOct)
+	return (*Rand)(&rand)
+}
diff --git a/libs/cryptowallet/hdwallet.go b/libs/cryptowallet/hdwallet.go
new file mode 100644
index 0000000..1d6bbe3
--- /dev/null
+++ b/libs/cryptowallet/hdwallet.go
@@ -0,0 +1,174 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package cryptowallet - generates and manipulates SECP256 keys
+*/
+package cryptowallet
+
+import (
+	"encoding/hex"
+
+	"github.com/btcsuite/btcd/btcec"
+	"github.com/btcsuite/btcd/chaincfg"
+	"github.com/btcsuite/btcutil/hdkeychain"
+	"github.com/pkg/errors"
+	bip39 "github.com/tyler-smith/go-bip39"
+)
+
+const (
+	// CoinTypeBitcoinMain is Bitcoin main network coin
+	CoinTypeBitcoinMain = 0
+	// CoinTypeBitcoinTestNet is Bitcoin test network coin
+	CoinTypeBitcoinTestNet = 1
+)
+
+var (
+	// ErrUnsupportedCoin is returned when the coinType is not supported
+	errUnsupportedCoin = errors.New("unsupported coin")
+)
+
+//BIP 32 - xPub/xPriv from seed
+//BIP 39 - Mnemonic Wordlist
+//BIP 44 - m / purpose' / coin_type' / account' / change / address_index
+
+/*
+   Some Useful tools for testsing
+   Mnemonic Code Converter tool
+   https://iancoleman.io/bip39/
+
+   Key Convertor
+   https://www.bitaddress.org
+*/
+
+// userWallet holds the persistent user data
+
+//chainParams chain config based on coin type
+func chainParams(coinType int) (*chaincfg.Params, error) {
+	switch coinType {
+	case CoinTypeBitcoinMain:
+		return &chaincfg.MainNetParams, nil
+	case CoinTypeBitcoinTestNet:
+		return &chaincfg.TestNet3Params, nil
+	}
+	return nil, errUnsupportedCoin
+}
+
+// Bip44Address -  generates a bitcoin address & private key for a given BIP44 path  -return btc address, private key, error
+func Bip44Address(seed []byte, coinType int, account int, change int, addressIndex int64) (string, *btcec.PublicKey, *btcec.PrivateKey, error) {
+	chain, err := chainParams(coinType)
+	if err != nil {
+		return "", nil, nil, err
+	}
+	bip32extended, err := bip32Extended(seed, coinType, account, change)
+	if err != nil {
+		return "", nil, nil, errors.Wrap(err, "Failed to BIP32 Ext from seed,coin,acc,change")
+	}
+	priveAddKey, err := bip32extended.Child(uint32(addressIndex))
+	if err != nil {
+		return "", nil, nil, errors.Wrap(err, "Failed to derive child from Bip32 ext")
+	}
+	priv, err := priveAddKey.ECPrivKey()
+	if err != nil {
+		return "", nil, nil, errors.Wrap(err, "Failed to extract Private key from ECPriv")
+	}
+	pubKey, err := priveAddKey.ECPubKey()
+	if err != nil {
+		return "", nil, nil, errors.Wrap(err, "Failed to extract Public key from ECPriv")
+	}
+	pub, err := priveAddKey.Address(chain)
+	if err != nil {
+		return "", nil, nil, errors.Wrap(err, "Failed to extract public key from priv key")
+	}
+	pubAdd := pub.EncodeAddress()
+	return pubAdd, pubKey, priv, nil
+}
+
+// MasterKeyFromSeed Generates a MasterKey or XPriv from a seed
+func masterKeyFromSeed(seed []byte, coinType int) (*hdkeychain.ExtendedKey, error) {
+	chain, err := chainParams(coinType)
+	if err != nil {
+		return nil, err
+	}
+	masterKey, err := hdkeychain.NewMaster(seed, chain)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to derive masterkey from seed")
+	}
+	return masterKey, nil
+}
+
+//Bip32Extended get Bip32 extended Keys for path
+func bip32Extended(seed []byte, coinType int, account int, change int) (*hdkeychain.ExtendedKey, error) {
+	masterKey, err := masterKeyFromSeed(seed, coinType)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to derive masterkey from seed")
+	}
+	hkStart := uint32(0x80000000)
+	child1, err := masterKey.Child(44 + hkStart)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to derive child1 from seed")
+	}
+	child2, err := child1.Child(uint32(coinType) + hkStart)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to derive child2 from seed")
+	}
+	child3, err := child2.Child(uint32(account) + hkStart)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to derive child3 from seed")
+	}
+	bip32extended, err := child3.Child(uint32(change))
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to derive BIP32ext from child3")
+	}
+	return bip32extended, nil
+}
+
+//SeedFromEntropy generate a Seed from supplied entropy string (from HSM)
+func seedFromEntropy(entropy string) ([]byte, error) {
+	entropyDecoded, err := hex.DecodeString(entropy)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to decode entropy as hex")
+	}
+	mnemonic, err := entropy2Mnemonic(entropyDecoded)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to derive mnemonic from Entropy")
+	}
+	seed, err := mnemonic2Seed(mnemonic)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to derive seed from mnemonic")
+	}
+	return seed, nil
+}
+
+//Entropy2Mnemonic convert a seed (entropy) to a Mmemonic String
+func entropy2Mnemonic(entropy []byte) (string, error) {
+	mnemonic, err := bip39.NewMnemonic(entropy)
+	if err != nil {
+		return "", errors.Wrap(err, "Failed to derive mnemonic from Entropy")
+	}
+	return mnemonic, nil
+}
+
+//Mnemonic2Seed convert BIP39 mnemonic (recovery phrase) to a seed byte array
+func mnemonic2Seed(mnemonic string) ([]byte, error) {
+	password := "" //we arent using passwords
+	seed, err := bip39.NewSeedWithErrorChecking(mnemonic, password)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to derive seed from Mnemonic")
+	}
+	return seed, nil
+}
diff --git a/libs/cryptowallet/hdwallet_test.go b/libs/cryptowallet/hdwallet_test.go
new file mode 100644
index 0000000..af7b2c4
--- /dev/null
+++ b/libs/cryptowallet/hdwallet_test.go
@@ -0,0 +1,192 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package cryptowallet
+
+import (
+	"encoding/hex"
+	"testing"
+
+	"github.com/btcsuite/btcd/chaincfg"
+	"github.com/btcsuite/btcutil"
+	"github.com/btcsuite/btcutil/hdkeychain"
+	"github.com/stretchr/testify/assert"
+)
+
+func Test_48ByteSeedGeneration(t *testing.T) {
+	seed, err := RandomBytes(65)
+	assert.Nil(t, err, "Error should be nil")
+	_, _, _, err = Bip44Address(seed, 0, 0, 0, 0)
+	assert.NotNil(t, err, "Error should be thrown Seed should be <=64")
+
+	seed, err = RandomBytes(64)
+	assert.Nil(t, err, "Error should be nil")
+	_, _, _, err = Bip44Address(seed, 0, 0, 0, 0)
+	assert.Nil(t, err, "Error should be nil")
+}
+
+func Test_OnlyGO(t *testing.T) {
+	hkStart := uint32(0x80000000)
+	masterSeed, err := hex.DecodeString("3779b041fab425e9c0fd55846b2a03e9a388fb12784067bd8ebdb464c2574a05bcc7a8eb54d7b2a2c8420ff60f630722ea5132d28605dbc996c8ca7d7a8311c0")
+	assert.Nil(t, err, "Error should be nil")
+	master, err := hdkeychain.NewMaster(masterSeed, &chaincfg.MainNetParams)
+	assert.Nil(t, err, "Error should be nil")
+	println(master.String())
+	ek1, err := master.Child(44 + hkStart)
+	assert.Nil(t, err, "Error should be nil")
+	ek2, err := ek1.Child(0 + hkStart)
+	assert.Nil(t, err, "Error should be nil")
+	ek3, err := ek2.Child(0 + hkStart)
+	assert.Nil(t, err, "Error should be nil")
+	ek4, err := ek3.Child(0)
+	assert.Nil(t, err, "Error should be nil")
+
+	//XPUB
+	pubKey, err := ek4.Neuter()
+	assert.Nil(t, err, "Error should be nil")
+	println(pubKey.String())           //XPUB
+	pubAddKey0, err := pubKey.Child(0) //0 address from XPUB
+	assert.Nil(t, err, "Error should be nil")
+	addr1, err := pubAddKey0.Address(&chaincfg.MainNetParams)
+	assert.Nil(t, err, "Error should be nil")
+	println(addr1.EncodeAddress())
+
+	//XPRIV
+	println(ek4.String())             //XPRIV
+	priveAddKey0, err := ek4.Child(0) //0 address from Priv
+	assert.Nil(t, err, "Error should be nil")
+	addr2, err := priveAddKey0.Address(&chaincfg.MainNetParams)
+	assert.Nil(t, err, "Error should be nil")
+	println(addr2.EncodeAddress())
+	priv, err := priveAddKey0.ECPrivKey()
+	assert.Nil(t, err, "Error should be nil")
+	wif, err := btcutil.NewWIF(priv, &chaincfg.MainNetParams, true)
+	assert.Nil(t, err, "Error should be nil")
+	println(wif.String())
+}
+
+//Test_BTCVectors - Cycle through the list of test vectors below taken from https://www.coinomi.com/recovery-phrase-tool.html
+//Need to add significantly more vectors for more edge cases, coins, accounts, change etc.
+func Test_BTCVectors(t *testing.T) {
+
+	for _, testVector := range vectors {
+
+		Chain := &testVector.net
+		startingEntropy, err := hex.DecodeString(testVector.entropy)
+		assert.Nil(t, err, "Error should be nil")
+
+		mnemonic, err := entropy2Mnemonic(startingEntropy)
+		assert.Nil(t, err, "Error should be nil")
+		assert.Equal(t, mnemonic, testVector.mnemonic, "Mnemonic is incorrect")
+
+		seed, err := mnemonic2Seed(mnemonic)
+		assert.Nil(t, err, "Error should be nil")
+		assert.Equal(t, hex.EncodeToString(seed), testVector.seed, "Seed from Mnemonic is incorrect")
+
+		seed2, err := seedFromEntropy(testVector.entropy)
+		assert.Nil(t, err, "Error should be nil")
+		assert.Equal(t, hex.EncodeToString(seed2), testVector.seed, "Seed from Mnemonic is incorrect")
+
+		xpriv, err := masterKeyFromSeed(seed, testVector.coin)
+		assert.Nil(t, err, "Error should be nil")
+		assert.Equal(t, xpriv.String(), testVector.bip32Root, "Invalid xPriv")
+		print("\n" + xpriv.String())
+
+		bip32Extended, err := bip32Extended(seed, testVector.coin, testVector.account, testVector.change)
+		assert.Nil(t, err, "Error should be nil")
+		assert.Equal(t, bip32Extended.String(), testVector.bip32ExPriv, "Invalid BIP32 Priv")
+		print("\n" + bip32Extended.String())
+
+		xPubKey, err := bip32Extended.Neuter()
+		assert.Nil(t, err, "Error should be nil")
+		xPub := xPubKey.String()
+		assert.Equal(t, xPub, testVector.bip32ExPub, "Invalid BIP32 Public (1)")
+
+		btcAdd, _, btcPrivKey, err := Bip44Address(seed, testVector.coin, testVector.account, testVector.change, testVector.addressIndex)
+		assert.Nil(t, err, "Error should be nil")
+		assert.Equal(t, btcAdd, testVector.address, "Invalid BTC Address")
+
+		wifComp, err := btcutil.NewWIF(btcPrivKey, Chain, true)
+		assert.Nil(t, err, "Error should be nil")
+		assert.Equal(t, wifComp.String(), testVector.privKey, "Invalid BTC Address")
+	}
+}
+
+var vectors = []struct {
+	net          chaincfg.Params
+	coin         int
+	account      int
+	change       int
+	addressIndex int64
+	entropy      string
+	mnemonic     string
+	seed         string
+	bip32Root    string
+	bip32ExPriv  string
+	bip32ExPub   string
+	address      string
+	privKey      string
+}{
+	{
+		chaincfg.MainNetParams,
+		0, 0, 0, 0,
+		"000102030405060708090a0b0c0d0e0f",
+		"abandon amount liar amount expire adjust cage candy arch gather drum buyer",
+		"3779b041fab425e9c0fd55846b2a03e9a388fb12784067bd8ebdb464c2574a05bcc7a8eb54d7b2a2c8420ff60f630722ea5132d28605dbc996c8ca7d7a8311c0",
+		"xprv9s21ZrQH143K2XojduRLQnU8D8K59KSBoMuQKGx8dW3NBitFDMkYGiJPwZdanjZonM7eXvcEbxwuGf3RdkCyyXjsbHSkwtLnJcsZ9US42Gd",
+		"xprvA2QWrMvVn11Cnc8Wv5XH22Phaz1eLLYUtUVCJxjRu3eSbPZk3WphdkqGBnAKiKtg3bxkL48zbf9C8jJKtbDhB4kTJuNfv3KZVRjxseHNNWk",
+		"xpub6FPsFsTPcNZW16Cz274HPALS91r8joGLFhQo7M93TPBRUBttb48xBZ9k34oiG29Bvqfry9QyXPsGXSRE1kjut92Dgik1w6Whm1GU4F122n8",
+		"128BCBZndgrPXzEgF4QbVR3jnQGwzRtEz5",
+		"L35qaFLpbCc9yCzeTuWJg4qWnTs9BaLr5CDYcnJ5UnGmgLo8JBgk",
+	},
+	{
+		chaincfg.MainNetParams,
+		0, 1, 1, 19,
+		"000102030405060708090a0b0c0d0e0f",
+		"abandon amount liar amount expire adjust cage candy arch gather drum buyer",
+		"3779b041fab425e9c0fd55846b2a03e9a388fb12784067bd8ebdb464c2574a05bcc7a8eb54d7b2a2c8420ff60f630722ea5132d28605dbc996c8ca7d7a8311c0",
+		"xprv9s21ZrQH143K2XojduRLQnU8D8K59KSBoMuQKGx8dW3NBitFDMkYGiJPwZdanjZonM7eXvcEbxwuGf3RdkCyyXjsbHSkwtLnJcsZ9US42Gd",
+		"xprvA1WdMXWAt7uoSc1STdHwXLLgWaiJovFwYAyHtowP666fCAZNA5T3msYkKqfiYFYwRVQqr8SbuYgtf2tZ1PJwWhWNHMjdknEnGkDmZrkpFn4",
+		"xpub6EVym334iVU6f65uZepwtUHR4cYoDNynuPtthCLzeRde4xtWhcmJKfsEB6vXKpYyh8FwwXoWE8NUDNvvsNAxDdXr3bwWhLfekyd3qcbbtuj",
+		"1N2pq8QzgYRmSyszkaGgNngpcUTqejsmKn",
+		"L3U3y6CFHwq9dS15VvtgHGorZFicanWBkfbee5gDp3m7uFHVoqAy",
+	},
+	{
+		chaincfg.TestNet3Params,
+		1, 0, 0, 0,
+		"000102030405060708090a0b0c0d0e0f",
+		"abandon amount liar amount expire adjust cage candy arch gather drum buyer",
+		"3779b041fab425e9c0fd55846b2a03e9a388fb12784067bd8ebdb464c2574a05bcc7a8eb54d7b2a2c8420ff60f630722ea5132d28605dbc996c8ca7d7a8311c0",
+		"tprv8ZgxMBicQKsPdM3GJUGqaS67XFjHNqUC8upXBhNb7UXqyKdLCj6HnTfqrjoEo6x89neRY2DzmKXhjWbAkxYvnb1U7vf4cF4qDicyb7Y2mNa",
+		"tprv8hJrzKEmbFfBx44tsRe1wHh25i5QGztsawJGmxeqryPwdXdKrgxMgJUWn35dY2nrYmomRWWL7Y9wJrA6EvKJ27BfQTX1tWzZVxAXrR2pLLn",
+		"tpubDDzu8jH1jdLrqX6gm5JcLhM8ejbLSL5nAEu44Uh9HFCLU1t6V5mwro6NxAXCfR2jUJ9vkYkUazKXQSU7WAaA9cbEkxdWmbLxHQnWqLyQ6uR",
+		"mq1VMMXiZKLdY2WLeaqocJxXijhEFoQu3X",
+		"cMwbkii126fSsPtWBUuUPrKZS5KK3qCjSNuRhcuw6sJ8HmVsrmHq",
+	},
+	{
+		chaincfg.TestNet3Params,
+		1, 1, 1, 19,
+		"000102030405060708090a0b0c0d0e0f",
+		"abandon amount liar amount expire adjust cage candy arch gather drum buyer",
+		"3779b041fab425e9c0fd55846b2a03e9a388fb12784067bd8ebdb464c2574a05bcc7a8eb54d7b2a2c8420ff60f630722ea5132d28605dbc996c8ca7d7a8311c0",
+		"tprv8ZgxMBicQKsPdM3GJUGqaS67XFjHNqUC8upXBhNb7UXqyKdLCj6HnTfqrjoEo6x89neRY2DzmKXhjWbAkxYvnb1U7vf4cF4qDicyb7Y2mNa",
+		"tprv8hfdp3VTvAW219XTuczuzC97BuNCpWZfRjPLEXgvrxfv8YW4yXFKAcic5S1AtPNWe36sXkUNWdAh6PSuQsYk3nabNKQnaPhGTx5etiDFSsW",
+		"tpubDEMfxTXi4YBgtcZFoGfWPboDkvt8yqka12z7X3jEHEUJy2kqbv4uM7LUFYcaMEApY7TbKj9FVqAhwUcvXVbLHRyyNRsUEFJy7x46dXMUHb2",
+		"mwXHRw1hMmWQhn54r3mXXZ62kaozQTkeTa",
+		"cPHvnD9R6ELjEWKamse2szPva2r8rJsxUHcKngfZghSTzaeaqa2g",
+	},
+}
diff --git a/libs/cryptowallet/keygen.go b/libs/cryptowallet/keygen.go
new file mode 100644
index 0000000..9e616bb
--- /dev/null
+++ b/libs/cryptowallet/keygen.go
@@ -0,0 +1,86 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package cryptowallet
+
+import (
+	"crypto/rand"
+	"encoding/hex"
+
+	"github.com/btcsuite/btcd/btcec"
+	"github.com/pkg/errors"
+)
+
+var (
+	errEntropyError = errors.New("Failed to supply entropy")
+)
+
+//RedeemSecret - using supplied seed return the 1st entry in the HD walet
+func RedeemSecret(entropy string) (secret string, err error) {
+	if entropy == "" {
+		return "", errEntropyError
+	}
+	seed, err := seedFromEntropy(entropy)
+	if err != nil {
+		return "", errors.Wrap(err, "Failed to create seed from entropy")
+	}
+	_, _, privKey, err := Bip44Address(seed, 0, 0, 0, 0)
+	if err != nil {
+		return "", errors.Wrap(err, "Failed to derive Wallet Key 0")
+	}
+	privateKeyStr := hex.EncodeToString(privKey.Serialize())
+	return privateKeyStr, nil
+}
+
+//RedeemPublicKey - using supplied seed return the 1st entry in the HD walet
+func RedeemPublicKey(entropy string) (secret string, err error) {
+	if entropy == "" {
+		return "", errEntropyError
+	}
+	seed, err := seedFromEntropy(entropy)
+	if err != nil {
+		return "", errors.Wrap(err, "Failed to create seed from entropy")
+	}
+	_, pubKey, _, err := Bip44Address(seed, 0, 0, 0, 0)
+	if err != nil {
+		return "", errors.Wrap(err, "Failed to derive Wallet Key 0")
+	}
+	pubKeyStr := hex.EncodeToString(pubKey.SerializeUncompressed())
+	return pubKeyStr, nil
+}
+
+//PublicKeyFromPrivate Derive EC Public key from a private key
+func PublicKeyFromPrivate(priv string) (string, string, error) {
+	remotePrivKeyBytes, err := hex.DecodeString(priv)
+	if err != nil {
+		return "", "", errors.Wrap(err, "Failed to hex decode PrivateKey")
+	}
+
+	_, cpub1 := btcec.PrivKeyFromBytes(btcec.S256(), remotePrivKeyBytes)
+	remotePubKeyStr := hex.EncodeToString(cpub1.SerializeUncompressed())
+	remotePubKeyCompressedStr := hex.EncodeToString(cpub1.SerializeCompressed())
+	return remotePubKeyStr, remotePubKeyCompressedStr, nil
+}
+
+//RandomBytes - generate n random bytes
+func RandomBytes(n int) ([]byte, error) {
+	bytes := make([]byte, n)
+	if _, err := rand.Read(bytes); err != nil {
+		return nil, err
+	}
+	return bytes, nil
+}
diff --git a/libs/cryptowallet/keygen_test.go b/libs/cryptowallet/keygen_test.go
new file mode 100644
index 0000000..b26d82e
--- /dev/null
+++ b/libs/cryptowallet/keygen_test.go
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package cryptowallet
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func Test_RedeemSecret(t *testing.T) {
+	secret, err := RedeemSecret("000102030405060708090a0b0c0d0e0f")
+	assert.Nil(t, err, "Error should be nil")
+	assert.Equal(t, "aef9737d5472303c32318fd6e33aade1fc3ac66159febaa02bd0f1a06834ba61", secret, "HD Wallet Address is incorrect")
+}
+
+func Test_RedeemPublicKey(t *testing.T) {
+	pubkey, err := RedeemPublicKey("000102030405060708090a0b0c0d0e0f")
+	assert.Nil(t, err, "Error should be nil")
+	assert.Equal(t, "04ce9b978595558053580d557ff40f9f99a4f1a7609c25268863ee64de7e4abbdad899f36b68872d13348a8098ba6132fb0a0ec4150058a237c7bcaf66e4e16ca7", pubkey, "HD Wallet Address is incorrect")
+}
+
+func Test_PublicKeyFromPrivate(t *testing.T) {
+	pub, _, err := PublicKeyFromPrivate("C70C9D95F4C1612C53886D2E07A2BAE5AA931F36C65E6AF13BFBA410A0CA1BD0")
+	assert.Nil(t, err, "Error should be nil")
+	assert.Equal(t, "04db1f3069f0e75feb1bdeeac9e29c8b8eb2ad1bbc9869f72481def876c1f50645b10ee6f9a640bd6dfd8d34286358b493f7b54c37e80ac9d97a4c01a41c0cc8eb", pub, "Pub key not derived from priv key")
+}
diff --git a/libs/datastore/boltbackend.go b/libs/datastore/boltbackend.go
new file mode 100644
index 0000000..4c4f5ee
--- /dev/null
+++ b/libs/datastore/boltbackend.go
@@ -0,0 +1,243 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package datastore
+
+import (
+	"bytes"
+	"encoding/gob"
+	"fmt"
+	"math/rand"
+	"time"
+
+	"github.com/pkg/errors"
+	bolt "go.etcd.io/bbolt"
+)
+
+// BoltBackend implements Backend interface with embedded Bolt storage
+type BoltBackend struct {
+	db *bolt.DB
+}
+
+// NewBoltBackend creates a new Bolt backend using CoreOS bbolt implementation
+func NewBoltBackend(filename string) (Backend, error) {
+	db, err := bolt.Open(
+		filename,
+		0600,
+		&bolt.Options{
+			Timeout: 1 * time.Second,
+		},
+	)
+
+	if err != nil {
+		return nil, errors.Wrap(err, "initialize bolt datastore backend")
+	}
+
+	return &BoltBackend{
+		db: db,
+	}, nil
+}
+
+// Set stores the value for a key of datatype using bolt datastore
+func (bb *BoltBackend) Set(datatype, key string, value []byte, indexData map[string]string) error {
+	return bb.db.Update(func(tx *bolt.Tx) error {
+		// Get or create the root bucket for the datatype
+		bk, err := tx.CreateBucketIfNotExists([]byte(datatype))
+		if err != nil {
+			return errors.Wrap(err, "failed to create root bucket")
+		}
+
+		// Get or crerate the data bucket for storing the key/values
+		dataBk, err := bk.CreateBucketIfNotExists([]byte("data"))
+		if err != nil {
+			return errors.Wrap(err, "failed to create data bucket")
+		}
+		// Store data in the data bucket
+		if err := dataBk.Put([]byte(key), value); err != nil {
+			return errors.Wrap(err, "failed to put data")
+		}
+
+		// Delete the previous indexes if they exists
+		if err := deleteIndexes(key, bk); err != nil {
+			return errors.Wrap(err, "delete old indexes")
+		}
+
+		// Perform indexing
+		if err := createIndexes(key, indexData, bk); err != nil {
+			return errors.Wrap(err, "create indexes")
+		}
+
+		return nil
+	})
+}
+
+// Get retreives the value for specified key and datatyoe
+// Returns ErrKeyNotFound if the key has no value set
+func (bb *BoltBackend) Get(datatype, key string) (data []byte, err error) {
+	err = bb.db.View(func(tx *bolt.Tx) error {
+		// Get the root bucket
+		bk := tx.Bucket([]byte(datatype))
+		if bk == nil {
+			return ErrKeyNotFound
+		}
+		dataBk := bk.Bucket([]byte("data"))
+		if dataBk == nil {
+			return ErrKeyNotFound
+		}
+
+		data = dataBk.Get([]byte(key))
+		if data == nil {
+			return ErrKeyNotFound
+		}
+
+		return nil
+	})
+
+	return
+}
+
+// Del deletes a key and all the indexes
+func (bb *BoltBackend) Del(datatype, key string) error {
+	return bb.db.Update(func(tx *bolt.Tx) error {
+		// Get the root bucket
+		bk := tx.Bucket([]byte(datatype))
+		if bk == nil {
+			return nil
+		}
+		dataBk := bk.Bucket([]byte("data"))
+		if dataBk == nil {
+			return nil
+		}
+
+		if err := deleteIndexes(key, bk); err != nil {
+			return errors.Wrap(err, "delete indexes")
+		}
+
+		return dataBk.Delete([]byte(key))
+	})
+}
+
+type iterFunc func() ([]byte, []byte)
+
+// ListKeys lists all keys for specified datatype
+func (bb *BoltBackend) ListKeys(datatype, index string, skip, limit int, reverse bool) (keys []string, err error) {
+	err = bb.db.View(func(tx *bolt.Tx) error {
+		// Get the root bucket
+		bk := tx.Bucket([]byte(datatype))
+		if bk == nil {
+			return nil
+		}
+		indexBk := bk.Bucket([]byte(fmt.Sprintf("index-%s", index)))
+		if indexBk == nil {
+			return nil
+		}
+		c := indexBk.Cursor()
+
+		var first, next iterFunc
+		switch reverse {
+		default:
+			first = c.First
+			next = c.Next
+		case true:
+			first = c.Last
+			next = c.Prev
+		}
+
+		i := 0
+		for k, v := first(); k != nil; k, v = next() {
+			i++
+			if i <= skip {
+				continue
+			}
+			keys = append(keys, string(v))
+			if limit > 0 && len(keys) >= limit {
+				break
+			}
+		}
+
+		return nil
+	})
+
+	return
+}
+
+// Close closes the database
+func (bb *BoltBackend) Close() error {
+	return errors.Wrap(bb.db.Close(), "close bolt datastore backend database")
+}
+
+func createIndexes(key string, indexData map[string]string, rootBucket *bolt.Bucket) error {
+	// Iterate over index values
+	for indexName, v := range indexData {
+		indexBk, err := rootBucket.CreateBucketIfNotExists([]byte(fmt.Sprintf("index-%s", indexName)))
+		if err != nil {
+			return errors.Wrapf(err, "failed to create index bucket for index %s", indexName)
+		}
+
+		// generate unique and sortable key
+		valueKey := createIndexValueKey(v)
+		if err := indexBk.Put([]byte(valueKey), []byte(key)); err != nil {
+			return errors.Wrap(err, "failed to put index data")
+		}
+
+		// update the index data with the actual key
+		indexData[indexName] = valueKey
+	}
+
+	b := new(bytes.Buffer)
+	if err := gob.NewEncoder(b).Encode(&indexData); err != nil {
+		return errors.Wrap(err, "failed to encode index data")
+	}
+
+	return rootBucket.Put([]byte(fmt.Sprintf("indexes-%s", key)), b.Bytes())
+}
+
+func deleteIndexes(key string, rootBucket *bolt.Bucket) error {
+	kiData := rootBucket.Get([]byte(fmt.Sprintf("indexes-%s", key)))
+	if kiData == nil {
+		return nil
+	}
+
+	indexData := map[string]string{}
+	b := bytes.NewBuffer(kiData)
+	if err := gob.NewDecoder(b).Decode(&indexData); err != nil {
+		return errors.Wrap(err, "invalid index data")
+	}
+
+	for indexName, v := range indexData {
+		indexBk := rootBucket.Bucket([]byte(fmt.Sprintf("index-%s", indexName)))
+		if indexBk == nil {
+			return errors.Errorf("index not found: %s", indexName)
+		}
+
+		if err := indexBk.Delete([]byte(v)); err != nil {
+			return nil
+		}
+	}
+
+	return rootBucket.Delete([]byte(fmt.Sprintf("indexes-%s", key)))
+}
+
+func createIndexValueKey(v string) string {
+	randBytes := make([]byte, 8)
+	rand.Read(randBytes)
+	return fmt.Sprintf("%s\x00%s%x", v, time.Now().UTC().Format(time.RFC3339), randBytes)
+}
+
+func init() {
+	rand.Seed(time.Now().UnixNano())
+}
diff --git a/libs/datastore/boltbackend_test.go b/libs/datastore/boltbackend_test.go
new file mode 100644
index 0000000..9ffffb6
--- /dev/null
+++ b/libs/datastore/boltbackend_test.go
@@ -0,0 +1,151 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package datastore
+
+import (
+	"bytes"
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+	"time"
+)
+
+const (
+	opSet = iota
+	opGet
+	opDel
+	opListKeys
+)
+
+func TestBoltBackend(t *testing.T) {
+	type tcOp struct {
+		optype      int
+		doctype     string
+		key         string
+		err         error
+		result      interface{}
+		listLimit   int
+		listSkip    int
+		listReverse bool
+	}
+
+	seedValues := []struct {
+		doctype string
+		key     string
+		value   []byte
+		index   map[string]string
+	}{
+		{"test", "3", []byte{3, 4, 5}, map[string]string{"index": "3"}},
+		{"test", "1", []byte{1, 2, 3}, map[string]string{"index": "1"}},
+		{"test", "4", []byte{4, 5}, map[string]string{"index": "4"}},
+		{"test", "2", []byte{2, 3, 4}, map[string]string{"index": "2"}},
+		{"test", "5", []byte{5, 6}, map[string]string{"index": "5"}},
+	}
+
+	testCases := []tcOp{
+		{opGet, "test", "", ErrKeyNotFound, nil, 0, 0, false},
+		{opGet, "", "1", ErrKeyNotFound, nil, 0, 0, false},
+		{opGet, "test", "1", nil, []byte{1, 2, 3}, 0, 0, false},
+		{opListKeys, "test", "index", nil, []string{"1", "2", "3", "4", "5"}, 0, 0, false},
+		{opDel, "test", "", nil, nil, 0, 0, false},
+		{opDel, "", "1", nil, nil, 0, 0, false},
+		{opDel, "test", "1", nil, nil, 0, 0, false},
+		{opDel, "test", "1", nil, nil, 0, 0, false},
+		{opListKeys, "test", "index", nil, []string{"2", "3", "4", "5"}, 0, 0, false},
+		{opListKeys, "test", "index", nil, []string{"2"}, 0, 1, false},
+		{opListKeys, "test", "index", nil, []string{"3", "4"}, 1, 2, false},
+		{opListKeys, "test", "index", nil, []string{"4", "5"}, 2, 2, false},
+		{opListKeys, "test", "index", nil, []string{"5"}, 3, 2, false},
+		{opListKeys, "test", "index", nil, []string{}, 4, 2, false},
+		{opListKeys, "test", "index", nil, []string{}, 5, 0, false},
+		{opListKeys, "test", "index", nil, []string{"2", "3", "4", "5"}, 0, 10, false},
+		{opListKeys, "test", "index", nil, []string{"5", "4", "3", "2"}, 0, 0, true},
+		{opListKeys, "test", "index", nil, []string{"4", "3", "2"}, 1, 0, true},
+		{opListKeys, "test", "index", nil, []string{"5"}, 0, 1, true},
+		{opListKeys, "test", "index", nil, []string{"4", "3"}, 1, 2, true},
+		{opListKeys, "test", "index", nil, []string{"3", "2"}, 2, 2, true},
+		{opListKeys, "test", "index", nil, []string{"2"}, 3, 2, true},
+		{opListKeys, "test", "index", nil, []string{}, 4, 2, true},
+		{opListKeys, "test", "index", nil, []string{}, 5, 0, true},
+		{opListKeys, "test", "index", nil, []string{"5", "4", "3", "2"}, 0, 10, true},
+
+		{opListKeys, "test-invalid", "index", nil, []string{}, 0, 5, false},
+		{opListKeys, "test", "index-invalid", nil, []string{}, 0, 5, false},
+	}
+
+	dbName := genTempFilename()
+	defer os.Remove(dbName)
+
+	b, err := NewBoltBackend(dbName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, sv := range seedValues {
+		if err := b.Set(sv.doctype, sv.key, sv.value, sv.index); err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	for itc, tc := range testCases {
+		t.Run(fmt.Sprintf("test case %d", itc), func(t *testing.T) {
+			switch tc.optype {
+			case opGet:
+				result, err := b.Get(tc.doctype, tc.key)
+				if err != tc.err {
+					t.Fatalf("invalid Get error response. Expected: %v, found: %v", tc.err, err)
+				}
+				if err != nil {
+					break
+				}
+				if !bytes.Equal(result, tc.result.([]byte)) {
+					t.Fatalf("invalid Get result. Expected: %v, found: %v", tc.result, result)
+				}
+			case opDel:
+				if err := b.Del(tc.doctype, tc.key); err != tc.err {
+					t.Fatalf("invalid Del error response. Expected: %v, found: %v", tc.err, err)
+				}
+			case opListKeys:
+				result, err := b.ListKeys(tc.doctype, tc.key, tc.listLimit, tc.listSkip, tc.listReverse)
+				if err != tc.err {
+					t.Fatalf("invalid ListKeys error response. Expected: %v, found: %v", tc.err, err)
+				}
+				if err != nil {
+					break
+				}
+
+				if strings.Join(result, "") != strings.Join(tc.result.([]string), "") {
+					t.Fatalf("invalid ListKeys result. Expected: %v, found: %v", tc.result, result)
+				}
+			}
+		})
+	}
+
+	if err := b.Close(); err != nil {
+		t.Fatalf("Close database: %v", err)
+	}
+
+}
+
+func genTempFilename() string {
+	tempDir := os.TempDir()
+	filename := fmt.Sprintf("milagro-test-bolt-%v.db", time.Now().UnixNano())
+	return filepath.Join(tempDir, filename)
+}
diff --git a/libs/datastore/datastore.go b/libs/datastore/datastore.go
new file mode 100644
index 0000000..a84a366
--- /dev/null
+++ b/libs/datastore/datastore.go
@@ -0,0 +1,154 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package datastore - enables data to be persisted in built in datebase (Bolt)
+*/
+package datastore
+
+import (
+	"errors"
+)
+
+var (
+	// ErrBackendNotInitialized is returned when the backend is not set
+	ErrBackendNotInitialized = errors.New("backend not initialized")
+	// ErrCodecNotInitialized is returned when the codec is not set
+	ErrCodecNotInitialized = errors.New("codec not initialized")
+	// ErrKeyNotFound is returned when an attempt to load a value of a missing key is made
+	ErrKeyNotFound = errors.New("key not found")
+)
+
+// Store provides key-value data storage with
+// specific backend and codec
+type Store struct {
+	backend Backend
+	codec   Codec
+}
+
+// NewStore constructs a new store
+func NewStore(options ...StoreOption) (*Store, error) {
+	s := &Store{}
+
+	for _, option := range options {
+		if err := option(s); err != nil {
+			return nil, err
+		}
+	}
+
+	return s, nil
+}
+
+// Set stores the value for a key of datatype
+func (s *Store) Set(datatype, key string, v interface{}, indexData map[string]string) error {
+	if err := s.checkInit(); err != nil {
+		return err
+	}
+
+	vbytes, err := s.codec.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	if err := s.backend.Set(datatype, key, vbytes, indexData); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Get retreives the value for specified key and datatyoe
+// Returns ErrKeyNotFound if the key has no value set
+func (s *Store) Get(datatype, key string, v interface{}) error {
+	if err := s.checkInit(); err != nil {
+		return err
+	}
+
+	vbytes, err := s.backend.Get(datatype, key)
+	if err != nil {
+		return err
+	}
+
+	if err := s.codec.Unmarshal(vbytes, v); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Del deletes a key and all the indexes
+func (s *Store) Del(datatype, key string) error {
+	if err := s.checkInit(); err != nil {
+		return err
+	}
+
+	return s.backend.Del(datatype, key)
+}
+
+// Close closes the database
+func (s *Store) Close() error {
+	return s.backend.Close()
+}
+
+// ListKeys lists keys by index
+func (s *Store) ListKeys(datatype, index string, skip, limit int, reverse bool) (keys []string, err error) {
+	return s.backend.ListKeys(datatype, index, skip, limit, reverse)
+}
+
+func (s *Store) checkInit() error {
+	if s.backend == nil {
+		return ErrBackendNotInitialized
+	}
+	if s.codec == nil {
+		return ErrBackendNotInitialized
+	}
+	return nil
+}
+
+// StoreOption sets additional parameters to the Store
+type StoreOption func(s *Store) error
+
+// WithBackend sets the store backend
+func WithBackend(b Backend) StoreOption {
+	return func(s *Store) error {
+		s.backend = b
+		return nil
+	}
+}
+
+// WithCodec sets the store codec
+func WithCodec(enc Codec) StoreOption {
+	return func(s *Store) error {
+		s.codec = enc
+		return nil
+	}
+}
+
+// Backend provides data storage interface
+type Backend interface {
+	Set(datatype, key string, value []byte, indexData map[string]string) error
+	Get(datatype, key string) ([]byte, error)
+	Del(datatype, key string) error
+	ListKeys(datatype, index string, skip, limit int, reverse bool) (keys []string, err error)
+	Close() error
+}
+
+// Codec probides data serialization interface
+type Codec interface {
+	Marshal(v interface{}) ([]byte, error)
+	Unmarshal([]byte, interface{}) error
+}
diff --git a/libs/datastore/gobcodec.go b/libs/datastore/gobcodec.go
new file mode 100644
index 0000000..92765b4
--- /dev/null
+++ b/libs/datastore/gobcodec.go
@@ -0,0 +1,51 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package datastore
+
+import (
+	"bytes"
+	"encoding/gob"
+)
+
+// GOBCodec implement Codec interface with GOB encoding
+type GOBCodec struct{}
+
+// NewGOBCodec creates a new GOB Codec
+func NewGOBCodec() Codec {
+	return &GOBCodec{}
+}
+
+// Marshal with GOB encoding
+func (s *GOBCodec) Marshal(v interface{}) ([]byte, error) {
+	buf := new(bytes.Buffer)
+	if err := gob.NewEncoder(buf).Encode(v); err != nil {
+		return nil, err
+	}
+
+	return buf.Bytes(), nil
+}
+
+// Unmarshal with GOB encoding
+func (s *GOBCodec) Unmarshal(b []byte, v interface{}) error {
+	buf := bytes.NewBuffer(b)
+	if err := gob.NewDecoder(buf).Decode(v); err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/libs/datastore/jsoncodec.go b/libs/datastore/jsoncodec.go
new file mode 100644
index 0000000..c672010
--- /dev/null
+++ b/libs/datastore/jsoncodec.go
@@ -0,0 +1,38 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package datastore
+
+import "encoding/json"
+
+// JSONCodec implement Codec interface with JSON encoding
+type JSONCodec struct{}
+
+// NewJSONCodec creates a new JSON Codec
+func NewJSONCodec() Codec {
+	return &JSONCodec{}
+}
+
+// Marshal with JSON encoding
+func (s *JSONCodec) Marshal(v interface{}) ([]byte, error) {
+	return json.Marshal(v)
+}
+
+// Unmarshal with JSON encoding
+func (s *JSONCodec) Unmarshal(b []byte, v interface{}) error {
+	return json.Unmarshal(b, v)
+}
diff --git a/libs/documents/build b/libs/documents/build
new file mode 100755
index 0000000..7f76f2d
--- /dev/null
+++ b/libs/documents/build
@@ -0,0 +1,9 @@
+#build the protobuffer docs.pb.go file from the definition file docs.proto
+protoc \
+  --proto_path=$HOME/go/src \
+  --proto_path=$HOME/go/src/github.com/gogo/protobuf/ \
+  --proto_path=. \
+  --go_out=. \
+  --govalidators_out=. \
+  *.proto
+
diff --git a/libs/documents/crypto.go b/libs/documents/crypto.go
new file mode 100644
index 0000000..f504ec0
--- /dev/null
+++ b/libs/documents/crypto.go
@@ -0,0 +1,171 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package documents
+
+import (
+	"bytes"
+	"fmt"
+
+	"github.com/apache/incubator-milagro-dta/libs/crypto"
+	"github.com/apache/incubator-milagro-dta/libs/cryptowallet"
+	proto "github.com/golang/protobuf/proto"
+	"github.com/pkg/errors"
+)
+
+var (
+	errRecipientNotFound      = errors.New("Recipient not found")
+	errFailedDecapsulation    = errors.New("Failed to decapsulate AES key")
+	errFailedToGenerateAESKey = errors.New("Failed to generate Random aesKey")
+)
+
+//decapsulate - decapsulate the aes for Recipient ID in the list
+func decapsulate(recipientCID string, recipients []*Recipient, sikeSK []byte) ([]byte, error) {
+	for _, recipient := range recipients {
+		if recipient.CID == recipientCID {
+			return decapsulateWithRecipient(*recipient, sikeSK)
+		}
+	}
+	return nil, errRecipientNotFound
+}
+
+func decapsulateWithRecipient(recipient Recipient, sikeSK []byte) ([]byte, error) {
+	cipherText := recipient.CipherText
+	encapsulatedKey := recipient.EncapsulatedKey
+	encapIV := recipient.IV
+
+	rc, recreatedAesKey := crypto.DecapsulateDecrypt(cipherText, encapIV, sikeSK, encapsulatedKey)
+
+	if rc != 0 {
+		return nil, errFailedDecapsulation
+	}
+	return recreatedAesKey, nil
+}
+
+func encapsulateKeyForRecipient(recipientsIDDocs map[string]IDDoc, secret []byte) (recipientList []*Recipient, err error) {
+	for id, idDocument := range recipientsIDDocs {
+		r := &Recipient{}
+		iv, err := cryptowallet.RandomBytes(16)
+		if err != nil {
+			return nil, errFailedToGenerateAESKey
+		}
+		r.CID = id
+		r.IV = iv
+		sikePK := idDocument.SikePublicKey
+
+		rc, cipherText, encapsulatedKey := crypto.EncapsulateEncrypt(secret, iv, sikePK)
+
+		if rc != 0 {
+			return nil, errFailedToGenerateAESKey
+		}
+		r.EncapsulatedKey = encapsulatedKey
+		r.CipherText = cipherText
+		recipientList = append(recipientList, r)
+	}
+
+	return recipientList, nil
+}
+
+func aesEncrypt(plainText []byte) (cipherText []byte, aesKey []byte, iv []byte, err error) {
+	aesKey, err = cryptowallet.RandomBytes(32)
+	if err != nil {
+		return nil, nil, nil, errFailedToGenerateAESKey
+	}
+	iv, err = cryptowallet.RandomBytes(16)
+	if err != nil {
+		return nil, nil, nil, errFailedToGenerateAESKey
+	}
+	paddedText, err := pkcs7Pad(plainText, 32)
+	if err != nil {
+		return nil, nil, nil, errors.Wrap(err, "Failed to pad Document secret")
+	}
+	cipherText = crypto.AESCBCEncrypt(aesKey, iv, paddedText)
+	return cipherText, aesKey, iv, nil
+}
+
+func aesDecrypt(cipherText []byte, iv []byte, aesKey []byte) (plainText []byte, err error) {
+	pt := crypto.AESCBCDecrypt(aesKey, iv, cipherText)
+	plainText, err = pkcs7Unpad(pt, 32)
+	if err != nil {
+		return nil, err
+	}
+	return plainText, nil
+}
+
+//Sign - generate a Signed envelope from the envelope
+func sign(envelope Envelope, blsSK []byte, signerNodeID string) (SignedEnvelope, error) {
+	envelopeBytes, err := proto.Marshal(&envelope)
+	if err != nil {
+		return SignedEnvelope{}, errors.Wrap(err, "Failed to serialize envelope in SignBLS")
+	}
+	rc, signature := crypto.BLSSign(envelopeBytes, blsSK)
+	if rc != 0 {
+		return SignedEnvelope{}, errors.Wrap(err, "Failed to sign envelope in in SignBLS")
+	}
+	signedEnvelope := SignedEnvelope{}
+	signedEnvelope.SignerCID = signerNodeID
+	signedEnvelope.Message = envelopeBytes
+	signedEnvelope.Signature = signature
+	return signedEnvelope, nil
+}
+
+//Verify verify the envelopes BLS signature
+func Verify(signedEnvelope SignedEnvelope, blsPK []byte) error {
+	message := signedEnvelope.Message
+	signature := signedEnvelope.Signature
+
+	rc := crypto.BLSVerify(message, blsPK, signature)
+	if rc == 0 {
+		return nil
+	}
+	return errors.New("invalid signature")
+}
+
+// Appends padding.
+func pkcs7Pad(data []byte, blocklen int) ([]byte, error) {
+	if blocklen <= 0 {
+		return nil, fmt.Errorf("invalid blocklen %d", blocklen)
+	}
+	padlen := 1
+	for ((len(data) + padlen) % blocklen) != 0 {
+		padlen = padlen + 1
+	}
+	pad := bytes.Repeat([]byte{byte(padlen)}, padlen)
+	return append(data, pad...), nil
+}
+
+// Returns slice of the original data without padding.
+func pkcs7Unpad(data []byte, blocklen int) ([]byte, error) {
+	if blocklen <= 0 {
+		return nil, fmt.Errorf("invalid blocklen %d", blocklen)
+	}
+	if len(data)%blocklen != 0 || len(data) == 0 {
+		return nil, fmt.Errorf("invalid data len %d", len(data))
+	}
+	padlen := int(data[len(data)-1])
+	if padlen > blocklen || padlen == 0 {
+		return nil, fmt.Errorf("invalid padding")
+	}
+	// check padding
+	pad := data[len(data)-padlen:]
+	for i := 0; i < padlen; i++ {
+		if pad[i] != byte(padlen) {
+			return nil, fmt.Errorf("invalid padding")
+		}
+	}
+	return data[:len(data)-padlen], nil
+}
diff --git a/libs/documents/docList.go b/libs/documents/docList.go
new file mode 100644
index 0000000..27ebabe
--- /dev/null
+++ b/libs/documents/docList.go
@@ -0,0 +1,83 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package documents
+
+// DocList is an array of all available document types currently supported.
+// It is necessary because the envelope body can store many different types of proto structs
+// You can't make an instance of a struct by the name of its type in golang, so this list
+// facilitates the creation of empty objects of the correct type.
+
+// In SmartDecodeEnvelope
+// 1)	DocList is used to determine a textual description of a message at runtime
+// 2)	When the message body types are unknown (eg. in the case of the command line tool)
+// 	The payload types are taken from the header, these are then used to obtain the DocType
+// 	and its subsequent (empty) message (proto.Message).
+// 	The objects can then be correctly populated using the type specific DecodeEnvelope
+
+// 	DecodeEnvelope has supplied types which are populated by the envelope and returned
+
+import (
+	"reflect"
+
+	"github.com/gogo/protobuf/proto"
+	"github.com/pkg/errors"
+)
+
+//DocType - defines a document which is parseable
+//It is necessary to build this list because there is no inheritance in
+type DocType struct {
+	Name     string //English name of the document
+	TypeCode float32
+	Version  float32
+	Message  proto.Message //An empty instance of the document for comparison
+}
+
+//DocList This is a master list of documents supported
+var DocList = []DocType{
+	//      Name. TypeCode, Version, Message
+	{"empty", 0, 1.0, nil},
+	{"Simple", 1, 1.0, &SimpleString{}},
+	{"PlainTestMessage1", 2, 1.0, &PlainTestMessage1{}},
+	{"EncryptTestMessage1", 3, 1.0, &EncryptTestMessage1{}},
+	{"IDDocument", 100, 1.0, &IDDocument{}},
+	{"OrderDocument", 101, 1.0, &OrderDocument{}},
+	{"PolicyDocument", 102, 1.0, &Policy{}},
+}
+
+//GetDocTypeForType return the DocType for a given Doc Code
+func GetDocTypeForType(docType float32) DocType {
+	for _, doc := range DocList {
+		if doc.TypeCode == docType {
+			return doc
+		}
+	}
+	return DocList[0]
+}
+
+//detectDocType Detect the DocType for the supplied protobuf Message, using the DocList
+func detectDocType(message proto.Message) (DocType, error) {
+	if message == nil {
+		return DocList[0], nil
+	}
+	for _, doc := range DocList {
+		if reflect.TypeOf(message) == reflect.TypeOf(doc.Message) {
+			return doc, nil
+		}
+	}
+	return DocType{}, errors.New("Document not found")
+}
diff --git a/libs/documents/docValidation_test.go b/libs/documents/docValidation_test.go
new file mode 100644
index 0000000..d1eca97
--- /dev/null
+++ b/libs/documents/docValidation_test.go
@@ -0,0 +1,111 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package documents
+
+import (
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/apache/incubator-milagro-dta/libs/cryptowallet"
+	multihash "github.com/multiformats/go-multihash"
+	"github.com/stretchr/testify/assert"
+)
+
+var (
+	pass = true
+	fail = false
+)
+
+func Test_1(t *testing.T) {
+	now := time.Now().Unix()
+
+	msg := &OrderDocument{
+		Coin:      10,
+		Reference: "ABC",
+		Timestamp: now,
+	}
+	err := msg.Validate()
+	assert.Nil(t, err, "Validation Failed")
+}
+
+func Test_SignedEnvelope(t *testing.T) {
+	se := &SignedEnvelope{
+		Signature: []byte("012345678901234567890123456789"),
+		SignerCID: "",
+		Message:   nil,
+	}
+	err := se.Validate()
+	assert.Nil(t, err, "Validation Failed1")
+
+}
+
+func Test_IPFSRegex(t *testing.T) {
+
+	rec := &Recipient{
+		Version: 1,
+		CID:     "QmSkKsExuUZJ9ETraPB9ZA9KySYGynvx1jK7LmWgRxinhx",
+	}
+	err := rec.Validate()
+	assert.Nil(t, err, "Validation Failed1")
+
+	rec = &Recipient{
+		Version: 1,
+		CID:     "QmSkKsExuUZJ9ETraPB9ZA9KySYGynvx1jK7LmWgRxinhx1", //extra char
+	}
+	err = rec.Validate()
+	assert.NotNil(t, err, "Validation Failed2")
+
+	rec = &Recipient{
+		Version: 1,
+		CID:     "QmSkKsExuUZJ9ETraPB9ZA9KySYGynvx1jK7LmWgRxinh", //less 1 char
+	}
+	err = rec.Validate()
+	assert.NotNil(t, err, "Validation Failed3")
+
+	rec = &Recipient{
+		Version: 1,
+		CID:     "QmSkKsExuUZJ9ETraPB9;A9KySYGynvx1jK7LmWgRxinhx", //puncuation
+	}
+	err = rec.Validate()
+	assert.NotNil(t, err, "Validation Failed4")
+
+	rec = &Recipient{
+		Version: 1,
+		CID:     "",
+	}
+	err = rec.Validate()
+	assert.Nil(t, err, "Validation Failed5")
+
+	rec = &Recipient{}
+	err = rec.Validate()
+	assert.Nil(t, err, "Validation Failed6")
+
+	for i := 0; i < 1000; i++ {
+		rnddata, _ := cryptowallet.RandomBytes(32)
+		mh, _ := multihash.Sum(rnddata, multihash.SHA2_256, 32)
+		cid := mh.B58String()
+		cid = fmt.Sprintf("%s", cid)
+		rec := &Recipient{
+			Version: 1,
+			CID:     cid,
+		}
+		err := rec.Validate()
+		assert.Nil(t, err, "Validation Failed1")
+	}
+}
diff --git a/libs/documents/docs.go b/libs/documents/docs.go
new file mode 100644
index 0000000..ae36c11
--- /dev/null
+++ b/libs/documents/docs.go
@@ -0,0 +1,235 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package documents - data is signed and nested in "encrypted envelope"
+*/
+package documents
+
+import (
+	"github.com/gogo/protobuf/proto"
+	"github.com/pkg/errors"
+)
+
+//DocType - defines a document that is parseable
+//It is necessary to build this list because there is no inheritance in
+
+var (
+	//EnvelopeVersion the versioning of the entire Envelope, (not individual documents/contents)
+	EnvelopeVersion float32 = 1.0
+)
+
+//IDDoc wrapper to encapsulate Header & IDDocument into one object
+type IDDoc struct {
+	*Header
+	*IDDocument
+}
+
+//OrderDoc puts and order in encrypted wrapper
+type OrderDoc struct {
+	*Header
+	*OrderDocument
+}
+
+//NewIDDoc generate a new empty IDDoc
+func NewIDDoc() IDDoc {
+	ret := IDDoc{}
+	ret.Header = &Header{}
+	ret.IDDocument = &IDDocument{}
+	return ret
+}
+
+//NewOrderDoc generate a new order
+func NewOrderDoc() OrderDoc {
+	ret := OrderDoc{}
+	ret.Header = &Header{}
+	ret.OrderDocument = &OrderDocument{}
+	return ret
+}
+
+//EncodeIDDocument encode an IDDoc into a raw bytes stream for the wire
+func EncodeIDDocument(idDocument IDDoc, blsSK []byte) ([]byte, error) {
+	header := idDocument.Header
+	plaintext := idDocument.IDDocument
+	rawDoc, err := Encode("", plaintext, nil, header, blsSK, nil)
+	return rawDoc, err
+}
+
+//EncodeOrderDocument encode an OrderDoc into a raw bytes stream for the wire
+func EncodeOrderDocument(nodeID string, orderDoc OrderDoc, blsSK []byte, previousCID string, recipients map[string]IDDoc) ([]byte, error) {
+	header := orderDoc.Header
+	header.PreviousCID = previousCID
+	//	rawDoc, err := Encode(orderDoc.OrderDocument, nil, header, blsSK, nil)
+	rawDoc, err := Encode(nodeID, nil, orderDoc.OrderDocument, header, blsSK, recipients)
+	return rawDoc, err
+}
+
+//DecodeIDDocument - decode a raw byte stream into an IDDocument
+func DecodeIDDocument(rawdoc []byte, tag string, idDocument *IDDoc) error {
+	plainText := IDDocument{}
+	header, err := Decode(rawdoc, tag, nil, "", &plainText, nil, nil)
+	if err != nil {
+		return errors.Wrap(err, "DecodeIDDocument Failed to Decode")
+	}
+	idDocument.Header = header
+	idDocument.IDDocument = &plainText
+
+	//validate the order document
+	err = idDocument.IDDocument.Validate()
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+//DecodeOrderDocument -
+func DecodeOrderDocument(rawdoc []byte, tag string, orderdoc *OrderDoc, sikeSK []byte, recipientCID string, sendersBlsPK []byte) error {
+	cipherText := OrderDocument{}
+	header, err := Decode(rawdoc, tag, sikeSK, recipientCID, nil, &cipherText, sendersBlsPK)
+	if err != nil {
+		return errors.Wrap(err, "DecodeIDDocument Failed to Decode")
+	}
+	orderdoc.Header = header
+	orderdoc.OrderDocument = &cipherText
+
+	//validate the order document
+	err = orderdoc.OrderDocument.Validate()
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+//Decode - Given a raw envelope, Sike Secret Key & ID - decode into plaintext, ciphertext(decrypted) and header
+func Decode(rawDoc []byte, tag string, sikeSK []byte, recipientID string, plainText proto.Message, encryptedText proto.Message, sendersBlsPK []byte) (header *Header, err error) {
+	signedEnvelope := SignedEnvelope{}
+	err = proto.Unmarshal(rawDoc, &signedEnvelope)
+	if err != nil {
+		return &Header{}, errors.New("Protobuf - Failed to unmarshal Signed Envelope")
+	}
+
+	//check the message verification if we have a key for it
+	if sendersBlsPK != nil {
+		err = Verify(signedEnvelope, sendersBlsPK)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	//Decode the  envelope
+	message := signedEnvelope.Message
+	envelope := Envelope{}
+	err = proto.Unmarshal(message, &envelope)
+	if err != nil {
+		return &Header{}, errors.New("Protobuf - Failed to unmarshal Envelope")
+	}
+	header = envelope.Header
+	header.IPFSID = tag
+	//Decode the plaintext
+	if plainText != nil {
+		err = proto.Unmarshal(envelope.Body, plainText)
+		if err != nil {
+			return &Header{}, errors.New("Protobuf - Failed to unmarshall plaintext")
+		}
+	}
+	//Decrypt the cipherText & decode into the correct object
+	if encryptedText != nil {
+		recipientList := header.Recipients
+		aesKey, err := decapsulate(recipientID, recipientList, sikeSK)
+
+		if err != nil {
+			return &Header{}, errors.Wrap(err, "Failed to Decapsulate Encrypted Text in Envelope Decode")
+		}
+
+		decryptedCipherText, err := aesDecrypt(envelope.EncryptedBody, header.EncryptedBodyIV, aesKey)
+		if err != nil {
+			return &Header{}, errors.Wrap(err, "Failed to AES Decrypt Envelope cipherText")
+		}
+		err = proto.Unmarshal(decryptedCipherText, encryptedText)
+		if err != nil {
+			return &Header{}, errors.New("Failed to unmarshall ciphertext")
+		}
+	}
+	return header, nil
+}
+
+//Encode - convert the header, secret and plaintext into a message for the wire
+//The Header can be pre-populated with any nece
+func Encode(nodeID string, plainText proto.Message, secretText proto.Message, header *Header, blsSK []byte, recipients map[string]IDDoc) (rawDoc []byte, err error) {
+	plainTextDocType, err := detectDocType(plainText)
+	if err != nil {
+		return nil, errors.New("Plaintext Document - Unknown Type")
+	}
+	encryptedTextDocType, err := detectDocType(secretText)
+	if err != nil {
+		return nil, errors.New("Encrypted Document - Unknown Type")
+	}
+	//build Header
+	header.Version = EnvelopeVersion
+	//TODO:  change datetime to real value - its 0 to create fixed IPFS refs
+	header.DateTime = 0 //time.Now().Unix()
+	header.BodyTypeCode = plainTextDocType.TypeCode
+	header.BodyVersion = plainTextDocType.Version
+	header.EncryptedBodyTypeCode = encryptedTextDocType.TypeCode
+	header.EncryptedBodyVersion = encryptedTextDocType.Version
+	//Plaintext to bytes
+	var body []byte
+	if plainText != nil {
+		body, err = proto.Marshal(plainText)
+		if err != nil {
+			return nil, errors.Wrap(err, "Failed to marshall Plaintext to Protobuf")
+		}
+	}
+	//Ciphertext
+	var cipherText []byte
+	if secretText != nil {
+		secretBody, err := proto.Marshal(secretText)
+		if err != nil {
+			return nil, err
+		}
+		var aesKey, iv []byte
+		cipherText, aesKey, iv, err = aesEncrypt(secretBody)
+
+		if err != nil {
+			return nil, err
+		}
+		header.EncryptedBodyIV = iv
+		recipientList, err := encapsulateKeyForRecipient(recipients, aesKey)
+		if err != nil {
+			return nil, err
+		}
+		header.Recipients = recipientList
+	}
+	//assemble
+	envelope := Envelope{}
+	envelope.Header = header
+	envelope.Body = body
+	envelope.EncryptedBody = cipherText
+	//sign
+	signedEnvelope, err := sign(envelope, blsSK, nodeID)
+
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to Sign Envelope")
+	}
+
+	//SignedEnvelope to bytes
+	rawDoc, err = proto.Marshal(&signedEnvelope)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to marshall Signed Envelope to Protobuf")
+	}
+	return rawDoc, nil
+}
diff --git a/libs/documents/docs.pb.go b/libs/documents/docs.pb.go
new file mode 100644
index 0000000..bb74de9
--- /dev/null
+++ b/libs/documents/docs.pb.go
@@ -0,0 +1,908 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: docs.proto
+
+package documents
+
+import (
+	fmt "fmt"
+	_ "github.com/gogo/protobuf/gogoproto"
+	proto "github.com/golang/protobuf/proto"
+	_ "github.com/mwitkow/go-proto-validators"
+	math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+type SignedEnvelope struct {
+	Signature            []byte   `protobuf:"bytes,1,opt,name=Signature,proto3" json:"Signature,omitempty"`
+	SignerCID            string   `protobuf:"bytes,2,opt,name=SignerCID,proto3" json:"SignerCID,omitempty"`
+	Message              []byte   `protobuf:"bytes,3,opt,name=Message,proto3" json:"Message,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *SignedEnvelope) Reset()         { *m = SignedEnvelope{} }
+func (m *SignedEnvelope) String() string { return proto.CompactTextString(m) }
+func (*SignedEnvelope) ProtoMessage()    {}
+func (*SignedEnvelope) Descriptor() ([]byte, []int) {
+	return fileDescriptor_2a25dace11219bce, []int{0}
+}
+
+func (m *SignedEnvelope) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_SignedEnvelope.Unmarshal(m, b)
+}
+func (m *SignedEnvelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_SignedEnvelope.Marshal(b, m, deterministic)
+}
+func (m *SignedEnvelope) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_SignedEnvelope.Merge(m, src)
+}
+func (m *SignedEnvelope) XXX_Size() int {
+	return xxx_messageInfo_SignedEnvelope.Size(m)
+}
+func (m *SignedEnvelope) XXX_DiscardUnknown() {
+	xxx_messageInfo_SignedEnvelope.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_SignedEnvelope proto.InternalMessageInfo
+
+func (m *SignedEnvelope) GetSignature() []byte {
+	if m != nil {
+		return m.Signature
+	}
+	return nil
+}
+
+func (m *SignedEnvelope) GetSignerCID() string {
+	if m != nil {
+		return m.SignerCID
+	}
+	return ""
+}
+
+func (m *SignedEnvelope) GetMessage() []byte {
+	if m != nil {
+		return m.Message
+	}
+	return nil
+}
+
+type Envelope struct {
+	Header               *Header  `protobuf:"bytes,1,opt,name=Header,proto3" json:"Header,omitempty"`
+	Body                 []byte   `protobuf:"bytes,2,opt,name=Body,proto3" json:"Body,omitempty"`
+	EncryptedBody        []byte   `protobuf:"bytes,3,opt,name=EncryptedBody,proto3" json:"EncryptedBody,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *Envelope) Reset()         { *m = Envelope{} }
+func (m *Envelope) String() string { return proto.CompactTextString(m) }
+func (*Envelope) ProtoMessage()    {}
+func (*Envelope) Descriptor() ([]byte, []int) {
+	return fileDescriptor_2a25dace11219bce, []int{1}
+}
+
+func (m *Envelope) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Envelope.Unmarshal(m, b)
+}
+func (m *Envelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Envelope.Marshal(b, m, deterministic)
+}
+func (m *Envelope) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Envelope.Merge(m, src)
+}
+func (m *Envelope) XXX_Size() int {
+	return xxx_messageInfo_Envelope.Size(m)
+}
+func (m *Envelope) XXX_DiscardUnknown() {
+	xxx_messageInfo_Envelope.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Envelope proto.InternalMessageInfo
+
+func (m *Envelope) GetHeader() *Header {
+	if m != nil {
+		return m.Header
+	}
+	return nil
+}
+
+func (m *Envelope) GetBody() []byte {
+	if m != nil {
+		return m.Body
+	}
+	return nil
+}
+
+func (m *Envelope) GetEncryptedBody() []byte {
+	if m != nil {
+		return m.EncryptedBody
+	}
+	return nil
+}
+
+type Header struct {
+	IPFSID                string       `protobuf:"bytes,1,opt,name=IPFSID,proto3" json:"IPFSID,omitempty"`
+	Version               float32      `protobuf:"fixed32,2,opt,name=Version,proto3" json:"Version,omitempty"`
+	DateTime              int64        `protobuf:"varint,3,opt,name=DateTime,proto3" json:"DateTime,omitempty"`
+	PreviousCID           string       `protobuf:"bytes,4,opt,name=PreviousCID,proto3" json:"PreviousCID,omitempty"`
+	BodyTypeCode          float32      `protobuf:"fixed32,5,opt,name=BodyTypeCode,proto3" json:"BodyTypeCode,omitempty"`
+	BodyVersion           float32      `protobuf:"fixed32,6,opt,name=BodyVersion,proto3" json:"BodyVersion,omitempty"`
+	EncryptedBodyTypeCode float32      `protobuf:"fixed32,7,opt,name=EncryptedBodyTypeCode,proto3" json:"EncryptedBodyTypeCode,omitempty"`
+	EncryptedBodyVersion  float32      `protobuf:"fixed32,8,opt,name=EncryptedBodyVersion,proto3" json:"EncryptedBodyVersion,omitempty"`
+	EncryptedBodyIV       []byte       `protobuf:"bytes,9,opt,name=EncryptedBodyIV,proto3" json:"EncryptedBodyIV,omitempty"`
+	Recipients            []*Recipient `protobuf:"bytes,10,rep,name=Recipients,proto3" json:"Recipients,omitempty"`
+	XXX_NoUnkeyedLiteral  struct{}     `json:"-"`
+	XXX_unrecognized      []byte       `json:"-"`
+	XXX_sizecache         int32        `json:"-"`
+}
+
+func (m *Header) Reset()         { *m = Header{} }
+func (m *Header) String() string { return proto.CompactTextString(m) }
+func (*Header) ProtoMessage()    {}
+func (*Header) Descriptor() ([]byte, []int) {
+	return fileDescriptor_2a25dace11219bce, []int{2}
+}
+
+func (m *Header) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Header.Unmarshal(m, b)
+}
+func (m *Header) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Header.Marshal(b, m, deterministic)
+}
+func (m *Header) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Header.Merge(m, src)
+}
+func (m *Header) XXX_Size() int {
+	return xxx_messageInfo_Header.Size(m)
+}
+func (m *Header) XXX_DiscardUnknown() {
+	xxx_messageInfo_Header.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Header proto.InternalMessageInfo
+
+func (m *Header) GetIPFSID() string {
+	if m != nil {
+		return m.IPFSID
+	}
+	return ""
+}
+
+func (m *Header) GetVersion() float32 {
+	if m != nil {
+		return m.Version
+	}
+	return 0
+}
+
+func (m *Header) GetDateTime() int64 {
+	if m != nil {
+		return m.DateTime
+	}
+	return 0
+}
+
+func (m *Header) GetPreviousCID() string {
+	if m != nil {
+		return m.PreviousCID
+	}
+	return ""
+}
+
+func (m *Header) GetBodyTypeCode() float32 {
+	if m != nil {
+		return m.BodyTypeCode
+	}
+	return 0
+}
+
+func (m *Header) GetBodyVersion() float32 {
+	if m != nil {
+		return m.BodyVersion
+	}
+	return 0
+}
+
+func (m *Header) GetEncryptedBodyTypeCode() float32 {
+	if m != nil {
+		return m.EncryptedBodyTypeCode
+	}
+	return 0
+}
+
+func (m *Header) GetEncryptedBodyVersion() float32 {
+	if m != nil {
+		return m.EncryptedBodyVersion
+	}
+	return 0
+}
+
+func (m *Header) GetEncryptedBodyIV() []byte {
+	if m != nil {
+		return m.EncryptedBodyIV
+	}
+	return nil
+}
+
+func (m *Header) GetRecipients() []*Recipient {
+	if m != nil {
+		return m.Recipients
+	}
+	return nil
+}
+
+type Recipient struct {
+	Version              float32  `protobuf:"fixed32,1,opt,name=Version,proto3" json:"Version,omitempty"`
+	CID                  string   `protobuf:"bytes,2,opt,name=CID,proto3" json:"CID,omitempty"`
+	EncapsulatedKey      []byte   `protobuf:"bytes,3,opt,name=EncapsulatedKey,proto3" json:"EncapsulatedKey,omitempty"`
+	CipherText           []byte   `protobuf:"bytes,4,opt,name=CipherText,proto3" json:"CipherText,omitempty"`
+	IV                   []byte   `protobuf:"bytes,5,opt,name=IV,proto3" json:"IV,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *Recipient) Reset()         { *m = Recipient{} }
+func (m *Recipient) String() string { return proto.CompactTextString(m) }
+func (*Recipient) ProtoMessage()    {}
+func (*Recipient) Descriptor() ([]byte, []int) {
+	return fileDescriptor_2a25dace11219bce, []int{3}
+}
+
+func (m *Recipient) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Recipient.Unmarshal(m, b)
+}
+func (m *Recipient) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Recipient.Marshal(b, m, deterministic)
+}
+func (m *Recipient) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Recipient.Merge(m, src)
+}
+func (m *Recipient) XXX_Size() int {
+	return xxx_messageInfo_Recipient.Size(m)
+}
+func (m *Recipient) XXX_DiscardUnknown() {
+	xxx_messageInfo_Recipient.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Recipient proto.InternalMessageInfo
+
+func (m *Recipient) GetVersion() float32 {
+	if m != nil {
+		return m.Version
+	}
+	return 0
+}
+
+func (m *Recipient) GetCID() string {
+	if m != nil {
+		return m.CID
+	}
+	return ""
+}
+
+func (m *Recipient) GetEncapsulatedKey() []byte {
+	if m != nil {
+		return m.EncapsulatedKey
+	}
+	return nil
+}
+
+func (m *Recipient) GetCipherText() []byte {
+	if m != nil {
+		return m.CipherText
+	}
+	return nil
+}
+
+func (m *Recipient) GetIV() []byte {
+	if m != nil {
+		return m.IV
+	}
+	return nil
+}
+
+type IDDocument struct {
+	AuthenticationReference string   `protobuf:"bytes,1,opt,name=AuthenticationReference,proto3" json:"AuthenticationReference,omitempty"`
+	BeneficiaryECPublicKey  []byte   `protobuf:"bytes,2,opt,name=BeneficiaryECPublicKey,proto3" json:"BeneficiaryECPublicKey,omitempty"`
+	SikePublicKey           []byte   `protobuf:"bytes,3,opt,name=SikePublicKey,proto3" json:"SikePublicKey,omitempty"`
+	BLSPublicKey            []byte   `protobuf:"bytes,4,opt,name=BLSPublicKey,proto3" json:"BLSPublicKey,omitempty"`
+	Timestamp               int64    `protobuf:"varint,5,opt,name=Timestamp,proto3" json:"Timestamp,omitempty"`
+	XXX_NoUnkeyedLiteral    struct{} `json:"-"`
+	XXX_unrecognized        []byte   `json:"-"`
+	XXX_sizecache           int32    `json:"-"`
+}
+
+func (m *IDDocument) Reset()         { *m = IDDocument{} }
+func (m *IDDocument) String() string { return proto.CompactTextString(m) }
+func (*IDDocument) ProtoMessage()    {}
+func (*IDDocument) Descriptor() ([]byte, []int) {
+	return fileDescriptor_2a25dace11219bce, []int{4}
+}
+
+func (m *IDDocument) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_IDDocument.Unmarshal(m, b)
+}
+func (m *IDDocument) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_IDDocument.Marshal(b, m, deterministic)
+}
+func (m *IDDocument) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_IDDocument.Merge(m, src)
+}
+func (m *IDDocument) XXX_Size() int {
+	return xxx_messageInfo_IDDocument.Size(m)
+}
+func (m *IDDocument) XXX_DiscardUnknown() {
+	xxx_messageInfo_IDDocument.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_IDDocument proto.InternalMessageInfo
+
+func (m *IDDocument) GetAuthenticationReference() string {
+	if m != nil {
+		return m.AuthenticationReference
+	}
+	return ""
+}
+
+func (m *IDDocument) GetBeneficiaryECPublicKey() []byte {
+	if m != nil {
+		return m.BeneficiaryECPublicKey
+	}
+	return nil
+}
+
+func (m *IDDocument) GetSikePublicKey() []byte {
+	if m != nil {
+		return m.SikePublicKey
+	}
+	return nil
+}
+
+func (m *IDDocument) GetBLSPublicKey() []byte {
+	if m != nil {
+		return m.BLSPublicKey
+	}
+	return nil
+}
+
+func (m *IDDocument) GetTimestamp() int64 {
+	if m != nil {
+		return m.Timestamp
+	}
+	return 0
+}
+
+type OrderDocument struct {
+	Type                 string      `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"`
+	Coin                 int64       `protobuf:"varint,2,opt,name=Coin,proto3" json:"Coin,omitempty"`
+	PrincipalCID         string      `protobuf:"bytes,3,opt,name=PrincipalCID,proto3" json:"PrincipalCID,omitempty"`
+	BeneficiaryCID       string      `protobuf:"bytes,4,opt,name=BeneficiaryCID,proto3" json:"BeneficiaryCID,omitempty"`
+	Reference            string      `protobuf:"bytes,5,opt,name=Reference,proto3" json:"Reference,omitempty"`
+	Timestamp            int64       `protobuf:"varint,6,opt,name=Timestamp,proto3" json:"Timestamp,omitempty"`
+	OrderPart2           *OrderPart2 `protobuf:"bytes,7,opt,name=OrderPart2,proto3" json:"OrderPart2,omitempty"`
+	OrderPart3           *OrderPart3 `protobuf:"bytes,8,opt,name=OrderPart3,proto3" json:"OrderPart3,omitempty"`
+	OrderPart4           *OrderPart4 `protobuf:"bytes,9,opt,name=OrderPart4,proto3" json:"OrderPart4,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}    `json:"-"`
+	XXX_unrecognized     []byte      `json:"-"`
+	XXX_sizecache        int32       `json:"-"`
+}
+
+func (m *OrderDocument) Reset()         { *m = OrderDocument{} }
+func (m *OrderDocument) String() string { return proto.CompactTextString(m) }
+func (*OrderDocument) ProtoMessage()    {}
+func (*OrderDocument) Descriptor() ([]byte, []int) {
+	return fileDescriptor_2a25dace11219bce, []int{5}
+}
+
+func (m *OrderDocument) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_OrderDocument.Unmarshal(m, b)
+}
+func (m *OrderDocument) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_OrderDocument.Marshal(b, m, deterministic)
+}
+func (m *OrderDocument) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_OrderDocument.Merge(m, src)
+}
+func (m *OrderDocument) XXX_Size() int {
+	return xxx_messageInfo_OrderDocument.Size(m)
+}
+func (m *OrderDocument) XXX_DiscardUnknown() {
+	xxx_messageInfo_OrderDocument.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_OrderDocument proto.InternalMessageInfo
+
+func (m *OrderDocument) GetType() string {
+	if m != nil {
+		return m.Type
+	}
+	return ""
+}
+
+func (m *OrderDocument) GetCoin() int64 {
+	if m != nil {
+		return m.Coin
+	}
+	return 0
+}
+
+func (m *OrderDocument) GetPrincipalCID() string {
+	if m != nil {
+		return m.PrincipalCID
+	}
+	return ""
+}
+
+func (m *OrderDocument) GetBeneficiaryCID() string {
+	if m != nil {
+		return m.BeneficiaryCID
+	}
+	return ""
+}
+
+func (m *OrderDocument) GetReference() string {
+	if m != nil {
+		return m.Reference
+	}
+	return ""
+}
+
+func (m *OrderDocument) GetTimestamp() int64 {
+	if m != nil {
+		return m.Timestamp
+	}
+	return 0
+}
+
+func (m *OrderDocument) GetOrderPart2() *OrderPart2 {
+	if m != nil {
+		return m.OrderPart2
+	}
+	return nil
+}
+
+func (m *OrderDocument) GetOrderPart3() *OrderPart3 {
+	if m != nil {
+		return m.OrderPart3
+	}
+	return nil
+}
+
+func (m *OrderDocument) GetOrderPart4() *OrderPart4 {
+	if m != nil {
+		return m.OrderPart4
+	}
+	return nil
+}
+
+type OrderPart2 struct {
+	CommitmentPublicKey  string   `protobuf:"bytes,1,opt,name=CommitmentPublicKey,proto3" json:"CommitmentPublicKey,omitempty"`
+	PreviousOrderCID     string   `protobuf:"bytes,2,opt,name=PreviousOrderCID,proto3" json:"PreviousOrderCID,omitempty"`
+	Timestamp            int64    `protobuf:"varint,3,opt,name=Timestamp,proto3" json:"Timestamp,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *OrderPart2) Reset()         { *m = OrderPart2{} }
+func (m *OrderPart2) String() string { return proto.CompactTextString(m) }
+func (*OrderPart2) ProtoMessage()    {}
+func (*OrderPart2) Descriptor() ([]byte, []int) {
+	return fileDescriptor_2a25dace11219bce, []int{6}
+}
+
+func (m *OrderPart2) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_OrderPart2.Unmarshal(m, b)
+}
+func (m *OrderPart2) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_OrderPart2.Marshal(b, m, deterministic)
+}
+func (m *OrderPart2) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_OrderPart2.Merge(m, src)
+}
+func (m *OrderPart2) XXX_Size() int {
+	return xxx_messageInfo_OrderPart2.Size(m)
+}
+func (m *OrderPart2) XXX_DiscardUnknown() {
+	xxx_messageInfo_OrderPart2.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_OrderPart2 proto.InternalMessageInfo
+
+func (m *OrderPart2) GetCommitmentPublicKey() string {
+	if m != nil {
+		return m.CommitmentPublicKey
+	}
+	return ""
+}
+
+func (m *OrderPart2) GetPreviousOrderCID() string {
+	if m != nil {
+		return m.PreviousOrderCID
+	}
+	return ""
+}
+
+func (m *OrderPart2) GetTimestamp() int64 {
+	if m != nil {
+		return m.Timestamp
+	}
+	return 0
+}
+
+type OrderPart3 struct {
+	Redemption               string   `protobuf:"bytes,1,opt,name=Redemption,proto3" json:"Redemption,omitempty"`
+	PreviousOrderCID         string   `protobuf:"bytes,2,opt,name=PreviousOrderCID,proto3" json:"PreviousOrderCID,omitempty"`
+	BeneficiaryEncryptedData []byte   `protobuf:"bytes,3,opt,name=BeneficiaryEncryptedData,proto3" json:"BeneficiaryEncryptedData,omitempty"`
+	Timestamp                int64    `protobuf:"varint,4,opt,name=Timestamp,proto3" json:"Timestamp,omitempty"`
+	XXX_NoUnkeyedLiteral     struct{} `json:"-"`
+	XXX_unrecognized         []byte   `json:"-"`
+	XXX_sizecache            int32    `json:"-"`
+}
+
+func (m *OrderPart3) Reset()         { *m = OrderPart3{} }
+func (m *OrderPart3) String() string { return proto.CompactTextString(m) }
+func (*OrderPart3) ProtoMessage()    {}
+func (*OrderPart3) Descriptor() ([]byte, []int) {
+	return fileDescriptor_2a25dace11219bce, []int{7}
+}
+
+func (m *OrderPart3) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_OrderPart3.Unmarshal(m, b)
+}
+func (m *OrderPart3) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_OrderPart3.Marshal(b, m, deterministic)
+}
+func (m *OrderPart3) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_OrderPart3.Merge(m, src)
+}
+func (m *OrderPart3) XXX_Size() int {
+	return xxx_messageInfo_OrderPart3.Size(m)
+}
+func (m *OrderPart3) XXX_DiscardUnknown() {
+	xxx_messageInfo_OrderPart3.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_OrderPart3 proto.InternalMessageInfo
+
+func (m *OrderPart3) GetRedemption() string {
+	if m != nil {
+		return m.Redemption
+	}
+	return ""
+}
+
+func (m *OrderPart3) GetPreviousOrderCID() string {
+	if m != nil {
+		return m.PreviousOrderCID
+	}
+	return ""
+}
+
+func (m *OrderPart3) GetBeneficiaryEncryptedData() []byte {
+	if m != nil {
+		return m.BeneficiaryEncryptedData
+	}
+	return nil
+}
+
+func (m *OrderPart3) GetTimestamp() int64 {
+	if m != nil {
+		return m.Timestamp
+	}
+	return 0
+}
+
+type OrderPart4 struct {
+	Secret               string   `protobuf:"bytes,1,opt,name=Secret,proto3" json:"Secret,omitempty"`
+	PreviousOrderCID     string   `protobuf:"bytes,2,opt,name=PreviousOrderCID,proto3" json:"PreviousOrderCID,omitempty"`
+	Timestamp            int64    `protobuf:"varint,3,opt,name=Timestamp,proto3" json:"Timestamp,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *OrderPart4) Reset()         { *m = OrderPart4{} }
+func (m *OrderPart4) String() string { return proto.CompactTextString(m) }
+func (*OrderPart4) ProtoMessage()    {}
+func (*OrderPart4) Descriptor() ([]byte, []int) {
+	return fileDescriptor_2a25dace11219bce, []int{8}
+}
+
+func (m *OrderPart4) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_OrderPart4.Unmarshal(m, b)
+}
+func (m *OrderPart4) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_OrderPart4.Marshal(b, m, deterministic)
+}
+func (m *OrderPart4) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_OrderPart4.Merge(m, src)
+}
+func (m *OrderPart4) XXX_Size() int {
+	return xxx_messageInfo_OrderPart4.Size(m)
+}
+func (m *OrderPart4) XXX_DiscardUnknown() {
+	xxx_messageInfo_OrderPart4.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_OrderPart4 proto.InternalMessageInfo
+
+func (m *OrderPart4) GetSecret() string {
+	if m != nil {
+		return m.Secret
+	}
+	return ""
+}
+
+func (m *OrderPart4) GetPreviousOrderCID() string {
+	if m != nil {
+		return m.PreviousOrderCID
+	}
+	return ""
+}
+
+func (m *OrderPart4) GetTimestamp() int64 {
+	if m != nil {
+		return m.Timestamp
+	}
+	return 0
+}
+
+type Policy struct {
+	Version              float32  `protobuf:"fixed32,1,opt,name=Version,proto3" json:"Version,omitempty"`
+	Name                 string   `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *Policy) Reset()         { *m = Policy{} }
+func (m *Policy) String() string { return proto.CompactTextString(m) }
+func (*Policy) ProtoMessage()    {}
+func (*Policy) Descriptor() ([]byte, []int) {
+	return fileDescriptor_2a25dace11219bce, []int{9}
+}
+
+func (m *Policy) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Policy.Unmarshal(m, b)
+}
+func (m *Policy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Policy.Marshal(b, m, deterministic)
+}
+func (m *Policy) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Policy.Merge(m, src)
+}
+func (m *Policy) XXX_Size() int {
+	return xxx_messageInfo_Policy.Size(m)
+}
+func (m *Policy) XXX_DiscardUnknown() {
+	xxx_messageInfo_Policy.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Policy proto.InternalMessageInfo
+
+func (m *Policy) GetVersion() float32 {
+	if m != nil {
+		return m.Version
+	}
+	return 0
+}
+
+func (m *Policy) GetName() string {
+	if m != nil {
+		return m.Name
+	}
+	return ""
+}
+
+type PlainTestMessage1 struct {
+	Nametest1            string   `protobuf:"bytes,1,opt,name=Nametest1,proto3" json:"Nametest1,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *PlainTestMessage1) Reset()         { *m = PlainTestMessage1{} }
+func (m *PlainTestMessage1) String() string { return proto.CompactTextString(m) }
+func (*PlainTestMessage1) ProtoMessage()    {}
+func (*PlainTestMessage1) Descriptor() ([]byte, []int) {
+	return fileDescriptor_2a25dace11219bce, []int{10}
+}
+
+func (m *PlainTestMessage1) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_PlainTestMessage1.Unmarshal(m, b)
+}
+func (m *PlainTestMessage1) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_PlainTestMessage1.Marshal(b, m, deterministic)
+}
+func (m *PlainTestMessage1) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_PlainTestMessage1.Merge(m, src)
+}
+func (m *PlainTestMessage1) XXX_Size() int {
+	return xxx_messageInfo_PlainTestMessage1.Size(m)
+}
+func (m *PlainTestMessage1) XXX_DiscardUnknown() {
+	xxx_messageInfo_PlainTestMessage1.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_PlainTestMessage1 proto.InternalMessageInfo
+
+func (m *PlainTestMessage1) GetNametest1() string {
+	if m != nil {
+		return m.Nametest1
+	}
+	return ""
+}
+
+type EncryptTestMessage1 struct {
+	Nametest2            string   `protobuf:"bytes,1,opt,name=Nametest2,proto3" json:"Nametest2,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *EncryptTestMessage1) Reset()         { *m = EncryptTestMessage1{} }
+func (m *EncryptTestMessage1) String() string { return proto.CompactTextString(m) }
+func (*EncryptTestMessage1) ProtoMessage()    {}
+func (*EncryptTestMessage1) Descriptor() ([]byte, []int) {
+	return fileDescriptor_2a25dace11219bce, []int{11}
+}
+
+func (m *EncryptTestMessage1) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_EncryptTestMessage1.Unmarshal(m, b)
+}
+func (m *EncryptTestMessage1) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_EncryptTestMessage1.Marshal(b, m, deterministic)
+}
+func (m *EncryptTestMessage1) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_EncryptTestMessage1.Merge(m, src)
+}
+func (m *EncryptTestMessage1) XXX_Size() int {
+	return xxx_messageInfo_EncryptTestMessage1.Size(m)
+}
+func (m *EncryptTestMessage1) XXX_DiscardUnknown() {
+	xxx_messageInfo_EncryptTestMessage1.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_EncryptTestMessage1 proto.InternalMessageInfo
+
+func (m *EncryptTestMessage1) GetNametest2() string {
+	if m != nil {
+		return m.Nametest2
+	}
+	return ""
+}
+
+type SimpleString struct {
+	Content              string   `protobuf:"bytes,1,opt,name=Content,proto3" json:"Content,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *SimpleString) Reset()         { *m = SimpleString{} }
+func (m *SimpleString) String() string { return proto.CompactTextString(m) }
+func (*SimpleString) ProtoMessage()    {}
+func (*SimpleString) Descriptor() ([]byte, []int) {
+	return fileDescriptor_2a25dace11219bce, []int{12}
+}
+
+func (m *SimpleString) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_SimpleString.Unmarshal(m, b)
+}
+func (m *SimpleString) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_SimpleString.Marshal(b, m, deterministic)
+}
+func (m *SimpleString) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_SimpleString.Merge(m, src)
+}
+func (m *SimpleString) XXX_Size() int {
+	return xxx_messageInfo_SimpleString.Size(m)
+}
+func (m *SimpleString) XXX_DiscardUnknown() {
+	xxx_messageInfo_SimpleString.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_SimpleString proto.InternalMessageInfo
+
+func (m *SimpleString) GetContent() string {
+	if m != nil {
+		return m.Content
+	}
+	return ""
+}
+
+func init() {
+	proto.RegisterType((*SignedEnvelope)(nil), "documents.SignedEnvelope")
+	proto.RegisterType((*Envelope)(nil), "documents.Envelope")
+	proto.RegisterType((*Header)(nil), "documents.Header")
+	proto.RegisterType((*Recipient)(nil), "documents.Recipient")
+	proto.RegisterType((*IDDocument)(nil), "documents.IDDocument")
+	proto.RegisterType((*OrderDocument)(nil), "documents.OrderDocument")
+	proto.RegisterType((*OrderPart2)(nil), "documents.OrderPart2")
+	proto.RegisterType((*OrderPart3)(nil), "documents.OrderPart3")
+	proto.RegisterType((*OrderPart4)(nil), "documents.OrderPart4")
+	proto.RegisterType((*Policy)(nil), "documents.Policy")
+	proto.RegisterType((*PlainTestMessage1)(nil), "documents.PlainTestMessage1")
+	proto.RegisterType((*EncryptTestMessage1)(nil), "documents.EncryptTestMessage1")
+	proto.RegisterType((*SimpleString)(nil), "documents.SimpleString")
+}
+
+func init() { proto.RegisterFile("docs.proto", fileDescriptor_2a25dace11219bce) }
+
+var fileDescriptor_2a25dace11219bce = []byte{
+	// 956 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x56, 0x4f, 0x6f, 0x1b, 0x45,
+	0x14, 0xd7, 0xda, 0x8e, 0x13, 0xbf, 0xb8, 0x21, 0x9d, 0x26, 0xed, 0xaa, 0x20, 0x12, 0xad, 0x22,
+	0x64, 0x24, 0xe2, 0x10, 0xdb, 0x8d, 0x20, 0x42, 0x42, 0xd8, 0x0e, 0x60, 0xf1, 0xcf, 0x8c, 0xa3,
+	0x08, 0xa9, 0x6a, 0xa5, 0xc9, 0xee, 0x8b, 0x33, 0xaa, 0x77, 0x67, 0xb5, 0x3b, 0x4e, 0xb1, 0x80,
+	0x33, 0x07, 0x8e, 0x9c, 0xb9, 0x20, 0xf5, 0xca, 0x11, 0xbe, 0x00, 0x47, 0xbe, 0x43, 0x44, 0x0e,
+	0x20, 0xbe, 0x01, 0x37, 0xd0, 0xcc, 0xfe, 0x0f, 0x71, 0x93, 0x03, 0x52, 0x7d, 0x9a, 0xf7, 0x7e,
+	0xef, 0xf7, 0xe6, 0xfd, 0x1d, 0x2f, 0x80, 0x23, 0xec, 0xb0, 0xe9, 0x07, 0x42, 0x0a, 0x52, 0x73,
+	0x84, 0x3d, 0x75, 0xd1, 0x93, 0xe1, 0xfd, 0xbd, 0x31, 0x97, 0xa7, 0xd3, 0xe3, 0xa6, 0x2d, 0xdc,
+	0x1d, 0xf7, 0x29, 0x97, 0x4f, 0xc4, 0xd3, 0x9d, 0xb1, 0xd8, 0xd6, 0x76, 0xdb, 0x67, 0x6c, 0xc2,
+	0x1d, 0x26, 0x45, 0x10, 0xee, 0xa4, 0xc7, 0xc8, 0xc5, 0xfd, 0xed, 0x1c, 0x6f, 0x2c, 0xc6, 0x62,
+	0x47, 0xab, 0x8f, 0xa7, 0x27, 0x5a, 0xd2, 0x82, 0x3e, 0x45, 0xe6, 0xd6, 0x77, 0x06, 0xac, 0x8c,
+	0xf8, 0xd8, 0x43, 0xe7, 0xc0, 0x3b, 0xc3, 0x89, 0xf0, 0x91, 0x6c, 0x41, 0x4d, 0x69, 0x98, 0x9c,
+	0x06, 0x68, 0x1a, 0x9b, 0x46, 0xa3, 0xde, 0xad, 0x5e, 0x9c, 0x6f, 0x94, 0xfc, 0x35, 0x9a, 0x01,
+	0xe4, 0xed, 0xc8, 0x0a, 0x83, 0xde, 0xa0, 0x6f, 0x96, 0x36, 0x8d, 0x46, 0xad, 0xfb, 0xf2, 0xc5,
+	0xf9, 0xc6, 0x3d, 0x58, 0x7f, 0xfc, 0xf9, 0xc3, 0x87, 0xfb, 0x6c, 0xe2, 0x4d, 0xdd, 0xfd, 0x47,
+	0x8f, 0xbe, 0xea, 0x3c, 0xf8, 0x66, 0xeb, 0xeb, 0xc7, 0x5b, 0x34, 0xb3, 0x26, 0x26, 0x2c, 0x7e,
+	0x82, 0x61, 0xc8, 0xc6, 0x68, 0x96, 0x95, 0x7b, 0x9a, 0x88, 0x96, 0x80, 0xa5, 0x34, 0x8c, 0xd7,
+	0xa1, 0xfa, 0x21, 0x32, 0x07, 0x03, 0x1d, 0xc3, 0x72, 0xeb, 0x76, 0x33, 0x2d, 0x4e, 0x33, 0x02,
+	0x68, 0x6c, 0x40, 0x08, 0x54, 0xba, 0xc2, 0x99, 0xe9, 0x30, 0xea, 0x54, 0x9f, 0xc9, 0x16, 0xdc,
+	0x3a, 0xf0, 0xec, 0x60, 0xe6, 0x4b, 0x74, 0x34, 0x18, 0x5d, 0x55, 0x54, 0x5a, 0x3f, 0x96, 0x93,
+	0x5b, 0xc8, 0x5d, 0xa8, 0x0e, 0x86, 0xef, 0x8f, 0x06, 0x7d, 0x7d, 0x5f, 0x8d, 0xc6, 0x92, 0x8a,
+	0xf6, 0x08, 0x83, 0x90, 0x0b, 0x4f, 0xfb, 0x2f, 0xd1, 0x44, 0x24, 0x6f, 0xc0, 0x52, 0x9f, 0x49,
+	0x3c, 0xe4, 0x6e, 0x94, 0x48, 0xb9, 0xbb, 0x7a, 0x71, 0xbe, 0x51, 0x5f, 0x7d, 0xf6, 0xed, 0x1f,
+	0x7f, 0x2d, 0x98, 0xcf, 0x7e, 0xfd, 0xf9, 0xfb, 0x19, 0x4d, 0x2d, 0xc8, 0x26, 0x2c, 0x0f, 0x03,
+	0x3c, 0xe3, 0x62, 0x1a, 0xaa, 0x92, 0x55, 0xf4, 0x25, 0x79, 0x15, 0xb1, 0xa0, 0xae, 0x82, 0x3a,
+	0x9c, 0xf9, 0xd8, 0x13, 0x0e, 0x9a, 0x0b, 0xfa, 0xba, 0x82, 0x4e, 0x79, 0x51, 0x72, 0x12, 0x51,
+	0x55, 0x9b, 0xe4, 0x55, 0xa4, 0x03, 0xeb, 0x85, 0x1c, 0x53, 0x77, 0x8b, 0xda, 0xf6, 0x6a, 0x90,
+	0xb4, 0x60, 0xad, 0x00, 0x24, 0x17, 0x2c, 0x69, 0xd2, 0x95, 0x18, 0x69, 0xc0, 0x4b, 0x05, 0xfd,
+	0xe0, 0xc8, 0xac, 0xe9, 0x22, 0x5f, 0x56, 0x93, 0x77, 0x00, 0x28, 0xda, 0xdc, 0xe7, 0xaa, 0x7b,
+	0x26, 0x6c, 0x96, 0x1b, 0xcb, 0xad, 0xb5, 0x5c, 0x3f, 0x53, 0x30, 0x9a, 0xb4, 0xd3, 0x35, 0x9a,
+	0xb3, 0xb7, 0x7e, 0x32, 0xa0, 0x96, 0x8a, 0xf9, 0x7e, 0x18, 0xc5, 0x7e, 0x6c, 0x43, 0xf9, 0x86,
+	0xc3, 0xa8, 0xec, 0xe2, 0xf0, 0x99, 0x1f, 0x4e, 0x27, 0x4c, 0xa2, 0xf3, 0x11, 0x26, 0x33, 0x72,
+	0x59, 0x4d, 0x5e, 0x05, 0xe8, 0x71, 0xff, 0x14, 0x83, 0x43, 0xfc, 0x52, 0xea, 0xce, 0xd5, 0x69,
+	0x4e, 0x43, 0x56, 0xa0, 0x34, 0x38, 0xd2, 0xed, 0xaa, 0xd3, 0xd2, 0xe0, 0xc8, 0xfa, 0xdb, 0x00,
+	0x18, 0xf4, 0xfb, 0x71, 0x7a, 0xe4, 0x2d, 0xb8, 0xf7, 0xde, 0x54, 0x9e, 0xa2, 0x27, 0xb9, 0xcd,
+	0x24, 0x17, 0x1e, 0xc5, 0x13, 0x0c, 0xd0, 0xb3, 0x31, 0x1e, 0xb5, 0x79, 0x30, 0xd9, 0x83, 0xbb,
+	0x5d, 0xf4, 0xf0, 0x84, 0xdb, 0x9c, 0x05, 0xb3, 0x83, 0xde, 0x70, 0x7a, 0x3c, 0xe1, 0xb6, 0x8a,
+	0x34, 0x1a, 0xf5, 0x39, 0xa8, 0x1a, 0xfe, 0x11, 0x7f, 0x82, 0x99, 0x79, 0x3c, 0xfc, 0x05, 0xa5,
+	0x9e, 0xb7, 0x8f, 0x47, 0x99, 0x51, 0x94, 0x58, 0x41, 0x47, 0x9a, 0x50, 0x53, 0xd3, 0x1b, 0x4a,
+	0xe6, 0xfa, 0x3a, 0xc3, 0xab, 0x86, 0x3c, 0x33, 0xb1, 0x7e, 0x2b, 0xc3, 0xad, 0xcf, 0x02, 0x07,
+	0x83, 0x34, 0x7b, 0x02, 0x15, 0x35, 0x65, 0x71, 0xaa, 0xfa, 0x4c, 0x5e, 0x83, 0x4a, 0x4f, 0xf0,
+	0x68, 0xa1, 0xca, 0x5d, 0x72, 0x71, 0xbe, 0xb1, 0xb2, 0xfa, 0x4f, 0xf2, 0x33, 0xcc, 0x3f, 0x17,
+	0xa9, 0xc6, 0xc9, 0xbb, 0x50, 0x1f, 0x06, 0xdc, 0xb3, 0xb9, 0xcf, 0x26, 0xaa, 0xb5, 0xe5, 0xeb,
+	0x5b, 0x5b, 0x20, 0x90, 0x1e, 0xac, 0xe4, 0x4a, 0x94, 0xee, 0xdd, 0xf3, 0x5d, 0x5c, 0xa2, 0xa8,
+	0x07, 0x31, 0xeb, 0xd8, 0x82, 0xe6, 0xeb, 0x31, 0xfd, 0xc2, 0xa0, 0x19, 0x50, 0xac, 0x54, 0xf5,
+	0xda, 0x4a, 0x91, 0x07, 0x00, 0xba, 0x50, 0x43, 0x16, 0xc8, 0x96, 0x5e, 0xce, 0xe5, 0xd6, 0x7a,
+	0x6e, 0x27, 0x32, 0x90, 0xe6, 0x0c, 0x0b, 0xb4, 0xb6, 0x5e, 0xcf, 0x39, 0xb4, 0x76, 0x8e, 0xd6,
+	0x2e, 0xd0, 0x3a, 0x7a, 0x4d, 0xe7, 0xd0, 0x3a, 0x39, 0x5a, 0xc7, 0xfa, 0xc5, 0xc8, 0x47, 0x49,
+	0xde, 0x84, 0x3b, 0x3d, 0xe1, 0xba, 0x5c, 0x2a, 0x52, 0x36, 0x38, 0x51, 0x6b, 0xaf, 0x82, 0xc8,
+	0x07, 0xb0, 0x9a, 0x3c, 0x71, 0xda, 0xcf, 0x0d, 0x17, 0xf4, 0x3f, 0xa4, 0x62, 0x79, 0xcb, 0xd7,
+	0x0f, 0xe2, 0xef, 0xf9, 0xc8, 0xdb, 0x6a, 0x85, 0x29, 0x3a, 0xe8, 0xfa, 0x32, 0x79, 0x38, 0x6a,
+	0x34, 0xa7, 0xf9, 0xff, 0xe2, 0xdc, 0x07, 0x33, 0xbf, 0x94, 0xc9, 0x43, 0xd8, 0x67, 0x92, 0xc5,
+	0x5b, 0x38, 0x17, 0x2f, 0xe6, 0x58, 0xb9, 0x3e, 0xc7, 0x1f, 0xf2, 0x39, 0x76, 0xd4, 0x3f, 0xd8,
+	0x08, 0xed, 0x00, 0x65, 0xf2, 0x0f, 0x16, 0x49, 0x2f, 0xae, 0x07, 0x7b, 0x50, 0x1d, 0x8a, 0x09,
+	0xb7, 0x67, 0xcf, 0x79, 0xb4, 0x09, 0x54, 0x3e, 0x65, 0x2e, 0x46, 0x01, 0x51, 0x7d, 0xb6, 0x76,
+	0xe1, 0xf6, 0x70, 0xc2, 0xb8, 0x77, 0x88, 0xa1, 0x8c, 0x3f, 0x0d, 0x76, 0xc9, 0x2b, 0x50, 0x53,
+	0xa0, 0xc4, 0x50, 0xee, 0xc6, 0x09, 0x66, 0x0a, 0xab, 0x0d, 0x77, 0xe2, 0x5a, 0xce, 0x23, 0xb5,
+	0x2e, 0x93, 0x5a, 0x56, 0x03, 0xea, 0x23, 0xee, 0xfa, 0x13, 0x1c, 0xc9, 0x80, 0x7b, 0x63, 0x15,
+	0x65, 0x4f, 0x78, 0x12, 0xbd, 0xa4, 0x82, 0x89, 0x78, 0x5c, 0xd5, 0x5f, 0x4b, 0xed, 0x7f, 0x03,
+	0x00, 0x00, 0xff, 0xff, 0x54, 0x80, 0x91, 0x77, 0xad, 0x09, 0x00, 0x00,
+}
diff --git a/libs/documents/docs.proto b/libs/documents/docs.proto
new file mode 100644
index 0000000..737d112
--- /dev/null
+++ b/libs/documents/docs.proto
@@ -0,0 +1,136 @@
+/*
+// Build with (note the location of protobuf & gohome 
+// Also you cant use ~ to refer to home dir
+
+  protoc \
+  --proto_path=$HOME/go/src \
+  --proto_path=$HOME/go/src/github.com/gogo/protobuf/ \
+  --proto_path=. \
+  --go_out=. \
+  --govalidators_out=. \
+  *.proto
+
+Validation performed using
+https://github.com/mwitkow/go-proto-validators
+
+
+Objective:
+To Create an extensible document structure that
+
+1) Entire document is signed by the author, this signature can be verified.
+2) It contains a Plaintext Message - which anyone can read
+3) It contains multiple Encrypted Messages
+    a) Each encrypted message can be decrytpted by different recipients.
+    b) The recipients of each encrypted message are detail as Recipients in the header
+*/
+
+
+syntax="proto3";
+
+package documents;
+import "github.com/mwitkow/go-proto-validators/validator.proto";
+import "github.com/gogo/protobuf/gogoproto/gogo.proto";
+//The Encrypted Envelope
+
+message SignedEnvelope {
+    bytes Signature = 1 [(validator.field) = { length_gt: 20}];
+    string SignerCID = 2 [(validator.field) = {regex: "^Q[[:alnum:]]{45}$|^$"}];
+    bytes Message   = 3;
+}
+
+message Envelope {
+   Header Header       = 1;
+   bytes Body          = 2;
+   bytes EncryptedBody = 3;
+} 
+
+message Header {
+    string IPFSID                  = 1; //this is always blank in a live document, the ID of the IPFS file is insert after decoding 
+    float Version                  = 2;
+    int64 DateTime                 = 3 [(validator.field) = {int_gt:1564050341,int_lt:32521429541}];
+    string PreviousCID             = 4;
+    float BodyTypeCode             = 5;
+    float BodyVersion              = 6;
+    float EncryptedBodyTypeCode    = 7;
+    float EncryptedBodyVersion     = 8;
+    bytes EncryptedBodyIV          = 9;
+    repeated Recipient Recipients  = 10 [(validator.field) = { repeated_count_max: 20}];
+}
+
+message Recipient {
+    float Version         = 1;
+    string CID            = 2 [(validator.field) = {regex: "^Q[[:alnum:]]{45}$|^$"}];
+    bytes EncapsulatedKey = 3;
+    bytes CipherText      = 4;
+    bytes IV              = 5;
+}
+
+
+message IDDocument {
+    string AuthenticationReference = 1;
+    bytes BeneficiaryECPublicKey   = 2;
+    bytes SikePublicKey            = 3;
+    bytes BLSPublicKey             = 4;
+    int64 Timestamp                = 5 [(validator.field) = {int_gt:1564050341,int_lt:32521429541}];
+}
+
+
+message OrderDocument {
+    string Type              = 1; //This can be used to extend the types of things that an order can do.
+    int64 Coin               = 2 [(validator.field) = {int_gt: -1, int_lt: 999}];
+    string PrincipalCID      = 3 [(validator.field) = {regex: "^Q[[:alnum:]]{45}$|^$"}];  //empty if ok
+    string BeneficiaryCID    = 4 [(validator.field) = {regex: "^Q[[:alnum:]]{45}$|^$"}];  //empty if ok
+    string Reference         = 5 [(validator.field) = {string_not_empty:true}]; //an id for this order e.g. walletID
+    int64 Timestamp          = 6 [(validator.field) = {int_gt:1564050341,int_lt:32521429541}];
+    OrderPart2 OrderPart2    = 7;
+    OrderPart3 OrderPart3    = 8;
+    OrderPart4 OrderPart4    = 9;
+}
+
+message OrderPart2 {
+    string CommitmentPublicKey = 1;
+    string PreviousOrderCID    = 2 [(validator.field) = {regex: "^Q[[:alnum:]]{45}$|^$"}];
+    int64 Timestamp            = 3 [(validator.field) = {int_gt:1564050341,int_lt:32521429541}];
+}
+
+message OrderPart3 {
+    string Redemption              = 1;
+    string PreviousOrderCID        = 2 [(validator.field) = {regex: "^Q[[:alnum:]]{45}$|^$"}];
+    bytes BeneficiaryEncryptedData = 3;
+    int64 Timestamp                = 4 [(validator.field) = {int_gt:1564050341,int_lt:32521429541}];
+}
+
+message OrderPart4 {
+    string Secret           = 1;
+    string PreviousOrderCID = 2 [(validator.field) = {regex: "^Q[[:alnum:]]{45}$|^$"}];
+    int64 Timestamp         = 3 [(validator.field) = {int_gt:1564050341,int_lt:32521429541}];
+}
+
+
+message Policy{
+    float Version = 1;
+    string Name   = 2; 
+}
+
+message PlainTestMessage1 {
+    string Nametest1 = 1;
+}
+
+message EncryptTestMessage1 {
+    string Nametest2 = 1;
+}
+
+message SimpleString {
+    string Content = 1;
+}
+
+
+//Version everything!!!!
+//Mark SIKE keys with a version
+
+
+
+// rtn = makeEnv(char* message, char* SIKEpk[],  char* encMessage, char* encapsulatedKey[], char* encapsulationVersion
+// rtn = decodeEnv(char* encapsulationVersion, char* encapsulatedKey,  char* SIKEprivKey)
+// rtn = sign( char* BLSsk, char* signature) 
+// rtn = verify(char* signature, char* message)  
diff --git a/libs/documents/docs.validator.pb.go b/libs/documents/docs.validator.pb.go
new file mode 100644
index 0000000..905146b
--- /dev/null
+++ b/libs/documents/docs.validator.pb.go
@@ -0,0 +1,176 @@
+// Code generated by protoc-gen-gogo. DO NOT EDIT.
+// source: docs.proto
+
+package documents
+
+import (
+	fmt "fmt"
+	_ "github.com/gogo/protobuf/gogoproto"
+	proto "github.com/golang/protobuf/proto"
+	_ "github.com/mwitkow/go-proto-validators"
+	github_com_mwitkow_go_proto_validators "github.com/mwitkow/go-proto-validators"
+	math "math"
+	regexp "regexp"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+var _regex_SignedEnvelope_SignerCID = regexp.MustCompile(`^Q[[:alnum:]]{45}$|^$`)
+
+func (this *SignedEnvelope) Validate() error {
+	if !(len(this.Signature) > 20) {
+		return github_com_mwitkow_go_proto_validators.FieldError("Signature", fmt.Errorf(`value '%v' must have a length greater than '20'`, this.Signature))
+	}
+	if !_regex_SignedEnvelope_SignerCID.MatchString(this.SignerCID) {
+		return github_com_mwitkow_go_proto_validators.FieldError("SignerCID", fmt.Errorf(`value '%v' must be a string conforming to regex "^Q[[:alnum:]]{45}$|^$"`, this.SignerCID))
+	}
+	return nil
+}
+func (this *Envelope) Validate() error {
+	if this.Header != nil {
+		if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Header); err != nil {
+			return github_com_mwitkow_go_proto_validators.FieldError("Header", err)
+		}
+	}
+	return nil
+}
+func (this *Header) Validate() error {
+	if !(this.DateTime > 1564050341) {
+		return github_com_mwitkow_go_proto_validators.FieldError("DateTime", fmt.Errorf(`value '%v' must be greater than '1564050341'`, this.DateTime))
+	}
+	if !(this.DateTime < 32521429541) {
+		return github_com_mwitkow_go_proto_validators.FieldError("DateTime", fmt.Errorf(`value '%v' must be less than '32521429541'`, this.DateTime))
+	}
+	if len(this.Recipients) > 20 {
+		return github_com_mwitkow_go_proto_validators.FieldError("Recipients", fmt.Errorf(`value '%v' must contain at most 20 elements`, this.Recipients))
+	}
+	for _, item := range this.Recipients {
+		if item != nil {
+			if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
+				return github_com_mwitkow_go_proto_validators.FieldError("Recipients", err)
+			}
+		}
+	}
+	return nil
+}
+
+var _regex_Recipient_CID = regexp.MustCompile(`^Q[[:alnum:]]{45}$|^$`)
+
+func (this *Recipient) Validate() error {
+	if !_regex_Recipient_CID.MatchString(this.CID) {
+		return github_com_mwitkow_go_proto_validators.FieldError("CID", fmt.Errorf(`value '%v' must be a string conforming to regex "^Q[[:alnum:]]{45}$|^$"`, this.CID))
+	}
+	return nil
+}
+func (this *IDDocument) Validate() error {
+	if !(this.Timestamp > 1564050341) {
+		return github_com_mwitkow_go_proto_validators.FieldError("Timestamp", fmt.Errorf(`value '%v' must be greater than '1564050341'`, this.Timestamp))
+	}
+	if !(this.Timestamp < 32521429541) {
+		return github_com_mwitkow_go_proto_validators.FieldError("Timestamp", fmt.Errorf(`value '%v' must be less than '32521429541'`, this.Timestamp))
+	}
+	return nil
+}
+
+var _regex_OrderDocument_PrincipalCID = regexp.MustCompile(`^Q[[:alnum:]]{45}$|^$`)
+var _regex_OrderDocument_BeneficiaryCID = regexp.MustCompile(`^Q[[:alnum:]]{45}$|^$`)
+
+func (this *OrderDocument) Validate() error {
+	if !(this.Coin > -1) {
+		return github_com_mwitkow_go_proto_validators.FieldError("Coin", fmt.Errorf(`value '%v' must be greater than '-1'`, this.Coin))
+	}
+	if !(this.Coin < 999) {
+		return github_com_mwitkow_go_proto_validators.FieldError("Coin", fmt.Errorf(`value '%v' must be less than '999'`, this.Coin))
+	}
+	if !_regex_OrderDocument_PrincipalCID.MatchString(this.PrincipalCID) {
+		return github_com_mwitkow_go_proto_validators.FieldError("PrincipalCID", fmt.Errorf(`value '%v' must be a string conforming to regex "^Q[[:alnum:]]{45}$|^$"`, this.PrincipalCID))
+	}
+	if !_regex_OrderDocument_BeneficiaryCID.MatchString(this.BeneficiaryCID) {
+		return github_com_mwitkow_go_proto_validators.FieldError("BeneficiaryCID", fmt.Errorf(`value '%v' must be a string conforming to regex "^Q[[:alnum:]]{45}$|^$"`, this.BeneficiaryCID))
+	}
+	if this.Reference == "" {
+		return github_com_mwitkow_go_proto_validators.FieldError("Reference", fmt.Errorf(`value '%v' must not be an empty string`, this.Reference))
+	}
+	if !(this.Timestamp > 1564050341) {
+		return github_com_mwitkow_go_proto_validators.FieldError("Timestamp", fmt.Errorf(`value '%v' must be greater than '1564050341'`, this.Timestamp))
+	}
+	if !(this.Timestamp < 32521429541) {
+		return github_com_mwitkow_go_proto_validators.FieldError("Timestamp", fmt.Errorf(`value '%v' must be less than '32521429541'`, this.Timestamp))
+	}
+	if this.OrderPart2 != nil {
+		if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.OrderPart2); err != nil {
+			return github_com_mwitkow_go_proto_validators.FieldError("OrderPart2", err)
+		}
+	}
+	if this.OrderPart3 != nil {
+		if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.OrderPart3); err != nil {
+			return github_com_mwitkow_go_proto_validators.FieldError("OrderPart3", err)
+		}
+	}
+	if this.OrderPart4 != nil {
+		if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.OrderPart4); err != nil {
+			return github_com_mwitkow_go_proto_validators.FieldError("OrderPart4", err)
+		}
+	}
+	return nil
+}
+
+var _regex_OrderPart2_PreviousOrderCID = regexp.MustCompile(`^Q[[:alnum:]]{45}$|^$`)
+
+func (this *OrderPart2) Validate() error {
+	if !_regex_OrderPart2_PreviousOrderCID.MatchString(this.PreviousOrderCID) {
+		return github_com_mwitkow_go_proto_validators.FieldError("PreviousOrderCID", fmt.Errorf(`value '%v' must be a string conforming to regex "^Q[[:alnum:]]{45}$|^$"`, this.PreviousOrderCID))
+	}
+	if !(this.Timestamp > 1564050341) {
+		return github_com_mwitkow_go_proto_validators.FieldError("Timestamp", fmt.Errorf(`value '%v' must be greater than '1564050341'`, this.Timestamp))
+	}
+	if !(this.Timestamp < 32521429541) {
+		return github_com_mwitkow_go_proto_validators.FieldError("Timestamp", fmt.Errorf(`value '%v' must be less than '32521429541'`, this.Timestamp))
+	}
+	return nil
+}
+
+var _regex_OrderPart3_PreviousOrderCID = regexp.MustCompile(`^Q[[:alnum:]]{45}$|^$`)
+
+func (this *OrderPart3) Validate() error {
+	if !_regex_OrderPart3_PreviousOrderCID.MatchString(this.PreviousOrderCID) {
+		return github_com_mwitkow_go_proto_validators.FieldError("PreviousOrderCID", fmt.Errorf(`value '%v' must be a string conforming to regex "^Q[[:alnum:]]{45}$|^$"`, this.PreviousOrderCID))
+	}
+	if !(this.Timestamp > 1564050341) {
+		return github_com_mwitkow_go_proto_validators.FieldError("Timestamp", fmt.Errorf(`value '%v' must be greater than '1564050341'`, this.Timestamp))
+	}
+	if !(this.Timestamp < 32521429541) {
+		return github_com_mwitkow_go_proto_validators.FieldError("Timestamp", fmt.Errorf(`value '%v' must be less than '32521429541'`, this.Timestamp))
+	}
+	return nil
+}
+
+var _regex_OrderPart4_PreviousOrderCID = regexp.MustCompile(`^Q[[:alnum:]]{45}$|^$`)
+
+func (this *OrderPart4) Validate() error {
+	if !_regex_OrderPart4_PreviousOrderCID.MatchString(this.PreviousOrderCID) {
+		return github_com_mwitkow_go_proto_validators.FieldError("PreviousOrderCID", fmt.Errorf(`value '%v' must be a string conforming to regex "^Q[[:alnum:]]{45}$|^$"`, this.PreviousOrderCID))
+	}
+	if !(this.Timestamp > 1564050341) {
+		return github_com_mwitkow_go_proto_validators.FieldError("Timestamp", fmt.Errorf(`value '%v' must be greater than '1564050341'`, this.Timestamp))
+	}
+	if !(this.Timestamp < 32521429541) {
+		return github_com_mwitkow_go_proto_validators.FieldError("Timestamp", fmt.Errorf(`value '%v' must be less than '32521429541'`, this.Timestamp))
+	}
+	return nil
+}
+func (this *Policy) Validate() error {
+	return nil
+}
+func (this *PlainTestMessage1) Validate() error {
+	return nil
+}
+func (this *EncryptTestMessage1) Validate() error {
+	return nil
+}
+func (this *SimpleString) Validate() error {
+	return nil
+}
diff --git a/libs/documents/docs_test.go b/libs/documents/docs_test.go
new file mode 100644
index 0000000..40509e1
--- /dev/null
+++ b/libs/documents/docs_test.go
@@ -0,0 +1,229 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package documents
+
+import (
+	"bytes"
+	"crypto/sha256"
+	"encoding/hex"
+	mrand "math/rand"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/apache/incubator-milagro-dta/libs/crypto"
+	"github.com/apache/incubator-milagro-dta/libs/cryptowallet"
+	"github.com/go-test/deep"
+	"github.com/gogo/protobuf/proto"
+	"github.com/google/uuid"
+	"github.com/stretchr/testify/assert"
+)
+
+//Test to check that data is being encrypted in Order & not encrypted in ID
+func Test_EnvelopeEncryption(t *testing.T) {
+	s1, id1, _, _, _, blsSK := BuildTestIDDoc()
+
+	order, _ := BuildTestOrderDoc()
+	order.IPFSID = "NEW IPFS ID"
+	recipients := map[string]IDDoc{
+		id1: s1,
+	}
+	testText := "SEARCH_FOR_THIS123"
+	testTextBytes := []byte(testText)
+	order.Reference = testText
+	raw, _ := EncodeOrderDocument(id1, order, blsSK, "", recipients)
+	contains := bytes.Contains(raw, testTextBytes)
+	assert.False(t, contains, "Testtext should not be found inside the Envelope - its inside the ciphertext")
+
+	iddoc, _, _, _, _, blsSK := BuildTestIDDoc()
+	iddoc.AuthenticationReference = testText
+
+	raw2, _ := EncodeIDDocument(iddoc, blsSK)
+	contains2 := bytes.Contains(raw2, testTextBytes)
+
+	assert.True(t, contains2, "Testtext should  be found inside the Envelope -its inside the plaintext")
+
+}
+
+func Test_EncodeDecodeOrderDoc(t *testing.T) {
+	s1, id1, _, sikeSK, blsPK, blsSK := BuildTestIDDoc()
+	order, _ := BuildTestOrderDoc()
+	order.IPFSID = "NEW IPFS ID"
+	recipients := map[string]IDDoc{
+		id1: s1,
+	}
+	raw, _ := EncodeOrderDocument(id1, order, blsSK, "PREVIOUSCID", recipients)
+	reconstitutedOrder := OrderDoc{}
+	_ = DecodeOrderDocument(raw, "NEW IPFS ID", &reconstitutedOrder, sikeSK, id1, blsPK)
+	order.Header.Recipients[0].CipherText = reconstitutedOrder.Header.Recipients[0].CipherText
+	differences := deep.Equal(reconstitutedOrder, order)
+	var failed = false
+	for _, diff := range differences {
+		//ignore differences with XXX_ in the names, as these are protobuffer additional fields
+		if strings.Contains(diff, "XXX_") == false {
+			failed = true
+		}
+	}
+	assert.False(t, failed, "Reconstituted Fields don't match")
+	assert.NotNil(t, reconstitutedOrder.OrderPart4.Secret, "Reconstituted Fields dont match")
+}
+
+func Test_EncodeDecodeID(t *testing.T) {
+	iddoc, tag, _, _, _, blsSK := BuildTestIDDoc()
+	raw, _ := EncodeIDDocument(iddoc, blsSK)
+	reconstitutedIDDoc := NewIDDoc()
+	_ = DecodeIDDocument(raw, tag, &reconstitutedIDDoc)
+	differences := deep.Equal(reconstitutedIDDoc, iddoc)
+	var failed = false
+	for _, diff := range differences {
+		if strings.Contains(diff, "XXX_") == false {
+			failed = true
+		}
+	}
+	assert.False(t, failed, "Reconstituted Fields dont match")
+	assert.NotNil(t, reconstitutedIDDoc.DateTime, "Reconstituted Fields dont match")
+}
+
+func Test_AESPadding(t *testing.T) {
+	for i := 0; i < 1000; i++ {
+		randCount := mrand.Intn(100)
+		plainText, _ := cryptowallet.RandomBytes(randCount)
+		cipherText, aesKey, iv, _ := aesEncrypt(plainText)
+		decryptedPlaintext, _ := aesDecrypt(cipherText, iv, aesKey)
+		assert.Equal(t, decryptedPlaintext, plainText, "AES round trip fails")
+	}
+}
+
+func Test_EncodeDecode(t *testing.T) {
+	//These are some DocID for local user
+	s1, id1, _, sikeSK1, _, _ := BuildTestIDDoc()
+	recipients := map[string]IDDoc{
+		id1: s1,
+	}
+	seed, _ := cryptowallet.RandomBytes(16)
+	//Now generate a test Document & use some temp keys, as once made, we needs the TestID above to decode
+	_, blsPK, blsSK := crypto.BLSKeys(seed, nil)
+	secretBody := &SimpleString{Content: "B"}
+	plainText := &SimpleString{Content: "A"}
+	header := &Header{}
+	previousIDCode := "previous_id_code"
+	header.PreviousCID = previousIDCode
+	rawDoc, err := Encode(id1, plainText, secretBody, header, blsSK, recipients)
+	assert.Nil(t, err, "Failed to Encode")
+
+	//Now test Decode,
+	sigEnv := &SignedEnvelope{}
+	_ = proto.Unmarshal(rawDoc, sigEnv)
+	err = Verify(*sigEnv, blsPK)
+	assert.Nil(t, err, "Verify fails")
+
+	reconPlainText := &SimpleString{}
+	reconSecretBody := &SimpleString{}
+	tag := "this is the ipfs id tag"
+
+	reconHeader, err := Decode(rawDoc, tag, sikeSK1, id1, reconPlainText, reconSecretBody, blsPK)
+
+	assert.Nil(t, err, "Verify fails")
+	assert.Equal(t, plainText.Content, reconPlainText.Content, "Verify fails")
+	assert.Equal(t, secretBody.Content, reconSecretBody.Content, "Verify fails")
+	assert.NotNil(t, reconHeader.DateTime, "Header not populated")
+	assert.Equal(t, header.PreviousCID, previousIDCode, "Verify fails")
+	assert.Equal(t, reconHeader.IPFSID, tag, "tag not loaded into header")
+}
+
+func BuildTestOrderDoc() (OrderDoc, error) {
+	reference, err := uuid.NewUUID()
+	if err != nil {
+		return OrderDoc{}, err
+	}
+	order := NewOrderDoc()
+	//oder.Type will be used to extend the things that an order can do.
+	order.Type = "Safeguard_Secret"
+	order.Reference = reference.String()
+	order.Coin = 0
+	order.BeneficiaryCID = "TESTBeneficiaryIDDocumentCID"
+	order.Timestamp = time.Now().Unix()
+
+	o2 := &OrderPart2{}
+	o2.CommitmentPublicKey = "2CommitmentPublicKey"
+	o2.PreviousOrderCID = "2PreviousOrderCID"
+	o2.Timestamp = time.Now().Unix()
+
+	o3 := &OrderPart3{}
+	o3.Redemption = "3Redemption"
+	o3.PreviousOrderCID = "3PreviousOrderCID"
+	o3.BeneficiaryEncryptedData = []byte("3BeneficiaryEncryptedData")
+	o3.Timestamp = time.Now().Unix()
+
+	o4 := &OrderPart4{}
+	o4.Secret = "4Secret"
+	o4.PreviousOrderCID = "4PreviousOrderCID"
+	o4.Timestamp = time.Now().Unix()
+
+	order.OrderPart2 = o2
+	order.OrderPart3 = o3
+	order.OrderPart4 = o4
+	return order, nil
+}
+
+func BuildTestIDDoc() (IDDoc, string, []byte, []byte, []byte, []byte) {
+	//make some test ID docs
+	seed, _ := cryptowallet.RandomBytes(16)
+
+	_, sikePK, sikeSK := crypto.SIKEKeys(seed)
+
+	_, blsPK, blsSK := crypto.BLSKeys(seed, nil)
+
+	//id := []byte("TestID1")
+	envelope := Envelope{}
+	header := Header{}
+	idDocument := IDDocument{}
+	idDocument.SikePublicKey = sikePK
+	idDocument.BLSPublicKey = blsPK
+
+	//assemble
+	envelope.Header = &header
+	envelope.Body, _ = proto.Marshal(&idDocument)
+	envelope.EncryptedBody = nil
+	header.EncryptedBodyIV = nil
+	signedEnvelope, _ := sign(envelope, blsSK, "TESTID")
+	ipfsID, _ := createIDForSignedEnvelope(signedEnvelope)
+	iddoc := &IDDoc{}
+	rawDocI, _ := proto.Marshal(&signedEnvelope)
+	_ = DecodeIDDocument(rawDocI, ipfsID, iddoc)
+	return *iddoc, ipfsID, sikePK, sikeSK, blsPK, blsSK
+}
+
+//createIDForSignedEnvelope - create a hash for the document to be used as an ID
+func createIDForSignedEnvelope(signedEnvelope SignedEnvelope) (string, []byte) {
+	dat, _ := proto.Marshal(&signedEnvelope)
+	return sha256Hash(string(dat)), dat
+}
+
+func sha256Hash(data string) string {
+	hasher := sha256.New()
+	_, _ = hasher.Write([]byte(data))
+	return hex.EncodeToString(hasher.Sum(nil))
+}
+
+//Use - helper to remove warnings
+func Use(vals ...interface{}) {
+	for _, val := range vals {
+		_ = val
+	}
+}
diff --git a/libs/ipfs/apiconnector.go b/libs/ipfs/apiconnector.go
new file mode 100644
index 0000000..652016a
--- /dev/null
+++ b/libs/ipfs/apiconnector.go
@@ -0,0 +1,174 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package ipfs
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"io/ioutil"
+	"net"
+	"strings"
+
+	shell "github.com/ipfs/go-ipfs-api"
+	"github.com/pkg/errors"
+)
+
+// APIConnector is IPFS Shell API Connector
+type APIConnector struct {
+	shell *shell.Shell
+	id    string
+}
+
+// NewAPIConnector inisialises new IPFS API connector
+func NewAPIConnector(options ...APIConnectorOption) (Connector, error) {
+
+	cb := &APIConnectorBuilder{
+		nodeAddr: "localhost:5001",
+	}
+
+	for _, option := range options {
+		if err := option(cb); err != nil {
+			return nil, err
+		}
+	}
+
+	sh := shell.NewShell(cb.nodeAddr)
+
+	outID, err := sh.ID()
+	if err != nil {
+		return nil, errors.Wrap(ErrNodeConnection, err.Error())
+	}
+
+	if !sh.IsUp() {
+		return nil, ErrNodeConnection
+	}
+
+	if cb.swarmPeerAddr != "" {
+		_ = sh.SwarmConnect(context.Background(), cb.swarmPeerAddr)
+	}
+
+	return &APIConnector{
+		shell: sh,
+		id:    outID.ID,
+	}, nil
+}
+
+// Add adds a data to the IPFS network and returns the ipfs path
+func (c *APIConnector) Add(data []byte) (string, error) {
+	return c.shell.Add(bytes.NewReader(data), shell.Pin(true), shell.Progress(false))
+}
+
+// Get gets a data from ipfs path
+func (c *APIConnector) Get(path string) ([]byte, error) {
+	r, err := c.shell.Cat(path)
+	if err != nil {
+		return nil, err
+	}
+
+	b, err := ioutil.ReadAll(r)
+	if err != nil {
+		return nil, err
+	}
+
+	// Pin the document
+	if err := c.shell.Pin(path); err != nil {
+		return nil, err
+	}
+
+	return b, nil
+}
+
+// AddJSON encodes the data in JSON and adds it to the IPFS
+func (c *APIConnector) AddJSON(data interface{}) (string, error) {
+	jd, err := json.Marshal(data)
+	if err != nil {
+		return "", err
+	}
+
+	return c.Add(jd)
+}
+
+// GetJSON gets data from IPFS and decodes it from JSON
+func (c *APIConnector) GetJSON(path string, data interface{}) error {
+	jd, err := c.Get(path)
+	if err != nil {
+		return err
+	}
+
+	if err := json.Unmarshal(jd, data); err != nil {
+		return errors.Wrap(ErrDocumentNotValid, err.Error())
+	}
+
+	return nil
+}
+
+// GetID returns the local id
+func (c *APIConnector) GetID() string {
+	return c.id
+}
+
+// APIConnectorBuilder for building the IPFS API connector
+type APIConnectorBuilder struct {
+	nodeAddr      string
+	swarmPeerAddr string
+}
+
+// APIConnectorOption function
+type APIConnectorOption func(*APIConnectorBuilder) error
+
+// NodeAddr specifies the IPFS local node address
+func NodeAddr(addr string) APIConnectorOption {
+	return func(cb *APIConnectorBuilder) error {
+		cb.nodeAddr = addr
+		return nil
+	}
+}
+
+// PeerAddr specifies the IPFS node peer to connect
+func PeerAddr(peerAddr string) APIConnectorOption {
+	return func(cb *APIConnectorBuilder) error {
+		cb.swarmPeerAddr = peerAddr
+		return nil
+	}
+}
+
+// PeerDomain returns the IPFS peer addr from domain TXT record
+func PeerDomain(domain string) APIConnectorOption {
+	return func(cb *APIConnectorBuilder) error {
+		var addr string
+		records, err := net.LookupTXT(domain)
+		if err != nil {
+			return err
+		}
+
+		for _, r := range records {
+			a := strings.TrimPrefix(strings.TrimSuffix(r, `"`), `"`)
+			if len(a) > 0 && a[0] == '/' {
+				addr = a
+			}
+		}
+
+		if addr == "" {
+			return errors.Errorf("unable to find the IPFS address from TXT record of %v", domain)
+		}
+
+		cb.swarmPeerAddr = addr
+		return nil
+	}
+}
diff --git a/libs/ipfs/ipfs.go b/libs/ipfs/ipfs.go
new file mode 100644
index 0000000..b9fa733
--- /dev/null
+++ b/libs/ipfs/ipfs.go
@@ -0,0 +1,43 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package ipfs - connect, get and set operations for embedded or external IPFS node
+*/
+package ipfs
+
+import (
+	"github.com/pkg/errors"
+)
+
+var (
+	// ErrNodeConnection when the ipfs node is not accessible
+	ErrNodeConnection = errors.New("ipfs node connection problem")
+	// ErrDocumentNotValid when the ipfs document is not well formatted
+	ErrDocumentNotValid = errors.New("document not valid")
+	// ErrDocumentNotFound when the ipfs document is not dound
+	ErrDocumentNotFound = errors.New("document not found")
+)
+
+// Connector is the IPFS connector interface
+type Connector interface {
+	GetID() string
+	Add(data []byte) (string, error)
+	Get(path string) ([]byte, error)
+	AddJSON(data interface{}) (string, error)
+	GetJSON(path string, data interface{}) error
+}
diff --git a/libs/ipfs/memory.go b/libs/ipfs/memory.go
new file mode 100644
index 0000000..ef20aa9
--- /dev/null
+++ b/libs/ipfs/memory.go
@@ -0,0 +1,104 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package ipfs
+
+import (
+	"encoding/json"
+	"sync"
+
+	multihash "github.com/multiformats/go-multihash"
+	"github.com/pkg/errors"
+)
+
+// MemoryConnector ipmlements IPFS Connector interface with Memory storage
+type MemoryConnector struct {
+	mutex sync.RWMutex
+	store map[string][]byte
+}
+
+// NewMemoryConnector creates a new MemoryConnector struct
+func NewMemoryConnector() (Connector, error) {
+	return &MemoryConnector{
+		mutex: sync.RWMutex{},
+		store: map[string][]byte{},
+	}, nil
+}
+
+// Add adds data to Memory IPFS
+func (m *MemoryConnector) Add(data []byte) (string, error) {
+	id, err := genIPFSID(data)
+	if err != nil {
+		return "", err
+	}
+
+	m.mutex.Lock()
+	m.store[id] = data
+	m.mutex.Unlock()
+
+	return id, nil
+}
+
+// Get gets data from Memory IPFS
+func (m *MemoryConnector) Get(path string) ([]byte, error) {
+	m.mutex.RLock()
+	data, ok := m.store[path]
+	m.mutex.RUnlock()
+	if !ok {
+		return nil, errors.New("Key not found")
+	}
+
+	return data, nil
+}
+
+// AddJSON encodes data to JSON and stores it in Memory IPFS
+func (m *MemoryConnector) AddJSON(data interface{}) (string, error) {
+	jd, err := json.Marshal(data)
+	if err != nil {
+		return "", err
+	}
+
+	return m.Add(jd)
+}
+
+// GetJSON gets data from IPFS and decodes it from JSON
+func (m *MemoryConnector) GetJSON(path string, data interface{}) error {
+	jd, err := m.Get(path)
+	if err != nil {
+		return err
+	}
+
+	if err := json.Unmarshal(jd, data); err != nil {
+		return errors.Wrap(ErrDocumentNotValid, err.Error())
+	}
+
+	return nil
+}
+
+// GetID returns the local id
+func (m *MemoryConnector) GetID() string {
+	return ""
+}
+
+func genIPFSID(data []byte) (string, error) {
+	mh, err := multihash.Sum(data, multihash.SHA2_256, 32)
+	if err != nil {
+		return "", err
+	}
+
+	return mh.B58String(), nil
+}
diff --git a/libs/ipfs/nodeconnector.go b/libs/ipfs/nodeconnector.go
new file mode 100644
index 0000000..d3d15e0
--- /dev/null
+++ b/libs/ipfs/nodeconnector.go
@@ -0,0 +1,259 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package ipfs
+
+import (
+	"context"
+	"crypto/rand"
+	"encoding/base64"
+	"encoding/json"
+	"io/ioutil"
+
+	memoryds "github.com/ipfs/go-datastore"
+	dsync "github.com/ipfs/go-datastore/sync"
+	levelds "github.com/ipfs/go-ds-leveldb"
+	cfg "github.com/ipfs/go-ipfs-config"
+	files "github.com/ipfs/go-ipfs-files"
+	core "github.com/ipfs/go-ipfs/core"
+	coreapi "github.com/ipfs/go-ipfs/core/coreapi"
+	repo "github.com/ipfs/go-ipfs/repo"
+	coreiface "github.com/ipfs/interface-go-ipfs-core"
+	path "github.com/ipfs/interface-go-ipfs-core/path"
+	ci "github.com/libp2p/go-libp2p-crypto"
+	peer "github.com/libp2p/go-libp2p-peer"
+
+	"github.com/pkg/errors"
+)
+
+const (
+	defaultShardFun = "prefix"
+)
+
+// NodeConnectorBuilder for building the IPFS embedded node connector
+type NodeConnectorBuilder struct {
+	ctx            context.Context
+	localAddresses []string
+	bootstrapPeers []string
+	dstore         repo.Datastore
+}
+
+// NodeConnectorOption function
+type NodeConnectorOption func(*NodeConnectorBuilder) error
+
+// NodeConnector is IPFS embedded node
+type NodeConnector struct {
+	id   string
+	ctx  context.Context
+	node *core.IpfsNode
+	api  coreiface.CoreAPI
+}
+
+// NewNodeConnector inisialises and runs a new IPFS Node
+func NewNodeConnector(options ...NodeConnectorOption) (Connector, error) {
+	cb := &NodeConnectorBuilder{
+		localAddresses: []string{},
+		bootstrapPeers: []string{},
+		ctx:            context.Background(),
+		dstore:         nil,
+	}
+
+	for _, option := range options {
+		if err := option(cb); err != nil {
+			return nil, err
+		}
+	}
+
+	if len(cb.localAddresses) == 0 {
+		cb.localAddresses = []string{"/ip4/0.0.0.0/tcp/4001"}
+	}
+
+	if cb.dstore == nil {
+		return nil, errors.New("IPFS datastore not initialized")
+	}
+
+	// Generate Node keys
+	priv, _, err := ci.GenerateKeyPairWithReader(ci.RSA, 2048, rand.Reader)
+	if err != nil {
+		return nil, err
+	}
+	privkeyb, err := priv.Bytes()
+	if err != nil {
+		return nil, err
+	}
+	pid, err := peer.IDFromPrivateKey(priv)
+	if err != nil {
+		return nil, err
+	}
+
+	conf := cfg.Config{
+		Bootstrap: cb.bootstrapPeers,
+	}
+	conf.Addresses.Swarm = cb.localAddresses
+	conf.Identity.PeerID = pid.Pretty()
+	conf.Identity.PrivKey = base64.StdEncoding.EncodeToString(privkeyb)
+	conf.Routing.Type = "dht"
+	conf.Swarm.ConnMgr = cfg.ConnMgr{
+		Type:        "basic",
+		LowWater:    20,
+		HighWater:   100,
+		GracePeriod: "30s",
+	}
+
+	appRepo := &repo.Mock{
+		D: dsync.MutexWrap(cb.dstore),
+		C: conf,
+	}
+
+	node, err := core.NewNode(cb.ctx, &core.BuildCfg{
+		Repo:   appRepo,
+		Online: true,
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	api, err := coreapi.NewCoreAPI(node)
+	if err != nil {
+		return nil, err
+	}
+
+	return &NodeConnector{
+		id:   pid.Pretty(),
+		ctx:  cb.ctx,
+		node: node,
+		api:  api,
+	}, nil
+}
+
+// Add adds a data to the IPFS network and returns the ipfs path
+func (c *NodeConnector) Add(data []byte) (string, error) {
+	f := files.NewBytesFile(data)
+	defer f.Close()
+	r, err := c.api.Unixfs().Add(c.ctx, f)
+	if err != nil {
+		return "", err
+	}
+	return r.Cid().String(), nil
+}
+
+// Get gets a data from ipfs path
+func (c *NodeConnector) Get(ipfsPath string) ([]byte, error) {
+	p := path.New(ipfsPath)
+
+	node, err := c.api.Unixfs().Get(c.ctx, p)
+	if err != nil {
+		return nil, err
+	}
+	defer node.Close()
+
+	f := files.ToFile(node)
+	if f == nil {
+		return nil, errors.New("not a file")
+	}
+	defer f.Close()
+
+	b, err := ioutil.ReadAll(f)
+	if err != nil {
+		return nil, err
+	}
+
+	// TODO: Pin the document
+	return b, nil
+}
+
+// AddJSON encodes the data in JSON and adds it to the IPFS
+func (c *NodeConnector) AddJSON(data interface{}) (string, error) {
+	jd, err := json.Marshal(data)
+	if err != nil {
+		return "", err
+	}
+
+	return c.Add(jd)
+}
+
+// GetJSON gets data from IPFS and decodes it from JSON
+func (c *NodeConnector) GetJSON(path string, data interface{}) error {
+	jd, err := c.Get(path)
+	if err != nil {
+		return err
+	}
+
+	if err := json.Unmarshal(jd, data); err != nil {
+		return errors.Wrap(ErrDocumentNotValid, err.Error())
+	}
+
+	return nil
+}
+
+// GetID returns the local id
+func (c *NodeConnector) GetID() string {
+	return c.id
+}
+
+// AddLocalAddress adds a new local IPFS Swarm address
+func AddLocalAddress(addr string) NodeConnectorOption {
+	return func(cb *NodeConnectorBuilder) error {
+		cb.localAddresses = append(cb.localAddresses, addr)
+		return nil
+	}
+}
+
+// AddBootstrapPeer adds a IPFS peer to the list of IPFS bootatrap addresses
+func AddBootstrapPeer(peerAddr ...string) NodeConnectorOption {
+	return func(cb *NodeConnectorBuilder) error {
+		cb.bootstrapPeers = append(cb.bootstrapPeers, peerAddr...)
+		return nil
+	}
+}
+
+// AddDefaultBootstrapPeers adds the default IPFS bootstrap addresses
+// The default IPFS addresses are maintained by the IPFS team
+func AddDefaultBootstrapPeers() NodeConnectorOption {
+	return func(cb *NodeConnectorBuilder) error {
+		cb.bootstrapPeers = append(cb.bootstrapPeers, cfg.DefaultBootstrapAddresses...)
+		return nil
+	}
+}
+
+// WithLevelDatastore initialize IPFS node with LevelDB datastore
+func WithLevelDatastore(path string) NodeConnectorOption {
+	return func(cb *NodeConnectorBuilder) (err error) {
+		cb.dstore, err = levelds.NewDatastore(path, &levelds.Options{
+			Compression: 0,
+		})
+
+		return nil
+	}
+}
+
+// WithMemoryDatastore initialize IPFS node with memory datastore
+func WithMemoryDatastore() NodeConnectorOption {
+	return func(cb *NodeConnectorBuilder) (err error) {
+		cb.dstore = memoryds.NewMapDatastore()
+
+		return nil
+	}
+}
+
+// WithContext sets the context
+func WithContext(ctx context.Context) NodeConnectorOption {
+	return func(cb *NodeConnectorBuilder) error {
+		cb.ctx = ctx
+		return nil
+	}
+}
diff --git a/libs/ipfs/nodeconnector_test.go b/libs/ipfs/nodeconnector_test.go
new file mode 100644
index 0000000..96e7795
--- /dev/null
+++ b/libs/ipfs/nodeconnector_test.go
@@ -0,0 +1,89 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package ipfs
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/pkg/errors"
+)
+
+func TestNodeConnector(t *testing.T) {
+	timeOut := time.Second * 5
+	ctx, cancel := context.WithCancel(context.Background())
+
+	errChan := make(chan error)
+	go func(ctx context.Context, errChan chan error) {
+		addr1 := "/ip4/127.0.0.1/tcp/53221"
+		addr2 := "/ip4/127.0.0.1/tcp/53222"
+
+		ipfs1, err := NewNodeConnector(
+			WithContext(ctx),
+			AddLocalAddress(addr1),
+			WithMemoryDatastore(),
+		)
+		if err != nil {
+			errChan <- err
+			return
+		}
+
+		ipfs2, err := NewNodeConnector(
+			WithContext(ctx),
+			AddLocalAddress(addr2),
+			AddBootstrapPeer(fmt.Sprintf("%s/ipfs/%s", addr1, ipfs1.GetID())),
+			WithMemoryDatastore(),
+		)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		bsend := []byte{1, 2, 3}
+		cid, err := ipfs1.Add(bsend)
+		if err != nil {
+			errChan <- err
+			return
+		}
+
+		b, err := ipfs2.Get(cid)
+		if err != nil {
+			errChan <- err
+			return
+		}
+
+		if !bytes.Equal(bsend, b) {
+			errChan <- errors.Errorf("Expected: %v, found: %v", bsend, b)
+			return
+		}
+
+		errChan <- nil
+	}(ctx, errChan)
+
+	time.AfterFunc(timeOut, func() {
+		t.Error("Timeout. Test took too long")
+		cancel()
+	})
+
+	if err := <-errChan; err != nil {
+		t.Fatal(err)
+	}
+
+}
diff --git a/libs/logger/logger.go b/libs/logger/logger.go
new file mode 100644
index 0000000..445ac6b
--- /dev/null
+++ b/libs/logger/logger.go
@@ -0,0 +1,164 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package logger - configurable logging middleware
+*/
+package logger
+
+import (
+	"errors"
+	"fmt"
+	"os"
+	"time"
+
+	"github.com/go-kit/kit/log"
+)
+
+const (
+	timeFormat = "2006-01-02T15:04:05.000"
+
+	logLevelNone = iota
+	logLevelError
+	logLevelInfo
+	logLevelDebug
+)
+
+// Logger implements go-kit logger interface
+// Adding additional functionality
+type Logger struct {
+	logger   log.Logger
+	logLevel int
+}
+
+// NewLogger initializes a new Logger instance
+// Supported log types are: text, json, none
+func NewLogger(logType, logLevel string, options ...Option) (*Logger, error) {
+	logger := logTypeFromString(logType)
+	if logger == nil {
+		return nil, errors.New("unuspported log format")
+	}
+
+	l := &Logger{
+		logger:   logger,
+		logLevel: logLevelFromString(logLevel),
+	}
+
+	for _, o := range options {
+		if err := o(l); err != nil {
+			return nil, err
+		}
+	}
+
+	return l, nil
+}
+
+func logTypeFromString(logType string) log.Logger {
+	var logger log.Logger
+	switch logType {
+	case "text":
+		logger = NewLogTextLogger(os.Stdout)
+	case "fmt":
+		logger = log.NewLogfmtLogger(os.Stdout)
+	case "json":
+		logger = log.NewJSONLogger(os.Stdout)
+	case "none":
+		logger = log.NewNopLogger()
+	default:
+		return nil
+	}
+
+	timestampFormat := log.TimestampFormat(
+		func() time.Time { return time.Now().UTC() },
+		timeFormat,
+	)
+
+	logger = log.With(logger, "ts", timestampFormat)
+
+	return logger
+}
+
+func logLevelFromString(logLevel string) int {
+	switch logLevel {
+	case "error":
+		return logLevelError
+	case "info":
+		return logLevelInfo
+	case "debug":
+		return logLevelDebug
+	}
+
+	return logLevelNone
+}
+
+// Option for adding additional configurations of Logger instance
+type Option func(l *Logger) error
+
+// With adds additional values to the logger
+func With(k, v interface{}) Option {
+	return func(l *Logger) error {
+		l.logger = log.With(l.logger, k, v)
+		return nil
+	}
+}
+
+// Log satisfies Logger interface
+func (l *Logger) Log(kvals ...interface{}) error {
+	return l.logger.Log(kvals...)
+}
+
+// Error log
+func (l *Logger) Error(msg string, vals ...interface{}) {
+	if l.logLevel < logLevelError {
+		return
+	}
+
+	_ = l.Log("t", "err", "msg", fmt.Sprintf(msg, vals...))
+}
+
+// Info log
+func (l *Logger) Info(msg string, vals ...interface{}) {
+	if l.logLevel < logLevelInfo {
+		return
+	}
+	_ = l.Log("t", "inf", "msg", fmt.Sprintf(msg, vals...))
+}
+
+// Request log
+func (l *Logger) Request(reqID, method, path string) {
+	if l.logLevel < logLevelInfo {
+		return
+	}
+	_ = l.Log("t", "req", "reqID", reqID, "method", method, "path", path)
+}
+
+// Response log
+func (l *Logger) Response(reqID, method, path string, statusCode int, statusText string, reqTime time.Duration) {
+	if l.logLevel < logLevelInfo {
+		return
+	}
+
+	_ = l.Log("t", "res", "reqID", reqID, "method", method, "path", path, "statusCode", statusCode, "statusText", statusText, "time", reqTime.String())
+}
+
+// Debug log
+func (l *Logger) Debug(msg string, vals ...interface{}) {
+	if l.logLevel < logLevelDebug {
+		return
+	}
+	_ = l.Log("t", "dbg", "msg", fmt.Sprintf(msg, vals...))
+}
diff --git a/libs/logger/textlogger.go b/libs/logger/textlogger.go
new file mode 100644
index 0000000..bc7b2e1
--- /dev/null
+++ b/libs/logger/textlogger.go
@@ -0,0 +1,70 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package logger
+
+import (
+	"fmt"
+	"io"
+	"log"
+	"strings"
+
+	kitlog "github.com/go-kit/kit/log"
+)
+
+type logTextLogger struct {
+	log *log.Logger
+}
+
+// NewLogTextLogger returns a logger that encodes keyvals to the Writer in
+// plain text format.
+// The passed Writer must be safe for concurrent use by multiple goroutines if
+// the returned Logger will be used concurrently.
+func NewLogTextLogger(w io.Writer) kitlog.Logger {
+	return &logTextLogger{log.New(w, "", 0)}
+}
+
+func (l logTextLogger) Log(keyvals ...interface{}) error {
+	var out string
+
+	for i, v := range keyvals {
+		if i%2 == 0 {
+			continue
+		}
+
+		k := keyvals[i-1]
+
+		switch k {
+		case "ts", "msg", "method", "path", "statusCode", "statusText", "reqID":
+			out += fmt.Sprintf("%v ", v)
+		case "t":
+			s, ok := v.(string)
+			if ok {
+				out += fmt.Sprintf("[%s] ", strings.ToUpper(s))
+			} else {
+				out += fmt.Sprintf("%v ", v)
+			}
+		case "time":
+			out += fmt.Sprintf("(%v) ", v)
+		default:
+			out += fmt.Sprintf("%v: %v ", k, v)
+		}
+	}
+
+	l.log.Println(strings.TrimSpace(out))
+	return nil
+}
diff --git a/libs/transport/authorizer.go b/libs/transport/authorizer.go
new file mode 100644
index 0000000..9484708
--- /dev/null
+++ b/libs/transport/authorizer.go
@@ -0,0 +1,152 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package transport
+
+import (
+	"context"
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"strings"
+
+	oidc "github.com/coreos/go-oidc"
+	"github.com/pkg/errors"
+)
+
+const (
+//	jwtRequestTimeout = time.Second * 2
+)
+
+// Authorizer interface for implementing API Authorization
+type Authorizer interface {
+	Authorize(header http.Header) (*UserClaims, error)
+}
+
+// OIDCAuthorizer implements OIDC/OAuth2 JWT token authorization token authorizer
+type OIDCAuthorizer struct {
+	ClientID        string
+	RequestUserInfo bool
+	ClaimsSupported []string
+	Provider        *oidc.Provider
+}
+
+// NewOIDCAuthorizer creates a new instance of OIDCAuthorizer
+func NewOIDCAuthorizer(clientID, oidcProvider string, claims ...string) (Authorizer, error) {
+	provider, err := oidc.NewProvider(context.Background(), oidcProvider)
+	if err != nil {
+		return nil, errors.Wrap(err, "init oidc provider")
+	}
+
+	return &OIDCAuthorizer{
+		ClientID:        clientID,
+		RequestUserInfo: true,
+		ClaimsSupported: claims[:],
+		Provider:        provider,
+	}, nil
+}
+
+// Authorize checks the IDToken
+func (a *OIDCAuthorizer) Authorize(header http.Header) (*UserClaims, error) {
+	rawIDToken, err := extractJWTToken(header.Get("Authorization"))
+	if err != nil {
+		return nil, err
+	}
+
+	verifier := a.Provider.Verifier(&oidc.Config{ClientID: a.ClientID})
+	idToken, err := verifier.Verify(context.Background(), rawIDToken)
+	if err != nil {
+		return nil, err
+	}
+	uc := &UserClaims{}
+	if err := idToken.Claims(uc); err != nil {
+		return nil, errors.Wrap(err, "parse claims")
+	}
+
+	return uc, nil
+}
+
+// UserClaims holds information about the claims from the UserInfo endpoint
+type UserClaims map[string]interface{}
+
+// GetString returns a value of a key if exists
+func (uc *UserClaims) GetString(key string) string {
+	if uc == nil {
+		return ""
+	}
+	vi, ok := (*uc)[key]
+	if ok {
+		v, ok := vi.(string)
+		if ok {
+			return v
+		}
+	}
+	return ""
+}
+
+// LocalAuthorizer implements JWT Authorizer without verifying the signature
+// For testing purposes only
+type LocalAuthorizer struct{}
+
+// Authorize checks the IDToken
+func (a *LocalAuthorizer) Authorize(header http.Header) (*UserClaims, error) {
+	rawIDToken, err := extractJWTToken(header.Get("Authorization"))
+	if err != nil {
+		return nil, err
+	}
+
+	uc := &UserClaims{}
+	if err := parseJWTToken(rawIDToken, uc); err != nil {
+		return nil, err
+	}
+
+	return uc, nil
+}
+
+func extractJWTToken(authHeader string) (string, error) {
+	split := strings.Split(authHeader, " ")
+	if len(split) < 2 || split[0] != "Bearer" {
+		return "", errors.New("invalid authorization header")
+	}
+	return split[1], nil
+}
+
+func parseJWTToken(p string, v interface{}) error {
+	parts := strings.Split(p, ".")
+	if len(parts) < 2 {
+		return fmt.Errorf("invalid token")
+	}
+	payload, err := base64.RawURLEncoding.DecodeString(parts[1])
+	if err != nil {
+		return errors.Wrap(err, "invalid token")
+	}
+
+	if err := json.Unmarshal(payload, v); err != nil {
+		return errors.Wrap(err, "invalid token payload")
+	}
+
+	return nil
+}
+
+// EmptyAuthorizer implements empty Authorizer
+type EmptyAuthorizer struct{}
+
+// Authorize checks the IDToken
+func (a *EmptyAuthorizer) Authorize(header http.Header) (*UserClaims, error) {
+	return &UserClaims{}, nil
+}
diff --git a/libs/transport/http.go b/libs/transport/http.go
new file mode 100644
index 0000000..f1590bb
--- /dev/null
+++ b/libs/transport/http.go
@@ -0,0 +1,528 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package transport - HTTP request and response methods
+*/
+package transport
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"strings"
+	"time"
+
+	"github.com/apache/incubator-milagro-dta/libs/logger"
+	"github.com/go-kit/kit/endpoint"
+	"github.com/go-kit/kit/metrics"
+	httptransport "github.com/go-kit/kit/transport/http"
+	"github.com/google/uuid"
+	"github.com/gorilla/mux"
+	"github.com/pkg/errors"
+)
+
+// TODO: Add request rate limiter
+// TODO: Add circuit breaker
+
+type contextKey int
+
+const (
+	contextKeyCorsOrigin     contextKey = 10000
+	contextQueryParams       contextKey = 10001
+	contextURLParams         contextKey = 10002
+	contextHTTPHeaders       contextKey = 10003
+	contextProtectedEndpoint contextKey = 10004
+	contextAuthorized        contextKey = 10005
+	contextAuthorizeError    contextKey = 10006
+	contextUserInfo          contextKey = 10007
+)
+
+var (
+	// ErrMethodNotAllowed when HTTP request method is not handled
+	ErrMethodNotAllowed = errors.New("method not allowed")
+	// ErrInvalidRequest when HTTP request is invalid
+	ErrInvalidRequest = errors.New("invalid request")
+	// ErrInvalidJSON when the request is invalid json
+	ErrInvalidJSON = errors.New("invalid json")
+	// ErrUnauthorized when a protected endpoint is not authorized
+	ErrUnauthorized = errors.New("unauthorized")
+	// ErrHTTPClientError when HTTP request status is not 200
+	ErrHTTPClientError = errors.New("request error")
+)
+
+// HTTPEndpoints is a map of endpoints
+// Key is the name of the endpoint
+type HTTPEndpoints map[string]HTTPEndpoint
+
+// HTTPEndpoint defines a single endpoint
+type HTTPEndpoint struct {
+	Path        string
+	Method      string
+	Endpoint    endpoint.Endpoint
+	NewRequest  func() interface{}
+	NewResponse func() interface{}
+	ErrStatus   ErrorStatus
+	Options     []httptransport.ServerOption
+}
+
+// ClientEndpoints is a map of all exported client endpoints
+type ClientEndpoints map[string]endpoint.Endpoint
+
+// ErrorStatus is a map of errors to http response status codes
+type ErrorStatus map[error]int
+
+// ResponseStatus returns the status code and status text based on the error type
+func (e ErrorStatus) ResponseStatus(err error) (statusCode int, statusText string) {
+	statusCode = http.StatusOK
+	statusText = ""
+
+	if err != nil {
+		statusCode = http.StatusInternalServerError
+
+		if sc, ok := e[errors.Cause(err)]; ok {
+			statusCode = sc
+			statusText = decodeError(err.Error())
+		}
+
+		// Add transport errors
+		switch errors.Cause(err) {
+		case ErrInvalidJSON, ErrInvalidRequest:
+			statusCode = http.StatusBadRequest
+		case ErrMethodNotAllowed:
+			statusCode = http.StatusMethodNotAllowed
+		case ErrUnauthorized:
+			statusCode = http.StatusUnauthorized
+			statusText = decodeError(err.Error())
+		case ErrHTTPClientError:
+			statusCode = http.StatusBadRequest
+			statusText = decodeError(err.Error())
+		}
+	}
+
+	if statusText == "" {
+		statusText = http.StatusText(statusCode)
+	}
+
+	return statusCode, statusText
+}
+
+func decodeError(strerr string) string {
+	ew := &errorWrapper{}
+	if er := json.Unmarshal([]byte(strerr), ew); er != nil {
+		return strerr
+	}
+	return ew.Error
+}
+
+// NewHTTPHandler returns an HTTP handler that makes a set of endpoints
+func NewHTTPHandler(endpoints HTTPEndpoints, logger *logger.Logger, duration metrics.Histogram) *mux.Router {
+	m := mux.NewRouter()
+	for eName, e := range endpoints {
+		endpoint := loggingMiddleware(
+			logger,
+			e.ErrStatus,
+		)(e.Endpoint)
+		endpoint = metricsDurationMiddleware(duration.With("method", eName))(endpoint)
+
+		options := []httptransport.ServerOption{
+			httptransport.ServerErrorEncoder(errorEncoder(e.ErrStatus, logger)),
+			parseQueryParams,
+			parseURLParams,
+			parseHTTPHeaders,
+			httptransport.ServerBefore(httptransport.PopulateRequestContext),
+		}
+
+		if e.Options != nil {
+			options = append(options, e.Options...)
+		}
+
+		m.Path(e.Path).Methods(http.MethodOptions).Handler(
+			httptransport.NewServer(
+				func(ctx context.Context, request interface{}) (response interface{}, err error) {
+					return nil, nil
+				},
+				decodeOptionsRequest,
+				func(ctx context.Context, w http.ResponseWriter, response interface{}) error {
+					return nil
+				},
+				options...,
+			),
+		)
+
+		m.Path(e.Path).Methods(e.Method).Handler(
+			httptransport.NewServer(
+				endpoint,
+				decodeJSONRequest(e),
+				encodeJSONResponse,
+				options...,
+			),
+		)
+	}
+
+	return m
+}
+
+// GetParams returns Query params of a request
+func GetParams(ctx context.Context) url.Values {
+	v := ctx.Value(contextQueryParams)
+	if v == nil {
+		return url.Values{}
+	}
+
+	values, ok := v.(url.Values)
+	if !ok {
+		return url.Values{}
+	}
+
+	return values
+}
+
+// GetURLParams returns URL params of the request path
+func GetURLParams(ctx context.Context) url.Values {
+	v := ctx.Value(contextURLParams)
+	if v == nil {
+		return url.Values{}
+	}
+
+	values, ok := v.(url.Values)
+	if !ok {
+		return url.Values{}
+	}
+
+	return values
+}
+
+// GetHeaders returns the HTTP Request headers
+func GetHeaders(ctx context.Context) http.Header {
+	v := ctx.Value(contextHTTPHeaders)
+	if v == nil {
+		return http.Header{}
+	}
+
+	headers, ok := v.(http.Header)
+	if !ok {
+		return http.Header{}
+	}
+
+	return headers
+}
+
+// GetUserInfo returns the authorized user info
+func GetUserInfo(ctx context.Context) *UserClaims {
+	v := ctx.Value(contextUserInfo)
+	if v == nil {
+		return &UserClaims{}
+	}
+
+	uc, ok := v.(*UserClaims)
+	if !ok {
+		return &UserClaims{}
+	}
+
+	return uc
+}
+
+// Options helper handlers
+
+// ServerOptions returns an array of httptransport.ServerOption
+func ServerOptions(opt ...httptransport.ServerOption) []httptransport.ServerOption {
+	return opt
+}
+
+// SetCors sets CORS HTTP response headers for specific domains
+func SetCors(domain string) httptransport.ServerOption {
+	return func(s *httptransport.Server) {
+		httptransport.ServerBefore(
+			func(ctx context.Context, r *http.Request) context.Context {
+				origin := r.Header.Get("Origin")
+				if domain != "*" && origin != domain {
+					return ctx
+				}
+				return context.WithValue(ctx, contextKeyCorsOrigin, origin)
+			},
+		)(s)
+
+		httptransport.ServerAfter(
+			func(ctx context.Context, w http.ResponseWriter) context.Context {
+				setCORSHeaders(ctx, w)
+				return ctx
+			},
+		)(s)
+	}
+}
+
+func setCORSHeaders(ctx context.Context, w http.ResponseWriter) {
+	cv := ctx.Value(contextKeyCorsOrigin)
+	if cv == nil {
+		return
+	}
+	origin, ok := cv.(string)
+	if !ok {
+		return
+	}
+
+	w.Header().Set("Access-Control-Allow-Origin", origin)
+	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
+	w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
+}
+
+// AuthorizeOIDC checks the Authorization header OIDC token, verifies it and gets the user info
+func AuthorizeOIDC(authorizer Authorizer, allowUnauthorized bool) httptransport.ServerOption {
+	return func(s *httptransport.Server) {
+		httptransport.ServerBefore(
+			func(ctx context.Context, r *http.Request) context.Context {
+				ctx = context.WithValue(ctx, contextProtectedEndpoint, !allowUnauthorized)
+
+				userInfo, err := authorizer.Authorize(r.Header)
+				if err != nil {
+					ctx = context.WithValue(ctx, contextAuthorized, false)
+					ctx = context.WithValue(ctx, contextAuthorizeError, err.Error())
+					return ctx
+				}
+				ctx = context.WithValue(ctx, contextAuthorized, true)
+				ctx = context.WithValue(ctx, contextUserInfo, userInfo)
+				return ctx
+			},
+		)(s)
+	}
+}
+
+// parseQueryParams and store them in context
+func parseQueryParams(s *httptransport.Server) {
+	httptransport.ServerBefore(
+		func(ctx context.Context, r *http.Request) context.Context {
+			return context.WithValue(ctx, contextQueryParams, r.URL.Query())
+		},
+	)(s)
+}
+
+// parseURLParams and store them in context
+func parseURLParams(s *httptransport.Server) {
+	httptransport.ServerBefore(
+		func(ctx context.Context, r *http.Request) context.Context {
+			muxV := mux.Vars(r)
+			qp := url.Values{}
+			for k, v := range muxV {
+				qp.Set(k, v)
+			}
+			return context.WithValue(ctx, contextURLParams, qp)
+		},
+	)(s)
+}
+
+// parseHTTPHeaders and store them in context
+func parseHTTPHeaders(s *httptransport.Server) {
+	httptransport.ServerBefore(
+		func(ctx context.Context, r *http.Request) context.Context {
+			return context.WithValue(ctx, contextHTTPHeaders, r.Header)
+		},
+	)(s)
+}
+
+func encodeJSONRequest(_ context.Context, r *http.Request, request interface{}) error {
+	if request == nil {
+		return nil
+	}
+
+	if urlV, ok := request.(url.Values); ok {
+		r.URL.RawQuery = urlV.Encode()
+		return nil
+	}
+
+	var buf bytes.Buffer
+	if err := json.NewEncoder(&buf).Encode(request); err != nil {
+		return err
+	}
+	r.Body = ioutil.NopCloser(&buf)
+	return nil
+}
+
+func decodeJSONRequest(e HTTPEndpoint) httptransport.DecodeRequestFunc {
+	return func(ctx context.Context, r *http.Request) (interface{}, error) {
+		if e.Method != r.Method {
+			return nil, ErrMethodNotAllowed
+		}
+
+		// Check authorization
+		if ctx.Value(contextProtectedEndpoint) == true {
+			if ctx.Value(contextAuthorized) == false {
+				errString, ok := ctx.Value(contextAuthorizeError).(string)
+				if ok {
+					return nil, errors.Wrap(ErrUnauthorized, errString)
+				}
+				return nil, ErrUnauthorized
+			}
+		}
+
+		// Decode request only if it's expected
+		if e.NewRequest == nil {
+			return nil, nil
+		}
+		req := e.NewRequest()
+		err := json.NewDecoder(r.Body).Decode(req)
+		if err != nil {
+			return nil, errors.Wrap(ErrInvalidJSON, err.Error())
+		}
+
+		return req, nil
+	}
+}
+
+func encodeJSONResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
+	if response == nil {
+		return nil
+	}
+
+	w.Header().Set("Content-Type", "application/json; charset=utf-8")
+	return json.NewEncoder(w).Encode(response)
+}
+
+func decodeOptionsRequest(ctx context.Context, r *http.Request) (interface{}, error) {
+	corsEnabled := ctx.Value(contextKeyCorsOrigin)
+	if corsEnabled == nil {
+		return nil, ErrMethodNotAllowed
+	}
+
+	return nil, nil
+}
+
+func decodeJSONResponse(e HTTPEndpoint) httptransport.DecodeResponseFunc {
+	return func(_ context.Context, r *http.Response) (interface{}, error) {
+		if r.StatusCode != http.StatusOK {
+			strBody, _ := ioutil.ReadAll(r.Body)
+			defer r.Body.Close()
+
+			return nil, errors.Wrapf(ErrHTTPClientError, "status: %v (%s)", r.Status, decodeError(string(strBody)))
+		}
+
+		if e.NewResponse == nil {
+			return nil, nil
+		}
+		resp := e.NewResponse()
+		err := json.NewDecoder(r.Body).Decode(resp)
+		return resp, err
+	}
+}
+
+func errorEncoder(errorStatus ErrorStatus, logger *logger.Logger) httptransport.ErrorEncoder {
+	return func(ctx context.Context, err error, w http.ResponseWriter) {
+		statusCode, statusText := errorStatus.ResponseStatus(err)
+
+		// _ = logger.Log("status", fmt.Sprintf("%d %s", statusCode, statusText))
+		setCORSHeaders(ctx, w)
+		w.Header().Set("Content-Type", "application/json; charset=utf-8")
+		w.WriteHeader(statusCode)
+		_ = json.NewEncoder(w).Encode(errorWrapper{Error: statusText})
+	}
+}
+
+func loggingMiddleware(logger *logger.Logger, errorStatus ErrorStatus) endpoint.Middleware {
+	return func(next endpoint.Endpoint) endpoint.Endpoint {
+		return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+			method := getContextStr(ctx, httptransport.ContextKeyRequestMethod)
+			path := getContextStr(ctx, httptransport.ContextKeyRequestPath)
+			reqID := getReqID(ctx)
+
+			defer func(begin time.Time) {
+				statusCode, statusText := errorStatus.ResponseStatus(err)
+				if err != nil {
+					if statusCode == http.StatusInternalServerError {
+						logger.Error("reqID: %v, err: %v", reqID, err.Error())
+					}
+				}
+				logger.Response(reqID, method, path, statusCode, statusText, time.Since(begin))
+			}(time.Now())
+
+			logger.Request(reqID, method, path)
+
+			response, err = next(ctx, request)
+			return
+		}
+	}
+}
+
+func getContextStr(ctx context.Context, key interface{}) string {
+	if v := ctx.Value(key); v != nil {
+		if s, ok := v.(string); ok {
+			return s
+		}
+	}
+	return ""
+}
+
+func getReqID(ctx context.Context) string {
+	// check if request ID is passed as HTTP header
+	reqID := getContextStr(ctx, httptransport.ContextKeyRequestXRequestID)
+	if reqID == "" {
+		// generate request ID
+		id := uuid.New()
+		reqID = id.String()
+	}
+	return reqID
+}
+
+func metricsDurationMiddleware(duration metrics.Histogram) endpoint.Middleware {
+	return func(next endpoint.Endpoint) endpoint.Endpoint {
+		return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+			defer func(begin time.Time) {
+				if duration != nil {
+					duration.With("success", fmt.Sprint(err == nil)).Observe(time.Since(begin).Seconds())
+				}
+			}(time.Now())
+			return next(ctx, request)
+		}
+	}
+}
+
+type errorWrapper struct {
+	Error string `json:"error"`
+}
+
+// NewHTTPClient returns an HTTP handler that makes a set of endpoints
+func NewHTTPClient(instance string, endpoints HTTPEndpoints, logger *logger.Logger) (ClientEndpoints, error) {
+	if !strings.HasPrefix(instance, "http") {
+		instance = "http://" + instance
+	}
+	u, err := url.Parse(instance)
+	if err != nil {
+		return nil, err
+	}
+
+	ce := ClientEndpoints{}
+
+	for ename, e := range endpoints {
+		ce[ename] = httptransport.NewClient(
+			e.Method,
+			copyURL(u, e.Path),
+			encodeJSONRequest,
+			decodeJSONResponse(e),
+		).Endpoint()
+	}
+
+	return ce, nil
+}
+
+func copyURL(base *url.URL, path string) *url.URL {
+	next := *base
+	next.Path = path
+	return &next
+}
diff --git a/libs/validators/customvalidators.go b/libs/validators/customvalidators.go
new file mode 100644
index 0000000..4b71a7b
--- /dev/null
+++ b/libs/validators/customvalidators.go
@@ -0,0 +1,31 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package customvalidators - enable validation of messages
+*/
+package customvalidators
+
+import (
+	validator "gopkg.in/go-playground/validator.v9"
+)
+
+var (
+	validate *validator.Validate
+	pass     = true
+	fail     = false
+)
diff --git a/lint.sh b/lint.sh
new file mode 100755
index 0000000..7b862e2
--- /dev/null
+++ b/lint.sh
@@ -0,0 +1,7 @@
+set -e
+
+echo "Run go fmt"
+test -z "$(gofmt -s -l . 2>&1 | grep -v vendor | tee /dev/stderr)"
+
+echo "Run go lint"
+golint -set_exit_status $(go list ./...)
diff --git a/open-api.yaml b/open-api.yaml
index e0c16ff..24e7f3f 100644
--- a/open-api.yaml
+++ b/open-api.yaml
@@ -1,131 +1,44 @@
 openapi: 3.0.0
 info:
-  description: Milagro Secure - distributed / decentralized core security services.
   title: Apache Milagro Server
+  description: Milagro Secure - distributed / decentralized core security services. This is the HTTP API specification for the D-TA when it is running no plugins.
   contact:
-    email: howard@qredo.com
+    email: dev@milagro.apache.org
   license:
-    name: Apache Milagro
-  version: 0.0.1
+    name: http://www.apache.org/licenses/LICENSE-2.0
+  version: 1.0.0  
 paths:
-  /identity:
+  /v1/identity:
     post:
-      summary: Create an identity document
+      summary: Create an Identity Document
       tags:
-        - identity
-      operationId: createIdentity
-      # security:
-      # - bearerAuth: []
+        - identity      
       requestBody:
         content:
           application/json:
             schema:
               type: object
               properties:
-                name:
-                  required: true
+                Name:
                   type: string
-                  x-go-name: Name
-                  example: thisNode             
-      responses:
-        '200':
-          description: Successful operation
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/Identity'
-    get:
-       summary: Get a list of identities
-       tags:
-         - identity
-       operationId: getIdentities
-       security:
-        - bearerAuth: []
-       parameters: 
-         - name: page
-           in: query
-           description: current page
-           schema:
-             type: integer
-             default: 0
-         - name: perPage
-           in: query
-           description: number of items to show
-           schema:
-             type: integer
-             default: 10
-         - name: sortBy
-           in: query
-           description: Sort By field. Prefix with "-" for descending
-           schema:
-             type: string
-             enum:
-               - dateCreatedAsc               
-               - dateCreatedDesc               
-       responses:
-         '200':
-           description: Successful Operation
-           content:
-             application/json:
-               schema:
-                 $ref: '#/components/schemas/IdentityList'
-  /identity/{idDocAddress}:
-    get:
-      tags:
-        - identity
-      summary: Get a single identity
-      description: Use a known idDocumentAddress to access a single ID document
-      operationId: getIdentityByID
-      security:
-      - bearerAuth: []
-      parameters:
-        - name: idDocAddress
-          in: path
-          description: IPFS hash address of user id doc
-          required: true
-          schema:
-            type: string
+                  example: ExampleNodeName             
       responses:
         '200':
           description: Successful Operation
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/Identity'
-  /order:
-    post:
-      summary: Create an order for a new secret
-      tags:
-        - order
-      operationId: createsafe
-      # security:
-      # - bearerAuth: []
-      requestBody:
-        content:
-          application/json:
-            schema:
-              type: object
-              properties:
-                beneficiaryIDDOC:
-                  type: string
-                  x-go-name: BeneficiaryIDDOC
-                  example: '"kjhdhdjd"'
-                coin:
-                  type: integer
-                  format: int64
-                  x-go-name: Coin
-                  example: 2
-        x-go-name: Body
-      responses:
-        '200':
-          $ref: '#/components/schemas/safesecret'
+                $ref: '#/components/schemas/CreateIdentityResponse'
+        '400':
+          description: Invalid Request
+          content:
+            text/plain:
+             schema:
+              type: string
     get:
-      summary: Get a list of secrets
+      summary: Get a list of identity documents
       tags:
-        - order
-      operationId: getsafes
-      security:
-      - bearerAuth: []
+       - identity
       parameters: 
         - name: page
           in: query
@@ -145,221 +58,337 @@
           schema:
             type: string
             enum:
-              - dateCreated
-              - dateModified
-              - -dateCreated
-              - -dateModified
+              - dateCreatedAsc               
+              - dateCreatedDesc               
       responses:
         '200':
-          description: Successful operation
+          description: Successful Operation
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/Arrayofsafesecrets'
-  /order/{orderAddress}:
+                $ref: '#/components/schemas/IdentityListResponse'
+        '400':
+          description: Invalid Request
+          content:
+            text/plain:
+              schema:
+                type: string
+  /v1/identity/{IDDocumentCID}:
     get:
-      summary: Get details of a secret in custody
+      summary: Get Details of an Identity
       tags:
-        - order
-      operationId: getsafe
-      security:
-      - bearerAuth: []
-      parameters:
-        - name: safesecretAddress
+        - identity
+      parameters: 
+        - name: IDDocumentCID
           in: path
-          description: IPFS hash address of safe secret doc
+          description: IPFS hash address of Identity Document
           required: true
           schema:
             type: string
       responses:
         '200':
-          $ref: '#/components/schemas/safesecret'
-  /order/secret:
-    post:
-      summary: Release secret
-      tags:
-        - order
-      operationId: createkey
-      # security:
-      # - bearerAuth: []
-      requestBody:
-        content:
-          application/json:
-            schema:
-              type: object
-              properties:
-                partTwosecretDoc:
-                  type: string
-                  # example: QmReoUkzq6dEwdTZqCzNAqiMKPGdY2E3recm2tud1uuqia
-      responses:
-        '200':
-          $ref: '#/components/schemas/keysecret'
-  /order/pairing:
-    post:
-      summary: Generate and issue a type-3 pairing key
-      tags:
-        - order
-      operationId: createsafe
-      # security:
-      # - bearerAuth: []
-      requestBody:
-        content:
-          application/json:
-            schema:
-              type: object
-              properties:
-                beneficiaryIDDOC:
-                  type: string
-                  x-go-name: BeneficiaryIDDOC
-                  example: '"kjhdhdjd"'
-                coin:
-                  type: integer
-                  format: int64
-                  x-go-name: Coin
-                  example: 2
-        x-go-name: Body
-      responses:
-        '200':
-          $ref: '#/components/schemas/safesecret'
-  /fulfill/order:
-    post:
-      summary: Create Public Address
-      tags:
-        - fulfill
-      operationId: fulfillsafe 
-      requestBody:
-        content:
-          application/json:
-            schema:
-              type: object
-              properties:
-                safeDocAddress:
-                  type: string
-                  x-go-name: safeDocAddress
-                  example: Qme5S5xVfGYF46oftiLQDevPAGSKy1aggdtrZvvEdiXuqM
-        x-go-name: Body
-      responses:
-        '200':
-          $ref: '#/components/schemas/safesecret'
-  /fulfill/order/secret:
-    post:
-      summary: Return Private Key
-      tags:
-        - fulfill
-      operationId: fulfillkey
-      requestBody:
-        content:
-          application/json:
-            schema:
-              type: object
-              properties:
-                safeDocAddress:
-                  type: string
-                  x-go-name: keyDocAddress
-                  example: Qme5S5xVfGYF46oftiLQDevPAGSKy1aggdtrZvvEdiXuqM
-        x-go-name: Body
-      responses:
-        '200':
-          $ref: '#/components/schemas/safesecret'
-  /fulfill/order/pairing:
-    post:
-      summary: Return mPIN Key
-      tags:
-        - fulfill
-      operationId: fulfillkey
-      requestBody:
-        content:
-          application/json:
-            schema:
-              type: object
-              properties:
-                safeDocAddress:
-                  type: string
-                  x-go-name: keyDocAddress
-                  example: Qme5S5xVfGYF46oftiLQDevPAGSKy1aggdtrZvvEdiXuqM
-        x-go-name: Body
-      responses:
-        '200':
-          $ref: '#/components/schemas/safesecret'
-  /status:
-    get:
-      description: Test Server Health
-      tags:
-        - system
-      operationId: healthcheck
-      responses:
-        '200':
-          description: Successful operation
+          description: Successful Operation
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/SystemHealth'
+                $ref: '#/components/schemas/Identity'
+        '400':
+          description: Invalid Request
+          content:
+            text/plain:
+              schema:
+                type: string
+  /v1/order:
+    post:
+      summary: Create an order for a new Commitment
+      description: This request will return a Commitment (SECP256 public key) from the Master Fiduciary. The response also includes IPFS hash adresses of the Order Documents passed between the Principal and Master Fiduciary.
+      tags:
+      - order
+      requestBody:
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                BeneficiaryIDDocumentCID:
+                  type: string                  
+                  example: QmZJGAuHEzf3arcEDdRzS4ZVRY1onmQG3NCn9mXEYD4eon
+      responses:
+        '200':
+          description: Successful Operation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/OrderResponse'
+        '400':
+          description: Invalid Request
+          content:
+            text/plain:
+              schema:
+                type: string
+    get:
+      summary: Get a list of orders managed by this D-TA
+      tags: 
+      - order
+      parameters: 
+        - name: page
+          in: query
+          description: current page
+          schema:
+            type: integer
+            default: 0
+        - name: perPage
+          in: query
+          description: number of items to show
+          schema:
+            type: integer
+            default: 10
+        - name: sortBy
+          in: query
+          description: Sort By field. Prefix with "-" for descending
+          schema:
+            type: string
+            enum:
+              - dateCreatedAsc               
+              - dateCreatedDesc
+      responses:
+        '200':
+          description: Succesful Operation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/OrderListResponse'
+        '400':
+          description: Invalid Request
+          content:
+            text/plain:
+             schema:
+              type: string
+  /v1/order/{OrderReference}:
+    get:
+      summary: Get details of an order
+      tags:
+      - order
+      parameters:
+      - name: OrderReference
+        in: path
+        description: Reference for a single order
+        required: true
+        schema:
+          type: string
+      responses:
+        '200':
+          description: Succesful Operation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/GetOrderResponse'
+        '400':
+          description: Invalid Request
+          content:
+            text/plain:
+             schema:
+              type: string
+  /v1/order/secret:
+    post:
+      summary: Returns the SECP256 Secret Key
+      tags:
+        - order
+      requestBody:
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                OrderReference:
+                  type: string                  
+                  example: 9f3ac746-c418-11e9-b78c-acde48001122
+                BeneficiaryIDDocumentCID:
+                  type: string                  
+                  example: QmfWg5GffUEzwahd9hkvdnqTGQs5PfusoEpx3kSDSdG4ze
+      responses:
+        '200':
+          description: Succesful Operation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/OrderSecretResponse'
+        '400':
+          description: Invalid Request
+          content:
+            text/plain:
+             schema:
+              type: string
+  /v1/fulfill/order:
+    post:
+      summary: Create Public Address
+      tags:
+        - fulfill      
+      requestBody:
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                OrderPart1CID:
+                  type: string
+                  example: Qme5S5xVfGYF46oftiLQDevPAGSKy1aggdtrZvvEdiXuqM
+                DocumentCID:
+                  type: string
+                  example: Qme5S5xVfGYF46oftiLQDevPAGSKy1aggdtrZvvEdiXuqM
+      responses:
+        '200':           
+          description: Succesful Operation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/FulfillOrderResponse'
+        '400':
+          description: Invalid Request
+          content:
+            text/plain:
+             schema:
+              type: string
+  /v1/fulfill/order/secret:
+    post:
+      summary: Return Private Key
+      tags:
+        - fulfill      
+      requestBody:
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                OrderPart3CID:
+                  type: string
+                SenderDocumentCID:
+                  type: string                                  
+      responses:
+        '200':
+          description: Succesful Operation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/FulfillOrderSecretResponse'
+        '400':
+          description: Invalid Request
+          content:
+            text/plain:
+             schema:
+              type: string
+  /v1/status:
+    get:
+      description: Test Server Health
+      tags:
+        - system      
+      responses:
+        '200':
+          description: Successful Operation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StatusResponse'
+        '400':
+          description: Invalid Request
+          content:
+            text/plain:
+              schema:
+                type: string
 servers:
-  - url: 'http://localhost:5555'
   - url: 'http://localhost:5556'
-# security:
-#   - bearerAuth: []
+  - url: 'http://localhost:5558' 
 components:
-  securitySchemes:
-    bearerAuth:
-      type: http
-      scheme: bearer
-      bearerFormat: JWT
   schemas:
-    Identity:
-      type: object
-      properties:
-        idDocumentAddress:
-          type: string
-        AuthenticationReference:  
-          type: string
-        BenListenerWalletAddress: 
-          type: string
-        BenSASPubKey:             
-          type: string
-        BenECAddPubKey:           
-          type: string
-        SikePublicKey:            
-          type: string
-        PicnicPublicKey:
-          type: string      
-        Handle:
-          type: string
-        Email:
-          type: string
-        Username:
-          type: string
-        Timestamp:
-          type: integer 
-    IdentityList:
-      type: object
-      items:
-        $ref: '#/components/schemas/IdentityArray'
-    IdentityArray:
-      type: array
-      items: 
-        $ref: '#/components/schemas/Identity'
-    safesecret:
-      type: object
-      properties:
-        safesecretAddress:
-          type: string
-    Arrayofsafesecrets:
-      type: array
-      items:
-        $ref: '#/components/schemas/safesecret'
-    keysecret:
-      type: object
-      properties:
-        secretDocAddress:
-          type: string
-    SystemHealth:
-      type: object
-      properties:
-        timeStamp:
-          type: string
-        testString:
-          type: string
+      CreateIdentityResponse:
+        type: object
+        properties:
+          IDDocumentCID:
+            type: string      
+      IdentityListResponse:
+        type: object
+        properties:
+          IDDocumentList:
+            type: array
+            items: 
+              $ref: '#/components/schemas/Identity'    
+      Identity:
+        type: object
+        properties:
+          IDDocumentCID:
+            type: string
+          AuthenticationReference:  
+            type: string
+          BeneficiaryECPublicKey: 
+            type: string          
+          SikePublicKey:            
+            type: string
+          BlsPublicKey:
+            type: string                
+          Timestamp:
+            type: integer
+      OrderResponse:
+        type: object
+        properties:
+          OrderReference:
+            type: string
+          Commitment:
+            type: string
+          CreatedAt:
+            type: string
+      OrderListResponse:
+        type: object
+        properties:
+          OrderReference:
+            type: array
+            items:
+              type: string
+      GetOrderResponse:
+        type: object
+        properties:
+          Order:
+            type: object
+            properties:
+              Order: 
+                type: string
+              TimeStamp:
+                type: integer                            
+      OrderSecretResponse:
+        type: object
+        properties:
+          Secret:
+            type: string
+          Commitment:
+            type: string
+          OrderReference:
+            type: string
+      FulfillOrderResponse:
+        type: object
+        properties: 
+          OrderPart2CID:
+            type: string
+      FulfillOrderSecretResponse:
+        type: object
+        properties:
+          OrderPart4CID:
+            type: string
+      StatusResponse:
+        type: object
+        properties:
+          application:
+            type: string
+          apiVersion:
+              type: string
+          extensionVendor:
+            type: string
+          nodeCID:
+            type: string
+          timeStamp:
+            type: string
+          plugin:
+            type: string
+          nodeType:
+            type: string
 tags:
   - name: identity
     description: Actors in the system
@@ -367,12 +396,18 @@
       url: 'https://milagro.apache.org/docs/milagro-intro/'
       description: Apache Milagro Docs
   - name: order
-    description: Send Requests to Principal Node
+    description: Communication between Principals and Master Fiduciaries
     externalDocs:
       url: 'https://milagro.apache.org/docs/milagro-intro/'
       description: Apache Milagro Docs
   - name: fulfill
-    description: Actions performed by the Fiduciary node
+    description: Actions performed by the Master Fiduciary
     externalDocs:
       url: 'https://milagro.apache.org/docs/milagro-intro/'
       description: Apache Milagro Docs
+  - name: system
+    description: Test Server Health
+    externalDocs:
+      url: 'https://milagro.apache.org/docs/milagro-intro/'
+      description: Apache Milagro Docs
+  
diff --git a/pkg/api/client.go b/pkg/api/client.go
new file mode 100644
index 0000000..00d336d
--- /dev/null
+++ b/pkg/api/client.go
@@ -0,0 +1,91 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package api - service integration and contract types
+*/
+package api
+
+import (
+	"context"
+	"net/http"
+
+	"github.com/apache/incubator-milagro-dta/libs/logger"
+	"github.com/apache/incubator-milagro-dta/libs/transport"
+)
+
+var (
+	apiVersion = "v1"
+)
+
+//ClientService - enables service to be mocked
+type ClientService interface {
+	FulfillOrder(req *FulfillOrderRequest) (*FulfillOrderResponse, error)
+	FulfillOrderSecret(req *FulfillOrderSecretRequest) (*FulfillOrderSecretResponse, error)
+}
+
+// MilagroClientService - implements Service Interface
+type MilagroClientService struct {
+	endpoints transport.ClientEndpoints
+}
+
+// ClientEndpoints return only the exported endpoints
+func ClientEndpoints() transport.HTTPEndpoints {
+	return transport.HTTPEndpoints{
+		"FulfillOrder": {
+			Path:        "/" + apiVersion + "/fulfill/order",
+			Method:      http.MethodPost,
+			NewRequest:  func() interface{} { return &FulfillOrderRequest{} },
+			NewResponse: func() interface{} { return &FulfillOrderResponse{} },
+		},
+		"FulfillOrderSecret": {
+			Path:        "/" + apiVersion + "/fulfill/order/secret",
+			Method:      http.MethodPost,
+			NewRequest:  func() interface{} { return &FulfillOrderSecretRequest{} },
+			NewResponse: func() interface{} { return &FulfillOrderSecretResponse{} },
+		},
+	}
+}
+
+// NewHTTPClient returns Service backed by an HTTP server living at the remote instance
+func NewHTTPClient(instance string, logger *logger.Logger) (ClientService, error) {
+	clientEndpoints, err := transport.NewHTTPClient(instance, ClientEndpoints(), logger)
+	return MilagroClientService{clientEndpoints}, err
+
+}
+
+//FulfillOrder -
+func (c MilagroClientService) FulfillOrder(req *FulfillOrderRequest) (*FulfillOrderResponse, error) {
+	endpoint := c.endpoints["FulfillOrder"]
+	d, err := endpoint(context.Background(), req)
+	if err != nil {
+		return nil, err
+	}
+	r := d.(*FulfillOrderResponse)
+	return r, nil
+}
+
+//FulfillOrderSecret -
+func (c MilagroClientService) FulfillOrderSecret(req *FulfillOrderSecretRequest) (*FulfillOrderSecretResponse, error) {
+	endpoint := c.endpoints["FulfillOrderSecret"]
+	d, err := endpoint(context.Background(), req)
+	if err != nil {
+		return nil, err
+	}
+	r := d.(*FulfillOrderSecretResponse)
+	return r, nil
+}
diff --git a/pkg/api/proto.go b/pkg/api/proto.go
new file mode 100644
index 0000000..d0ca577
--- /dev/null
+++ b/pkg/api/proto.go
@@ -0,0 +1,171 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package api
+
+/*
+ For validation see:
+ https://github.com/go-playground/validator
+
+*/
+
+import (
+	"time"
+)
+
+//CreateIdentityRequest -
+type CreateIdentityRequest struct {
+	Name      string            `json:"name,omitempty" validate:"required,alphanum"`
+	Extension map[string]string `json:"extension,omitempty"`
+}
+
+//CreateIdentityResponse -
+type CreateIdentityResponse struct {
+	IDDocumentCID string            `json:"idDocumentCID,omitempty"`
+	Extension     map[string]string `json:"extension,omitempty"`
+}
+
+//GetIdentityRequest -
+type GetIdentityRequest struct {
+	IDDocumentCID string `json:"idDocumentCID"  validate:"IPFS"`
+}
+
+//GetIdentityResponse -
+type GetIdentityResponse struct {
+	IDDocumentCID           string            `json:"idDocumentCID,omitempty"`
+	AuthenticationReference string            `json:"authenticationReference,omitempty"`
+	BeneficiaryECPublicKey  string            `json:"beneficiaryECPublicKey,omitempty"`
+	SikePublicKey           string            `json:"sikePublicKey,omitempty"`
+	BLSPublicKey            string            `json:"blsPublicKey,omitempty"`
+	Handle                  string            `json:"handle,omitempty"`
+	Email                   string            `json:"email,omitempty"`
+	Username                string            `json:"string,omitempty"`
+	Timestamp               int64             `json:"timestamp,omitempty"`
+	Extension               map[string]string `json:"extension,omitempty"`
+}
+
+//IdentityListRequest -
+type IdentityListRequest struct {
+	Page      int               `json:"page,omitempty"`
+	PerPage   int               `json:"perPage,omitempty"`
+	SortBy    string            `json:"sortBy,omitempty"`
+	Extension map[string]string `json:"extension,omitempty"`
+}
+
+//IdentityListResponse -
+type IdentityListResponse struct {
+	IDDocumentList []GetIdentityResponse `json:"idDocumentList,omitempty"`
+	Extension      map[string]string     `json:"extension,omitempty"`
+}
+
+//OrderRequest -
+type OrderRequest struct {
+	// BeneficiaryIDDocumentCID string            `json:"BeneficiaryIDDocumentCID,omitempty" validate:"omitempty,IPFS"`
+	BeneficiaryIDDocumentCID string            `json:"beneficiaryIDDocumentCID,omitempty"`
+	Extension                map[string]string `json:"extension,omitempty"`
+}
+
+//OrderResponse -
+type OrderResponse struct {
+	// OrderPart1CID  string            `json:"orderPart1CID,omitempty" validate:"omitempty,IPFS"`
+	// OrderPart2CID  string            `json:"orderPart2CID,omitempty" validate:"omitempty,IPFS"`
+	OrderReference string            `json:"orderReference,omitempty" validate:"omitempty"`
+	Commitment     string            `json:"commitment,omitempty"`
+	CreatedAt      int64             `json:"createdAt,omitempty"`
+	Extension      map[string]string `json:"extension,omitempty"`
+}
+
+//OrderListRequest -
+type OrderListRequest struct {
+	Page      int               `json:"page,omitempty"`
+	PerPage   int               `json:"perPage,omitempty"`
+	SortBy    string            `json:"sortBy,omitempty"`
+	Extension map[string]string `json:"extension,omitempty"`
+}
+
+//OrderListResponse -
+type OrderListResponse struct {
+	OrderReference []string          `json:"orderReference,omitempty"`
+	Extension      map[string]string `json:"extension,omitempty"`
+}
+
+//GetOrderRequest -
+type GetOrderRequest struct {
+	OrderReference string            `json:"orderReference,omitempty"`
+	Extension      map[string]string `json:"extension,omitempty"`
+}
+
+//GetOrderResponse -
+type GetOrderResponse struct {
+	OrderCID  string            `json:"orderCID,omitempty"`
+	Order     string            `json:"order,omitempty"`
+	Timestamp int64             `json:"timestamp,omitempty"`
+	Extension map[string]string `json:"extension,omitempty"`
+}
+
+//OrderSecretRequest -
+type OrderSecretRequest struct {
+	OrderReference           string            `json:"orderReference,omitempty" validate:"omitempty"`
+	BeneficiaryIDDocumentCID string            `json:"beneficiaryIDDocumentCID,omitempty" validate:"omitempty,IPFS"`
+	Extension                map[string]string `json:"extension,omitempty"`
+}
+
+//OrderSecretResponse -
+type OrderSecretResponse struct {
+	Secret         string            `json:"secret,omitempty"`
+	Commitment     string            `json:"commitment,omitempty"`
+	OrderReference string            `json:"orderReference,omitempty" validate:"omitempty"`
+	Extension      map[string]string `json:"extension,omitempty"`
+}
+
+//FulfillOrderSecretRequest -
+type FulfillOrderSecretRequest struct {
+	OrderPart3CID     string            `json:"orderPart3CID,omitempty" validate:"IPFS"`
+	SenderDocumentCID string            `json:"documentCID,omitempty" validate:"IPFS"`
+	Extension         map[string]string `json:"extension,omitempty"`
+}
+
+//FulfillOrderSecretResponse -
+type FulfillOrderSecretResponse struct {
+	OrderPart4CID string            `json:"orderPart4CID,omitempty"`
+	Extension     map[string]string `json:"extension,omitempty"`
+}
+
+//FulfillOrderRequest -
+type FulfillOrderRequest struct {
+	OrderPart1CID string            `json:"orderPart1CID,omitempty" validate:"IPFS"`
+	DocumentCID   string            `json:"documentCID,omitempty" validate:"IPFS"`
+	Extension     map[string]string `json:"extension,omitempty"`
+}
+
+//FulfillOrderResponse -
+type FulfillOrderResponse struct {
+	OrderPart2CID string            `json:"orderPart2CID,omitempty"`
+	Extension     map[string]string `json:"extension,omitempty"`
+}
+
+//StatusResponse -
+type StatusResponse struct {
+	Application     string            `json:"application,omitempty"`
+	TimeStamp       time.Time         `json:"timeStamp,omitempty"`
+	APIVersion      string            `json:"apiVersion,omitempty"`
+	NodeCID         string            `json:"nodeCID,omitempty"`
+	ExtensionVendor string            `json:"extensionVendor,omitempty"`
+	Extension       map[string]string `json:"extension,omitempty"`
+	Plugin          string            `json:"plugin,omitempty"`
+	NodeType        string            `json:"nodeType,omitempty"`
+}
diff --git a/pkg/bitcoinplugin/coin.go b/pkg/bitcoinplugin/coin.go
new file mode 100644
index 0000000..b6b55ac
--- /dev/null
+++ b/pkg/bitcoinplugin/coin.go
@@ -0,0 +1,134 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package bitcoinplugin
+
+/*
+The coin constans are defined here
+https://github.com/satoshilabs/slips/blob/master/slip-0044.md
+https://www.thepolyglotdeveloper.com/2018/02/generate-cryptocurrency-private-keys-public-addresses-golang/
+https://godoc.org/bitbucket.org/dchapes/ripple/crypto/rkey#example-package--Address
+
+*/
+
+import (
+	"encoding/hex"
+
+	"github.com/btcsuite/btcd/btcec"
+	"github.com/btcsuite/btcd/chaincfg"
+	"github.com/btcsuite/btcutil"
+	"github.com/pkg/errors"
+)
+
+var (
+	errUnsupportedCoin = errors.New("unsupported coin")
+)
+
+//Network list of Cryptocurrency networks
+type Network struct {
+	name        string
+	symbol      string
+	xpubkey     byte
+	xprivatekey byte
+}
+
+var network = map[string]Network{
+	"btc":     {name: "bitcoin", symbol: "btc", xpubkey: 0x00, xprivatekey: 0x80},
+	"testbtc": {name: "bitcoin testnet", symbol: "btc", xpubkey: 0x6f, xprivatekey: 0xef},
+}
+
+func addressForPublicKey(publicKey string, coinType int) (string, error) {
+	pubK, _ := hex.DecodeString(publicKey)
+	pubKeyBytes := []byte(pubK)
+
+	switch coinType {
+	case 0: //Bitcoin
+		return network["btc"].pubkeyToAddress(pubKeyBytes, false)
+	case 1: //Bitcoin Testnet
+		return network["testbtc"].pubkeyToAddress(pubKeyBytes, false)
+	}
+	return "", errUnsupportedCoin
+}
+
+func addressForPrivateKey(privateKey []byte, coinType int) (string, error) {
+	switch coinType {
+	case 0: //Bitcoin
+		return network["btc"].privkeyToAddress(privateKey, false)
+	case 1: //Bitcoin Testnet
+		return network["testbtc"].privkeyToAddress(privateKey, false)
+	}
+	return "", errUnsupportedCoin
+}
+
+func (network Network) privkeyToAddress(privateKey []byte, compressed bool) (string, error) {
+	wif, _ := network.createPrivateKeyFromBytes(privateKey)
+	address, _ := network.getAddress(wif)
+	if compressed == true {
+		address.SetFormat(btcutil.PKFCompressed)
+	} else {
+		address.SetFormat(btcutil.PKFUncompressed)
+	}
+	return address.EncodeAddress(), nil
+}
+
+func (network Network) pubkeyToAddress(publicKey []byte, compressed bool) (string, error) {
+	mainNetAddr, err := btcutil.NewAddressPubKey(publicKey, network.getNetworkParams())
+	if err != nil {
+		return "", errors.Wrap(err, "Failed to decode Public Key")
+	}
+	if compressed == true {
+		mainNetAddr.SetFormat(btcutil.PKFCompressed)
+	} else {
+		mainNetAddr.SetFormat(btcutil.PKFUncompressed)
+	}
+	return mainNetAddr.EncodeAddress(), nil
+}
+
+func (network Network) getNetworkParams() *chaincfg.Params {
+	networkParams := &chaincfg.MainNetParams
+	networkParams.PubKeyHashAddrID = network.xpubkey
+	networkParams.PrivateKeyID = network.xprivatekey
+	return networkParams
+}
+
+func (network Network) createPrivateKeyFromBytes(privateKey []byte) (*btcutil.WIF, error) {
+	secret, _ := btcec.PrivKeyFromBytes(btcec.S256(), privateKey)
+	return btcutil.NewWIF(secret, network.getNetworkParams(), true)
+}
+
+func (network Network) createPrivateKey() (*btcutil.WIF, error) {
+	secret, err := btcec.NewPrivateKey(btcec.S256())
+	if err != nil {
+		return nil, err
+	}
+	return btcutil.NewWIF(secret, network.getNetworkParams(), true)
+}
+
+func (network Network) importWIF(wifStr string) (*btcutil.WIF, error) {
+	wif, err := btcutil.DecodeWIF(wifStr)
+	if err != nil {
+		return nil, err
+	}
+	if !wif.IsForNet(network.getNetworkParams()) {
+		return nil, errors.New("The WIF string is not valid for the `" + network.name + "` network")
+	}
+	return wif, nil
+}
+
+func (network Network) getAddress(wif *btcutil.WIF) (*btcutil.AddressPubKey, error) {
+	return btcutil.NewAddressPubKey(wif.PrivKey.PubKey().SerializeUncompressed(), network.getNetworkParams())
+}
diff --git a/pkg/bitcoinplugin/coin_test.go b/pkg/bitcoinplugin/coin_test.go
new file mode 100644
index 0000000..30b9af0
--- /dev/null
+++ b/pkg/bitcoinplugin/coin_test.go
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package bitcoinplugin
+
+import (
+	"encoding/hex"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func Test_AddressForPublicKey(t *testing.T) {
+	pubKey := "0487DBF8D88A860270AB7D689EB44C2DFFF768D2F7851A753FACF356978B82CE4ACB5C9B061FC884668D9BB46B83D6BF180A2099F397142785D2E03DACCEF03D01"
+	btcAddress, err := addressForPublicKey(pubKey, 0)
+	assert.Nil(t, err, "Error should be nil")
+	assert.Equal(t, "1MwiNcg3v19BLeawNJKL8L18m4Tzmtua5T", btcAddress)
+
+	btcTestNetAddress, err := addressForPublicKey(pubKey, 1)
+	assert.Nil(t, err, "Error should be nil")
+	assert.Equal(t, "n2Tfffm2j2aS7m4Z5sHhxFDTd44hfnDhPz", btcTestNetAddress)
+
+	_, err = addressForPublicKey(pubKey, 9999999999)
+	assert.EqualError(t, err, "unsupported coin")
+}
+func Test_AddressForPrivateKey(t *testing.T) {
+	privKey, _ := hex.DecodeString("EB354D4B18E0B4AC6E63369F33D0CFFE7F3C09101D29678877A6CE8879D7E152")
+	btcAddress, err := addressForPrivateKey(privKey, 0)
+	assert.Nil(t, err, "Error should be nil")
+	assert.Equal(t, "1MwiNcg3v19BLeawNJKL8L18m4Tzmtua5T", btcAddress)
+
+	btcTestNetAddress, err := addressForPrivateKey(privKey, 1)
+	assert.Nil(t, err, "Error should be nil")
+	assert.Equal(t, "n2Tfffm2j2aS7m4Z5sHhxFDTd44hfnDhPz", btcTestNetAddress)
+
+	_, err = addressForPrivateKey(privKey, 9999999999)
+	assert.EqualError(t, err, "unsupported coin")
+}
diff --git a/pkg/bitcoinplugin/helpers.go b/pkg/bitcoinplugin/helpers.go
new file mode 100644
index 0000000..eb65167
--- /dev/null
+++ b/pkg/bitcoinplugin/helpers.go
@@ -0,0 +1,225 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package bitcoinplugin
+
+import (
+	"crypto/sha256"
+	"encoding/hex"
+	"fmt"
+	"math/big"
+
+	"github.com/apache/incubator-milagro-dta/libs/cryptowallet"
+	"github.com/apache/incubator-milagro-dta/libs/documents"
+	"github.com/apache/incubator-milagro-dta/pkg/common"
+	"github.com/btcsuite/btcd/btcec"
+	"github.com/pkg/errors"
+)
+
+func deriveFinalPrivateKey(s *Service, order documents.OrderDoc, beneficiariesSikeSK []byte, beneficiariesSeed []byte, beneficiaryIDDocumentCID string, nodeID string, signingBlsPK []byte) (string, error) {
+	if beneficiaryIDDocumentCID != "" {
+		//we are using the beneficiary specified in order Part 3
+		beneficiaryBlob := order.OrderPart3.BeneficiaryEncryptedData
+
+		//Decrypt the Envelope intented for the Beneficiary
+		privateKeyPart1of1, err := adhocEncryptedEnvelopeDecode(s, beneficiariesSikeSK, beneficiaryBlob, beneficiaryIDDocumentCID, signingBlsPK)
+		if err != nil {
+			return "", err
+		}
+		//Calculate the final private key by Eliptical Key addition of both parts
+		privateKeyPart2of2 := order.OrderDocument.OrderPart4.Secret
+
+		finalPrivateKey, err := addPrivateKeys(privateKeyPart1of1, privateKeyPart2of2)
+
+		if err != nil {
+			return "", err
+		}
+		return finalPrivateKey, err
+	}
+
+	//we are using the beneficiary specified in the order part 1
+	privateKeyPart2of2 := order.OrderDocument.OrderPart4.Secret
+	// if order.OrderDocument.BeneficiaryCID != nodeID {
+	// 	//need to forward this data to the beneficiary to complete redemption
+	// 	return "", errors.New("Currently beneficiary must be the same as the Principal")
+	// }
+	//restore the Seed
+	_, _, ecAddPrivateKey, err := cryptowallet.Bip44Address(beneficiariesSeed, cryptowallet.CoinTypeBitcoinMain, 0, 0, 0)
+	if err != nil {
+		return "", err
+	}
+	privateKeyPart1of1 := hex.EncodeToString(ecAddPrivateKey.Serialize())
+	finalPrivateKey, err := addPrivateKeys(privateKeyPart1of1, privateKeyPart2of2)
+	if err != nil {
+		return "", err
+	}
+	return finalPrivateKey, err
+
+}
+
+func adhocEncryptedEnvelopeEncode(s *Service, nodeID string, beneficiaryIDDocumentCID string, order documents.OrderDoc, blsSK []byte) ([]byte, error) {
+	//Regenerate the original Princaipal Priv Key based on Order
+	if beneficiaryIDDocumentCID == "" {
+		//beneficiaryIDDocumentCID is empty when it was passed in the Inital Deposit Order
+		return nil, nil
+	}
+	seedHex, err := common.RetrieveSeed(s.Store, order.Reference)
+	if err != nil {
+		return nil, err
+	}
+	seedOrderModifier := order.OrderDocument.OrderPart2.PreviousOrderCID
+	seed, err := hex.DecodeString(seedHex)
+	if err != nil {
+		return nil, err
+	}
+	concatenatedSeeds := append(seed, seedOrderModifier...)
+	finalSeed := sha256.Sum256(concatenatedSeeds)
+	finalSeedHex := hex.EncodeToString(finalSeed[:])
+	privateKeyPart1of2, err := cryptowallet.RedeemSecret(finalSeedHex)
+	if err != nil {
+		return nil, err
+	}
+	beneficiaryIDDocument, err := common.RetrieveIDDocFromIPFS(s.Ipfs, beneficiaryIDDocumentCID)
+	if err != nil {
+		return nil, err
+	}
+	secretBody := &documents.SimpleString{Content: privateKeyPart1of2}
+	header := &documents.Header{}
+	recipients := map[string]documents.IDDoc{
+		beneficiaryIDDocumentCID: beneficiaryIDDocument,
+	}
+	docEnv, err := documents.Encode(nodeID, nil, secretBody, header, blsSK, recipients)
+	if err != nil {
+		return nil, err
+	}
+	return docEnv, err
+}
+
+func adhocEncryptedEnvelopeDecode(s *Service, sikeSK []byte, beneficiaryBlob []byte, beneficiaryIDDocumentCID string, signingBlsPK []byte) (string, error) {
+	//Regenerate the original Principal Priv Key based on Order
+	secretBody := &documents.SimpleString{}
+	_, err := documents.Decode(beneficiaryBlob, "INTERNAL", sikeSK, beneficiaryIDDocumentCID, nil, secretBody, signingBlsPK)
+	if err != nil {
+		return "", err
+	}
+	return secretBody.Content, err
+}
+
+func generateFinalPubKey(s *Service, pubKeyPart2of2 string, order documents.OrderDoc) (string, string, error) {
+	beneficiaryIDDocumentCID := order.OrderDocument.BeneficiaryCID
+	coinType := order.Coin
+	var pubKeyPart1of2 string
+
+	if beneficiaryIDDocumentCID == "" {
+		//There is no beneficiary ID so we do it all locally based on
+		//Retrieve the Local Seed
+		seedHex, err := common.RetrieveSeed(s.Store, order.Reference)
+		if err != nil {
+			return "", "", err
+		}
+		seedOrderModifier := order.OrderDocument.OrderPart2.PreviousOrderCID
+		seed, err := hex.DecodeString(seedHex)
+		if err != nil {
+			return "", "", err
+		}
+		concatenatedSeeds := append(seed, seedOrderModifier...)
+		finalSeed := sha256.Sum256(concatenatedSeeds)
+		finalSeedHex := hex.EncodeToString(finalSeed[:])
+		//Use HD Wallet to obtain the local Public Key
+		pubKeyPart1of2, err = cryptowallet.RedeemPublicKey(finalSeedHex)
+
+		if err != nil {
+			return "", "", err
+		}
+	}
+
+	if beneficiaryIDDocumentCID != "" {
+		//There is a BeneficiaryID use it to generate the key
+		//Get beneficiary's identity out of IPFS
+		id := &documents.IDDoc{}
+		rawDocI, err := s.Ipfs.Get(beneficiaryIDDocumentCID)
+		if err != nil {
+			return "", "", errors.Wrapf(err, "Read identity Doc")
+		}
+		err = documents.DecodeIDDocument(rawDocI, beneficiaryIDDocumentCID, id)
+		if err != nil {
+			return "", "", err
+		}
+		pubKeyPart1of2 = hex.EncodeToString(id.BeneficiaryECPublicKey)
+	}
+
+	finalPublicKey, err := addPublicKeys(pubKeyPart2of2, pubKeyPart1of2)
+
+	if err != nil {
+		return "", "", err
+	}
+	addressForPublicKey, err := addressForPublicKey(finalPublicKey, int(coinType))
+	if err != nil {
+		return "", "", err
+	}
+	return finalPublicKey, addressForPublicKey, nil
+
+}
+
+//AddPrivateKeys Perform eliptical key additon on 2 privates keys
+func addPrivateKeys(key1 string, key2 string) (string, error) {
+	curveOrder := new(big.Int)
+	curveOrder.SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
+	priv1 := new(big.Int)
+	priv2 := new(big.Int)
+	priv3 := new(big.Int)
+	priv1.SetString(key1, 16)
+	priv2.SetString(key2, 16)
+	priv3.Add(priv1, priv2)
+	if curveOrder.Cmp(priv3) == -1 {
+		priv3.Sub(priv3, curveOrder)
+	}
+	priv4 := fmt.Sprintf("%064x", priv3)
+	return priv4, nil
+}
+
+//AddPublicKeys Perform eliptical key addition on 2 public keys
+func addPublicKeys(key1 string, key2 string) (string, error) {
+	pub1Hex, err := hex.DecodeString(key1)
+	if err != nil {
+		return "", errors.Wrap(err, "Failed to hex decode String")
+	}
+	dpub1, err := btcec.ParsePubKey(pub1Hex, btcec.S256())
+	if err != nil {
+		return "", errors.Wrap(err, "Failed to Parse Public Key")
+	}
+	pub2Hex, err := hex.DecodeString(key2)
+	if err != nil {
+		return "", errors.Wrap(err, "Failed to hex decode String")
+	}
+	dpub2, err := btcec.ParsePubKey(pub2Hex, btcec.S256())
+	if err != nil {
+		return "", errors.Wrap(err, "Failed to Parse Public Key")
+	}
+	x, y := btcec.S256().Add(dpub1.X, dpub1.Y, dpub2.X, dpub2.Y)
+	comp := fmt.Sprintf("04%064X%064X", x, y)
+	compByte, err := hex.DecodeString(comp)
+	if err != nil {
+		return "", err
+	}
+	pubKey, err := btcec.ParsePubKey([]byte(compByte), btcec.S256())
+	if err != nil {
+		return "", err
+	}
+	pubKeyString := hex.EncodeToString(pubKey.SerializeCompressed())
+	return pubKeyString, nil
+}
diff --git a/pkg/bitcoinplugin/helpers_test.go b/pkg/bitcoinplugin/helpers_test.go
new file mode 100644
index 0000000..6a32e95
--- /dev/null
+++ b/pkg/bitcoinplugin/helpers_test.go
@@ -0,0 +1,47 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package bitcoinplugin
+
+import (
+	"encoding/hex"
+	"testing"
+
+	"github.com/btcsuite/btcd/btcec"
+	"github.com/stretchr/testify/assert"
+)
+
+func Test_AddKeys(t *testing.T) {
+	privKey1, _ := btcec.NewPrivateKey(btcec.S256())
+	privKey2, _ := btcec.NewPrivateKey(btcec.S256())
+	privKey1Str := hex.EncodeToString(privKey1.Serialize())
+	privKey2Str := hex.EncodeToString(privKey2.Serialize())
+
+	pubKey1 := btcec.PublicKey(privKey1.ToECDSA().PublicKey)
+	pubKey2 := btcec.PublicKey(privKey2.ToECDSA().PublicKey)
+	pubKey1Str := hex.EncodeToString(pubKey1.SerializeUncompressed())
+	pubKey2Str := hex.EncodeToString(pubKey2.SerializeUncompressed())
+
+	//run Additions
+	privAdd, _ := addPrivateKeys(privKey1Str, privKey2Str)
+	pubAdd, _ := addPublicKeys(pubKey1Str, pubKey2Str)
+
+	privAddBytes, _ := hex.DecodeString(privAdd)
+	_, pubKeyFromPrivate := btcec.PrivKeyFromBytes(btcec.S256(), privAddBytes)
+	pubKeyFromPrivateString := hex.EncodeToString(pubKeyFromPrivate.SerializeCompressed())
+	assert.Equal(t, pubKeyFromPrivateString, pubAdd, "Addition failed")
+}
diff --git a/pkg/bitcoinplugin/open-api.yaml b/pkg/bitcoinplugin/open-api.yaml
new file mode 100644
index 0000000..92d8f9b
--- /dev/null
+++ b/pkg/bitcoinplugin/open-api.yaml
@@ -0,0 +1,110 @@
+openapi: 3.0.0
+info:
+  title: Apache Milagro D-TA Bitcoin Plugin
+  description: Returns a Bitcoin Address. This specification only shows endpoints that vary from the standard Milagro REST API
+  contact:
+    email: dev@milagro.apache.org
+  license:
+    name: http://www.apache.org/licenses/LICENSE-2.0
+  version: 1.0.0  
+paths:
+  /v1/order:
+    post:
+      summary: Create an order for a new BitCoin Address
+      description: This request will return a Bitcoin Public Address. Coin type 0 = testnet Coint type 1 = Mainnet
+      tags:
+      - order
+      requestBody:
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                beneficiaryIDDocumentCID:
+                  type: string                                    
+                extension:
+                  type: object
+                  properties:
+                    coin:
+                      type: string                    
+                      example: "0"
+      responses:
+        '200':
+          description: Successful Operation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/OrderResponse'
+        '400':
+          description: Invalid Request
+          content:
+            text/plain:
+              schema:
+                type: string    
+  /v1/order/secret:
+    post:
+      summary: Returns the Bitcoin secret key that can be used to sign transactions
+      tags:
+        - order
+      requestBody:
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                orderReference:
+                  type: string                                    
+                beneficiaryIDDocumentCID:
+                  type: string                                    
+      responses:
+        '200':
+          description: Succesful Operation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/OrderSecretResponse'
+        '400':
+          description: Invalid Request
+          content:
+            text/plain:
+             schema:
+              type: string
+servers:
+  - url: 'http://localhost:5556'
+  - url: 'http://localhost:5558' 
+components:
+  schemas:
+      OrderResponse:
+        type: object
+        properties:
+          orderReference:
+            type: string
+          commitment:
+            type: string
+          createdAt:
+            type: string
+          extension:
+            type: object
+            properties:
+              address:
+                type: string                               
+      OrderSecretResponse:
+        type: object
+        properties:
+          secret:
+            type: string
+          commitment:
+            type: string
+          orderReference:
+            type: string
+          extension:
+            type: object
+            properties:
+              address:
+                type: string
+tags:
+  - name: order
+    description: Communication between Principals and Master Fiduciaries
+    externalDocs:
+      url: 'https://milagro.apache.org/docs/milagro-intro/'
+      description: Apache Milagro Docs
\ No newline at end of file
diff --git a/pkg/bitcoinplugin/service.go b/pkg/bitcoinplugin/service.go
new file mode 100644
index 0000000..f087855
--- /dev/null
+++ b/pkg/bitcoinplugin/service.go
@@ -0,0 +1,140 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package bitcoinplugin - Milagro D-TA plugin that generates bitcoin addresses
+*/
+package bitcoinplugin
+
+import (
+	"strconv"
+
+	"github.com/apache/incubator-milagro-dta/libs/cryptowallet"
+	"github.com/apache/incubator-milagro-dta/libs/documents"
+	"github.com/apache/incubator-milagro-dta/pkg/api"
+	"github.com/apache/incubator-milagro-dta/pkg/common"
+	"github.com/apache/incubator-milagro-dta/pkg/defaultservice"
+
+	"github.com/pkg/errors"
+)
+
+var (
+	extensionVendor = "Milagro"
+	pluginName      = "bitcoinwallet"
+)
+
+// Service is the Milagro bitcoin service
+type Service struct {
+	defaultservice.Service
+}
+
+// NewService returns a Milagro implementation of Service
+func NewService() *Service {
+	return &Service{}
+}
+
+// Name of the plugin
+func (s *Service) Name() string {
+	return pluginName
+}
+
+// Vendor of the plugin
+func (s *Service) Vendor() string {
+	return extensionVendor
+}
+
+// ValidateOrderRequest checks if the Coin type is valid
+func (s *Service) ValidateOrderRequest(req *api.OrderRequest) error {
+	if _, err := strconv.ParseInt(req.Extension["coin"], 10, 64); err != nil {
+		return errors.Wrap(err, "Failed to Parse Coin Type")
+	}
+
+	return nil
+}
+
+//ValidateOrderSecretRequest - checks incoming OrderSecret fields for Error, comparing to the Original Order
+func (s *Service) ValidateOrderSecretRequest(req *api.OrderSecretRequest, order documents.OrderDoc) error {
+	//These are deliberately overly long winded, but it makes the case I'm trapping more obvious to the reader
+
+	//There is no beneficiary supplided in either the Deposit or Redemption
+	if order.BeneficiaryCID == "" && req.BeneficiaryIDDocumentCID == "" {
+		return errors.New("Beneficiary must be supplied")
+	}
+
+	//A beneficiary is specified in both, but they aren't the same
+	if order.BeneficiaryCID != "" && req.BeneficiaryIDDocumentCID != "" && order.BeneficiaryCID != req.BeneficiaryIDDocumentCID {
+		return errors.New("Beneficiaries in order & order/secret don't match")
+	}
+
+	//order & order/secret beneficiary are the same order/secret is not required - discard
+	if order.BeneficiaryCID != "" && req.BeneficiaryIDDocumentCID != "" && order.BeneficiaryCID == req.BeneficiaryIDDocumentCID {
+		req.BeneficiaryIDDocumentCID = ""
+	}
+	return nil
+}
+
+// PrepareOrderPart1 adds the coin type to the order
+func (s *Service) PrepareOrderPart1(order *documents.OrderDoc, reqExtension map[string]string) (fulfillExtension map[string]string, err error) {
+	coin, err := strconv.ParseInt(reqExtension["coin"], 10, 64)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to Parse Coin Type")
+	}
+
+	order.Coin = coin
+	return nil, nil
+}
+
+// PrepareOrderResponse gets the updated order and returns the commitment and extension
+func (s *Service) PrepareOrderResponse(orderPart2 *documents.OrderDoc, reqExtension, fulfillExtension map[string]string) (commitment string, extension map[string]string, err error) {
+	pubKeyPart2of2 := orderPart2.OrderPart2.CommitmentPublicKey
+	finalPublicKey, cryptoAddress, err := generateFinalPubKey(s, pubKeyPart2of2, *orderPart2)
+
+	return finalPublicKey, map[string]string{"address": cryptoAddress}, nil
+}
+
+// ProduceBeneficiaryEncryptedData -
+func (s *Service) ProduceBeneficiaryEncryptedData(blsSK []byte, order *documents.OrderDoc, req *api.OrderSecretRequest) (encrypted []byte, extension map[string]string, err error) {
+
+	enc, err := adhocEncryptedEnvelopeEncode(s, s.NodeID(), req.BeneficiaryIDDocumentCID, *order, blsSK)
+	return enc, nil, err
+}
+
+// ProduceFinalSecret -
+func (s *Service) ProduceFinalSecret(seed, sikeSK []byte, order, orderPart4 *documents.OrderDoc, req *api.OrderSecretRequest, fulfillSecretRespomse *api.FulfillOrderSecretResponse) (secret, commitment string, extension map[string]string, err error) {
+	//retrieve principal IDDoc
+	principalDocID, err := common.RetrieveIDDocFromIPFS(s.Ipfs, order.PrincipalCID)
+	if err != nil {
+		return "", "", nil, err
+	}
+
+	finalPrivateKey, err := deriveFinalPrivateKey(s, *orderPart4, sikeSK, seed, req.BeneficiaryIDDocumentCID, s.NodeID(), principalDocID.BLSPublicKey)
+	if err != nil {
+		return "", "", nil, err
+	}
+	//Generate Public key & derive crypto address
+	finalPublicKey, finalPublicKeyCompressed, err := cryptowallet.PublicKeyFromPrivate(finalPrivateKey)
+	if err != nil {
+		return "", "", nil, err
+	}
+
+	addressForPublicKey, err := addressForPublicKey(finalPublicKey, int(order.Coin))
+	if err != nil {
+		return "", "", nil, err
+	}
+
+	return finalPrivateKey, finalPublicKeyCompressed, map[string]string{"address": addressForPublicKey}, nil
+}
diff --git a/pkg/common/common.go b/pkg/common/common.go
new file mode 100644
index 0000000..b8b6b0c
--- /dev/null
+++ b/pkg/common/common.go
@@ -0,0 +1,260 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package common - helper functions that enable service to get and set encrypted envelopes
+*/
+package common
+
+import (
+	"encoding/hex"
+	"fmt"
+	"io"
+	"sync"
+	"time"
+
+	"github.com/apache/incubator-milagro-dta/libs/cryptowallet"
+	"github.com/apache/incubator-milagro-dta/libs/datastore"
+	"github.com/apache/incubator-milagro-dta/libs/documents"
+	"github.com/apache/incubator-milagro-dta/libs/ipfs"
+	"github.com/google/uuid"
+	"github.com/pkg/errors"
+)
+
+var previousIDMutex = &sync.Mutex{}
+
+//IdentitySecrets - keys required for decryption and signing
+type IdentitySecrets struct {
+	Name          string `json:"Name"`
+	Seed          string `json:"Seed"`
+	SikeSecretKey string `json:"SikeSecretKey"`
+	BLSSecretKey  string `json:"BlsSecretKey"`
+}
+
+// CreateNewDepositOrder - Generate an empty new Deposit Order with random reference
+func CreateNewDepositOrder(BeneficiaryIDDocumentCID string, nodeID string) (*documents.OrderDoc, error) {
+	//Create a reference for this order
+	reference, err := uuid.NewUUID()
+	if err != nil {
+		return nil, err
+	}
+	order := documents.NewOrderDoc()
+	//oder.Type will be used to extend the things that an order can do.
+	order.Type = "Safeguard_Secret"
+	order.PrincipalCID = nodeID
+	order.Reference = reference.String()
+	order.BeneficiaryCID = BeneficiaryIDDocumentCID
+	order.Timestamp = time.Now().Unix()
+	return &order, nil
+}
+
+// RetrieveOrderFromIPFS - retrieve an Order from IPFS and Decode the into an  object
+func RetrieveOrderFromIPFS(ipfs ipfs.Connector, ipfsID string, sikeSK []byte, recipientID string, sendersBlsPK []byte) (*documents.OrderDoc, error) {
+	o := &documents.OrderDoc{}
+	rawDocO, err := ipfs.Get(ipfsID)
+	if err != nil {
+		return nil, err
+	}
+	err = documents.DecodeOrderDocument(rawDocO, ipfsID, o, sikeSK, recipientID, sendersBlsPK)
+	return o, err
+}
+
+// RetrieveIDDocFromIPFS finds and parses the IDDocument
+func RetrieveIDDocFromIPFS(ipfs ipfs.Connector, ipfsID string) (documents.IDDoc, error) {
+	iddoc := &documents.IDDoc{}
+	rawDocI, err := ipfs.Get(ipfsID)
+	if err != nil {
+		return documents.IDDoc{}, err
+	}
+	err = documents.DecodeIDDocument(rawDocI, ipfsID, iddoc)
+	return *iddoc, err
+}
+
+// MakeRandomSeedAndStore genefates and stores a random seed
+func MakeRandomSeedAndStore(store *datastore.Store, rng io.Reader, reference string) (seedHex string, err error) {
+	seed := make([]byte, 32)
+	if _, err := io.ReadFull(rng, seed); err != nil {
+		return "", err
+	}
+	i := len(seed)
+	if i > 32 {
+		i = 32
+	}
+	var byte32 [32]byte
+	copy(byte32[:], seed[:i])
+	seedHex = hex.EncodeToString(seed)
+	if err := store.Set("keySeed", reference, seedHex, nil); err != nil {
+		return "", errors.Wrap(err, "store seed")
+	}
+	return seedHex, nil
+}
+
+// RetrieveSeed gets the seed from the key store
+func RetrieveSeed(store *datastore.Store, reference string) (seedHex string, err error) {
+	if err := store.Get("keySeed", reference, &seedHex); err != nil {
+		return "", nil
+	}
+	return seedHex, nil
+}
+
+// CreateAndStoreOrderPart2 -
+func CreateAndStoreOrderPart2(ipfs ipfs.Connector, store *datastore.Store, order *documents.OrderDoc, orderPart1CID, commitmentPublicKey, nodeID string, recipients map[string]documents.IDDoc) (orderPart2CID string, err error) {
+	Part2 := documents.OrderPart2{
+		CommitmentPublicKey: commitmentPublicKey,
+		PreviousOrderCID:    orderPart1CID,
+		Timestamp:           time.Now().Unix(),
+	}
+	order.OrderPart2 = &Part2
+	//Write the updated doc back to IPFS
+	orderPart2CID, err = WriteOrderToIPFS(nodeID, ipfs, store, nodeID, order, recipients)
+	if err != nil {
+		return "", err
+	}
+	return orderPart2CID, nil
+}
+
+// CreateAndStorePart3 adds part 3 "redemption request" to the order doc
+func CreateAndStorePart3(ipfs ipfs.Connector, store *datastore.Store, order *documents.OrderDoc, orderPart2CID, nodeID string, beneficiaryEncryptedData []byte, recipients map[string]documents.IDDoc) (orderPart3CID string, err error) {
+	//Add part 3 "redemption request" to the order doc
+	redemptionRequest := documents.OrderPart3{
+		//TODO
+		Redemption:               "SignedReferenceNumber",
+		PreviousOrderCID:         orderPart2CID,
+		BeneficiaryEncryptedData: beneficiaryEncryptedData,
+		Timestamp:                time.Now().Unix(),
+	}
+	order.OrderPart3 = &redemptionRequest
+	//Write the updated doc back to IPFS
+	orderPart3CID, err = WriteOrderToIPFS(nodeID, ipfs, store, nodeID, order, recipients)
+	if err != nil {
+		return "", nil
+	}
+	return orderPart3CID, nil
+}
+
+// CreateAndStoreOrderPart4 -
+func CreateAndStoreOrderPart4(ipfs ipfs.Connector, store *datastore.Store, order *documents.OrderDoc, commitmentPrivateKey, orderPart3CID, nodeID string, recipients map[string]documents.IDDoc) (orderPart4CID string, err error) {
+	Part4 := documents.OrderPart4{
+		Secret:           commitmentPrivateKey,
+		PreviousOrderCID: orderPart3CID,
+		Timestamp:        time.Now().Unix(),
+	}
+	order.OrderPart4 = &Part4
+	//Write the updated doc back to IPFS
+	orderPart4CID, err = WriteOrderToIPFS(nodeID, ipfs, store, nodeID, order, recipients)
+	if err != nil {
+		return "", nil
+	}
+	return orderPart4CID, nil
+}
+
+// WriteOrderToIPFS writes the order document to IPFS network
+func WriteOrderToIPFS(nodeID string, ipfs ipfs.Connector, store *datastore.Store, id string, order *documents.OrderDoc, recipients map[string]documents.IDDoc) (ipfsAddress string, err error) { // Get the secret keys
+	secrets := &IdentitySecrets{}
+	if err := store.Get("id-doc", nodeID, secrets); err != nil {
+		return "", errors.New("load secrets from store")
+	}
+	blsSecretKey, err := hex.DecodeString(secrets.BLSSecretKey)
+	if err != nil {
+		return "", errors.Wrap(err, "Decode identity secrets")
+	}
+
+	////Mutex Lock - only one thread at once can write to IPFS as we need to keep track of the previous ID and put it into the next doc to create a chain
+	previousIDMutex.Lock()
+	previousIDKey := fmt.Sprintf("previous-id-%s", nodeID)
+	var previousID string
+	if err := store.Get("id-doc", previousIDKey, &previousID); err != nil {
+		previousID = "genesis"
+		if err := store.Set("id-doc", previousIDKey, previousID, nil); err != nil {
+			return "", err
+		}
+	}
+
+	rawDoc, err := documents.EncodeOrderDocument(nodeID, *order, blsSecretKey, previousID, recipients)
+	if err != nil {
+		return "", errors.Wrap(err, "Failed to encode IDDocument")
+	}
+	ipfsAddress, err = ipfs.Add(rawDoc)
+	if err != nil {
+		return "", errors.Wrap(err, "Failed to Save Raw Document into IPFS")
+	}
+	if err := store.Set("id-doc", previousIDKey, ipfsAddress, nil); err != nil {
+		return "", err
+	}
+	previousIDMutex.Unlock()
+
+	//Write order to store
+	//orderRef := fmt.Sprintf("order-ref-%s", order.Reference)
+	if err := store.Set("order", order.Reference, ipfsAddress, map[string]string{"time": time.Now().UTC().Format(time.RFC3339)}); err != nil {
+		return "", errors.New("Save Order to store")
+	}
+	return ipfsAddress, nil
+}
+
+//InitECKeys - generate EC keys using BIP44 HD Wallets (as bitcoin) from seed
+func InitECKeys(seed []byte) ([]byte, error) {
+	//EC ADD Keypair Protocol
+	_, pubKeyECADD, _, err := cryptowallet.Bip44Address(seed, cryptowallet.CoinTypeBitcoinMain, 0, 0, 0)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to derive EC HD Wallet Key")
+	}
+	return pubKeyECADD.SerializeCompressed(), nil
+}
+
+// RetrieveIdentitySecrets gets the secrets for the node ID
+func RetrieveIdentitySecrets(store *datastore.Store, nodeID string) (name string, seed []byte, blsSK []byte, sikeSK []byte, err error) {
+
+	var idSecrets = &IdentitySecrets{}
+	if err := store.Get("id-doc", nodeID, idSecrets); err != nil {
+		return "", nil, nil, nil, err
+	}
+
+	seed, err = hex.DecodeString(idSecrets.Seed)
+	if err != nil {
+		return "", nil, nil, nil, err
+	}
+
+	blsSK, err = hex.DecodeString(idSecrets.BLSSecretKey)
+	if err != nil {
+		return "", nil, nil, nil, err
+	}
+
+	sikeSK, err = hex.DecodeString(idSecrets.SikeSecretKey)
+	if err != nil {
+		return "", nil, nil, nil, err
+	}
+	return idSecrets.Name, seed, blsSK, sikeSK, nil
+}
+
+// BuildRecipientList builds a list of recipients who are able to decrypt the encrypted envelope
+func BuildRecipientList(ipfs ipfs.Connector, localNodeDocCID, remoteNodeDocCID string) (map[string]documents.IDDoc, error) {
+	remoteNodeDoc, err := RetrieveIDDocFromIPFS(ipfs, remoteNodeDocCID)
+	if err != nil {
+		return nil, err
+	}
+
+	localNodeDoc, err := RetrieveIDDocFromIPFS(ipfs, localNodeDocCID)
+	if err != nil {
+		return nil, err
+	}
+
+	recipients := map[string]documents.IDDoc{
+		remoteNodeDocCID: remoteNodeDoc,
+		localNodeDocCID:  localNodeDoc,
+	}
+	return recipients, nil
+}
diff --git a/pkg/config/config.go b/pkg/config/config.go
new file mode 100644
index 0000000..d3a1386
--- /dev/null
+++ b/pkg/config/config.go
@@ -0,0 +1,142 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package config - create default config and read config values
+*/
+package config
+
+import (
+	"errors"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+
+	"github.com/go-yaml/yaml"
+)
+
+const (
+	configFileName = "config.yaml"
+)
+
+var (
+	// ErrConfigExists is returned on init if config file exists
+	ErrConfigExists = errors.New("Config file already exists")
+	// ErrConfigNotFound is returned when configuration not found
+	ErrConfigNotFound = errors.New("Configuration not found")
+)
+
+// HTTPConfig -
+type HTTPConfig struct {
+	ListenAddr    string `yaml:"listenAddr"`
+	MetricsAddr   string `yaml:"metricsAddr"`
+	OIDCProvider  string `yaml:"oidcProvider"`
+	OIDCClientID  string `yaml:"oidcClientID"`
+	OIDCClientKey string `yaml:"oidcClientKey"`
+	CorsAllow     string `yaml:"corsAllow"`
+}
+
+// LogConfig -
+type LogConfig struct {
+	Format string `yaml:"format"`
+	Level  string `yaml:"level"`
+}
+
+// IPFSConfig -
+type IPFSConfig struct {
+	Connector     string   `yaml:"connector"`
+	Bootstrap     []string `yaml:"bootstrap"`
+	ListenAddress string   `yaml:"listenAddress"`
+	APIAddress    string   `yaml:"apiAddress"`
+}
+
+// NodeConfig -
+type NodeConfig struct {
+	NodeType              string `yaml:"nodeType"`
+	MasterFiduciaryServer string `yaml:"masterFiduciaryServer"`
+	MasterFiduciaryNodeID string `yaml:"masterFiduciaryNodeID"`
+	NodeID                string `yaml:"nodeID"`
+	NodeName              string `yaml:"nodeName"`
+	Datastore             string `yaml:"dataStore"`
+}
+
+// PluginsConfig -
+type PluginsConfig struct {
+	Service string `yaml:"service"`
+}
+
+// Config -
+type Config struct {
+	HTTP    HTTPConfig    `yaml:"http"`
+	Node    NodeConfig    `yaml:"node"`
+	Log     LogConfig     `yaml:"log"`
+	IPFS    IPFSConfig    `yaml:"ipfs"`
+	Plugins PluginsConfig `yaml:"plugins"`
+}
+
+// Init initialise config folder with default options
+func Init(folder string, config *Config) error {
+	configFilePath := filepath.Join(folder, configFileName)
+
+	_, err := os.Stat(configFilePath)
+	if err == nil {
+		return ErrConfigExists
+	}
+	if !os.IsNotExist(err) {
+		return err
+	}
+
+	if err := os.MkdirAll(folder, 0700); err != nil {
+		return err
+	}
+
+	return SaveConfig(folder, config)
+}
+
+// ParseConfig parses configuration file
+func ParseConfig(folder string) (*Config, error) {
+	configFilePath := filepath.Join(folder, configFileName)
+	if _, err := os.Stat(configFilePath); err != nil {
+		if os.IsNotExist(err) {
+			return nil, ErrConfigNotFound
+		}
+		return nil, err
+	}
+
+	b, err := ioutil.ReadFile(configFilePath)
+	if err != nil {
+		return nil, err
+	}
+	cfg := &Config{}
+	if err := yaml.Unmarshal(b, cfg); err != nil {
+		return nil, err
+	}
+
+	return cfg, err
+}
+
+// SaveConfig stores configuration
+func SaveConfig(folder string, cfg *Config) error {
+	configFilePath := filepath.Join(folder, configFileName)
+
+	b, err := yaml.Marshal(cfg)
+	if err != nil {
+		return err
+	}
+
+	return ioutil.WriteFile(configFilePath, b, 0600)
+}
diff --git a/pkg/config/default.go b/pkg/config/default.go
new file mode 100644
index 0000000..1ea3ba1
--- /dev/null
+++ b/pkg/config/default.go
@@ -0,0 +1,78 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package config
+
+// DefaultConfig -
+func DefaultConfig() *Config {
+	return &Config{
+		HTTP:    defaultHTTPConfig(),
+		Node:    defaultNodeConfig(),
+		Log:     defaultLogConfig(),
+		IPFS:    defaultIPFSConfig(),
+		Plugins: defaultPluginsConfig(),
+	}
+}
+
+func defaultHTTPConfig() HTTPConfig {
+	return HTTPConfig{
+		ListenAddr:    ":5556",
+		MetricsAddr:   ":5557",
+		OIDCProvider:  "",
+		OIDCClientID:  "",
+		OIDCClientKey: "",
+		CorsAllow:     "*",
+	}
+}
+
+// LogConfig -
+func defaultLogConfig() LogConfig {
+	return LogConfig{
+		Format: "text",
+		Level:  "info",
+	}
+}
+
+// IPFSConfig -
+func defaultIPFSConfig() IPFSConfig {
+	return IPFSConfig{
+		Bootstrap: []string{
+			"/ip4/34.252.47.231/tcp/4001/ipfs/QmcEPkctfqQs6vbvTD8EdJmzy4zouAtrV8AwjLbGhbURep",
+		},
+		Connector:     "embedded",
+		ListenAddress: "/ip4/0.0.0.0/tcp/4001",
+		APIAddress:    "http://localhost:5001",
+	}
+}
+
+// NodeConfig -
+func defaultNodeConfig() NodeConfig {
+	return NodeConfig{
+		NodeType:              "multi",
+		MasterFiduciaryServer: "http://localhost:5556",
+		MasterFiduciaryNodeID: "",
+		NodeID:                "",
+		Datastore:             "embedded",
+	}
+}
+
+// PluginsConfig -
+func defaultPluginsConfig() PluginsConfig {
+	return PluginsConfig{
+		Service: "milagro",
+	}
+}
diff --git a/pkg/defaultservice/fulfill.go b/pkg/defaultservice/fulfill.go
new file mode 100644
index 0000000..a45eacb
--- /dev/null
+++ b/pkg/defaultservice/fulfill.go
@@ -0,0 +1,123 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package defaultservice
+
+import (
+	"github.com/apache/incubator-milagro-dta/libs/cryptowallet"
+	"github.com/apache/incubator-milagro-dta/pkg/api"
+	"github.com/apache/incubator-milagro-dta/pkg/common"
+)
+
+// FulfillOrder -
+func (s *Service) FulfillOrder(req *api.FulfillOrderRequest) (*api.FulfillOrderResponse, error) {
+	orderPart1CID := req.OrderPart1CID
+	nodeID := s.NodeID()
+	remoteIDDocCID := req.DocumentCID
+	_, _, _, sikeSK, err := common.RetrieveIdentitySecrets(s.Store, nodeID)
+	if err != nil {
+		return nil, err
+	}
+
+	remoteIDDoc, err := common.RetrieveIDDocFromIPFS(s.Ipfs, remoteIDDocCID)
+	if err != nil {
+		return nil, err
+	}
+
+	//Retrieve the order from IPFS
+	order, err := common.RetrieveOrderFromIPFS(s.Ipfs, orderPart1CID, sikeSK, nodeID, remoteIDDoc.BLSPublicKey)
+	if err != nil {
+		return nil, err
+	}
+
+	recipientList, err := common.BuildRecipientList(s.Ipfs, nodeID, nodeID)
+	if err != nil {
+		return nil, err
+	}
+
+	//Generate the secret and store for later redemption
+	seed, err := common.MakeRandomSeedAndStore(s.Store, s.Rng, order.Reference)
+	if err != nil {
+		return nil, err
+	}
+
+	//Generate the Public Key (Commitment) from the Seed/Secret
+	commitmentPublicKey, err := cryptowallet.RedeemPublicKey(seed)
+	if err != nil {
+		return nil, err
+	}
+
+	//Create an order response in IPFS
+	orderPart2CID, err := common.CreateAndStoreOrderPart2(s.Ipfs, s.Store, order, orderPart1CID, commitmentPublicKey, nodeID, recipientList)
+	if err != nil {
+		return nil, err
+	}
+
+	return &api.FulfillOrderResponse{
+		OrderPart2CID: orderPart2CID,
+	}, nil
+}
+
+// FulfillOrderSecret -
+func (s *Service) FulfillOrderSecret(req *api.FulfillOrderSecretRequest) (*api.FulfillOrderSecretResponse, error) {
+	//Initialise values from Request object
+	orderPart3CID := req.OrderPart3CID
+	nodeID := s.NodeID()
+	remoteIDDocCID := req.SenderDocumentCID
+	_, _, _, sikeSK, err := common.RetrieveIdentitySecrets(s.Store, nodeID)
+	if err != nil {
+		return nil, err
+	}
+
+	remoteIDDoc, err := common.RetrieveIDDocFromIPFS(s.Ipfs, remoteIDDocCID)
+	if err != nil {
+		return nil, err
+	}
+
+	//Retrieve the order from IPFS
+	order, err := common.RetrieveOrderFromIPFS(s.Ipfs, orderPart3CID, sikeSK, nodeID, remoteIDDoc.BLSPublicKey)
+	if err != nil {
+		return nil, err
+	}
+
+	recipientList, err := common.BuildRecipientList(s.Ipfs, nodeID, nodeID)
+	if err != nil {
+		return nil, err
+	}
+
+	//Retrieve the Seed
+	seed, err := common.RetrieveSeed(s.Store, order.Reference)
+	if err != nil {
+		return nil, err
+	}
+
+	//Generate the Secert from the Seed
+	commitmentPrivateKey, err := cryptowallet.RedeemSecret(seed)
+	if err != nil {
+		return nil, err
+	}
+
+	//Create an order response in IPFS
+	orderPart4ID, err := common.CreateAndStoreOrderPart4(s.Ipfs, s.Store, order, commitmentPrivateKey, orderPart3CID, nodeID, recipientList)
+	if err != nil {
+		return nil, err
+	}
+
+	return &api.FulfillOrderSecretResponse{
+		OrderPart4CID: orderPart4ID,
+	}, nil
+}
diff --git a/pkg/defaultservice/identity.go b/pkg/defaultservice/identity.go
new file mode 100644
index 0000000..d58aee8
--- /dev/null
+++ b/pkg/defaultservice/identity.go
@@ -0,0 +1,146 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package defaultservice
+
+import (
+	"encoding/hex"
+	"time"
+
+	"github.com/apache/incubator-milagro-dta/libs/crypto"
+	"github.com/apache/incubator-milagro-dta/libs/cryptowallet"
+	"github.com/apache/incubator-milagro-dta/libs/documents"
+	"github.com/apache/incubator-milagro-dta/pkg/api"
+	"github.com/apache/incubator-milagro-dta/pkg/common"
+	"github.com/pkg/errors"
+)
+
+// CreateIdentity creates a new identity
+func (s *Service) CreateIdentity(req *api.CreateIdentityRequest) (*api.CreateIdentityResponse, error) {
+	name := req.Name
+
+	//generate crypto random seed
+	seed, err := cryptowallet.RandomBytes(48)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to Generate random seed")
+	}
+
+	//Generate SIKE keys
+	rc1, sikePublicKey, sikeSecretKey := crypto.SIKEKeys(seed)
+	if rc1 != 0 {
+		return nil, errors.New("Failed to generate SIKE keys")
+	}
+
+	//Generate BLS keys
+	rc1, blsPublicKey, blsSecretKey := crypto.BLSKeys(seed, nil)
+	if rc1 != 0 {
+		return nil, errors.New("Failed to generate BLS keys")
+	}
+
+	ecPubKey, err := common.InitECKeys(seed)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to Generate EC Pub Key from random seed")
+	}
+	//build ID Doc
+	idDocument := documents.NewIDDoc()
+	idDocument.AuthenticationReference = name
+	idDocument.BeneficiaryECPublicKey = ecPubKey
+	idDocument.SikePublicKey = sikePublicKey
+	idDocument.BLSPublicKey = blsPublicKey
+	idDocument.Timestamp = time.Now().Unix()
+	//Encode the IDDoc to envelope byte stream
+	rawDoc, err := documents.EncodeIDDocument(idDocument, blsSecretKey)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to encode IDDocument")
+	}
+	idDocumentCID, err := s.Ipfs.Add(rawDoc)
+	if err != nil {
+		return nil, errors.Wrap(err, "Failed to Save Raw Document into IPFS")
+	}
+	secrets := common.IdentitySecrets{
+		Name:          name,
+		Seed:          hex.EncodeToString(seed),
+		BLSSecretKey:  hex.EncodeToString(blsSecretKey),
+		SikeSecretKey: hex.EncodeToString(sikeSecretKey),
+	}
+
+	if err := s.Store.Set("id-doc", idDocumentCID, secrets, map[string]string{"time": time.Now().UTC().Format(time.RFC3339)}); err != nil {
+		return nil, errors.Wrap(err, "Failed to Save ID Document - Write to Store")
+	}
+
+	return &api.CreateIdentityResponse{
+		IDDocumentCID: idDocumentCID,
+	}, nil
+}
+
+// GetIdentity retrieves an identity
+func (s *Service) GetIdentity(req *api.GetIdentityRequest) (*api.GetIdentityResponse, error) {
+	idDocumentCID := req.IDDocumentCID
+	idDocument, err := common.RetrieveIDDocFromIPFS(s.Ipfs, idDocumentCID)
+	if err != nil {
+		return nil, err
+	}
+	return &api.GetIdentityResponse{
+		IDDocumentCID:           idDocumentCID,
+		AuthenticationReference: idDocument.AuthenticationReference,
+		BeneficiaryECPublicKey:  hex.EncodeToString(idDocument.BeneficiaryECPublicKey),
+		SikePublicKey:           hex.EncodeToString(idDocument.SikePublicKey),
+		BLSPublicKey:            hex.EncodeToString(idDocument.BLSPublicKey),
+		Timestamp:               idDocument.Timestamp,
+	}, nil
+}
+
+// IdentityList reutrns the list of identities
+func (s *Service) IdentityList(req *api.IdentityListRequest) (*api.IdentityListResponse, error) {
+	page := req.Page
+	perPage := req.PerPage
+	sortBy := req.SortBy
+
+	IDDocumentCIDes, err := s.Store.ListKeys("id-doc", "time", page*perPage, perPage, sortBy != "dateCreatedAsc")
+	if err != nil {
+		return nil, err
+	}
+
+	fullIDList := make([]api.GetIdentityResponse, len(IDDocumentCIDes))
+	for i, idAddress := range IDDocumentCIDes {
+
+		rawDocI, err := s.Ipfs.Get(idAddress)
+		if err != nil {
+			return nil, errors.Wrapf(err, "Read identity Doc")
+		}
+
+		idDocument := &documents.IDDoc{}
+		if err = documents.DecodeIDDocument(rawDocI, idAddress, idDocument); err != nil {
+			return nil, err
+		}
+		//Need to copy the whole object so I can append the idddocadderess
+		idWithAddress := api.GetIdentityResponse{
+			IDDocumentCID:           idAddress,
+			AuthenticationReference: idDocument.AuthenticationReference,
+			BeneficiaryECPublicKey:  hex.EncodeToString(idDocument.BeneficiaryECPublicKey),
+			SikePublicKey:           hex.EncodeToString(idDocument.SikePublicKey),
+			BLSPublicKey:            hex.EncodeToString(idDocument.BLSPublicKey),
+			Timestamp:               idDocument.Timestamp,
+		}
+
+		fullIDList[i] = idWithAddress
+	}
+
+	return &api.IdentityListResponse{
+		IDDocumentList: fullIDList,
+	}, nil
+}
diff --git a/pkg/defaultservice/order.go b/pkg/defaultservice/order.go
new file mode 100644
index 0000000..4326ba0
--- /dev/null
+++ b/pkg/defaultservice/order.go
@@ -0,0 +1,281 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package defaultservice
+
+import (
+	"encoding/json"
+	"time"
+
+	"github.com/apache/incubator-milagro-dta/libs/cryptowallet"
+	"github.com/apache/incubator-milagro-dta/libs/documents"
+	"github.com/apache/incubator-milagro-dta/pkg/api"
+	"github.com/apache/incubator-milagro-dta/pkg/common"
+	"github.com/pkg/errors"
+)
+
+// GetOrder retreives an order
+func (s *Service) GetOrder(req *api.GetOrderRequest) (*api.GetOrderResponse, error) {
+	orderReference := req.OrderReference
+
+	var cid string
+	if err := s.Store.Get("order", orderReference, &cid); err != nil {
+		return nil, err
+	}
+
+	localIDDoc, err := common.RetrieveIDDocFromIPFS(s.Ipfs, s.NodeID())
+	if err != nil {
+		return nil, err
+	}
+
+	_, _, _, sikeSK, err := common.RetrieveIdentitySecrets(s.Store, s.NodeID())
+	if err != nil {
+		return nil, err
+	}
+
+	order, err := common.RetrieveOrderFromIPFS(s.Ipfs, cid, sikeSK, s.NodeID(), localIDDoc.BLSPublicKey)
+	if err != nil {
+		return nil, err
+	}
+
+	orderByte, err := json.Marshal(order)
+	if err != nil {
+		return nil, err
+	}
+	return &api.GetOrderResponse{
+		OrderCID: cid,
+		Order:    string(orderByte),
+	}, nil
+}
+
+// OrderList retrieves the list of orders
+func (s *Service) OrderList(req *api.OrderListRequest) (*api.OrderListResponse, error) {
+	page := req.Page
+	perPage := req.PerPage
+	sortBy := req.SortBy
+
+	orderref, err := s.Store.ListKeys("order", "time", page*perPage, perPage, sortBy != "dateCreatedAsc")
+	if err != nil {
+		return nil, err
+	}
+
+	//Pagnination - Show everything by default
+	start := 0
+	stop := len(orderref)
+
+	if perPage != 0 && page < len(orderref)/perPage && page*perPage < len(orderref) {
+		start = page
+		stop = perPage
+	}
+
+	return &api.OrderListResponse{
+		OrderReference: orderref[start:stop],
+	}, nil
+}
+
+// ValidateOrderRequest returns error if the request values are invalid
+func (s *Service) ValidateOrderRequest(req *api.OrderRequest) error {
+	return nil
+}
+
+//ValidateOrderSecretRequest - Validate fields in the Order Secret
+func (s *Service) ValidateOrderSecretRequest(req *api.OrderSecretRequest, order documents.OrderDoc) error {
+	return nil
+}
+
+// PrepareOrderPart1 is called before the order is send
+func (s *Service) PrepareOrderPart1(order *documents.OrderDoc, reqExtension map[string]string) (fulfillExtension map[string]string, err error) {
+	return nil, nil
+}
+
+// PrepareOrderResponse gets the updated order and returns the commitment and extension
+func (s *Service) PrepareOrderResponse(orderPart2 *documents.OrderDoc, reqExtension, fulfillExtension map[string]string) (commitment string, extension map[string]string, err error) {
+	return orderPart2.OrderPart2.CommitmentPublicKey, nil, nil
+}
+
+// Order -
+func (s *Service) Order(req *api.OrderRequest) (*api.OrderResponse, error) {
+	if err := s.Plugin.ValidateOrderRequest(req); err != nil {
+		return nil, err
+	}
+
+	//Initialise values from Request object
+	beneficiaryIDDocumentCID := req.BeneficiaryIDDocumentCID
+	iDDocID := s.NodeID()
+	recipientList, err := common.BuildRecipientList(s.Ipfs, iDDocID, s.MasterFiduciaryNodeID())
+	if err != nil {
+		return nil, err
+	}
+
+	remoteIDDoc, err := common.RetrieveIDDocFromIPFS(s.Ipfs, s.MasterFiduciaryNodeID())
+	if err != nil {
+		return nil, err
+	}
+
+	//Create Order
+	order, err := common.CreateNewDepositOrder(beneficiaryIDDocumentCID, iDDocID)
+	if err != nil {
+		return nil, err
+	}
+
+	fulfillExtension, err := s.Plugin.PrepareOrderPart1(order, req.Extension)
+	if err != nil {
+		return nil, err
+	}
+
+	//Write Order to IPFS
+	orderPart1CID, err := common.WriteOrderToIPFS(iDDocID, s.Ipfs, s.Store, iDDocID, order, recipientList)
+	if err != nil {
+		return nil, err
+	}
+
+	//Fullfill the order on the remote Server
+	request := &api.FulfillOrderRequest{
+		DocumentCID:   iDDocID,
+		OrderPart1CID: orderPart1CID,
+		Extension:     fulfillExtension,
+	}
+	response, err := s.MasterFiduciaryServer.FulfillOrder(request)
+	if err != nil {
+		return nil, errors.Wrap(err, "Contacting Fiduciary")
+	}
+
+	//Get the updated order out of IPFS
+	_, _, _, sikeSK, err := common.RetrieveIdentitySecrets(s.Store, iDDocID)
+	if err != nil {
+		return nil, err
+	}
+	updatedOrder, err := common.RetrieveOrderFromIPFS(s.Ipfs, response.OrderPart2CID, sikeSK, iDDocID, remoteIDDoc.BLSPublicKey)
+	if err != nil {
+		return nil, errors.Wrap(err, "Fail to retrieve Order from IPFS")
+	}
+
+	commitment, extension, err := s.Plugin.PrepareOrderResponse(updatedOrder, req.Extension, response.Extension)
+	if err != nil {
+		return nil, errors.Wrap(err, "Generating Final Public Key")
+	}
+
+	return &api.OrderResponse{
+		OrderReference: order.Reference,
+		Commitment:     commitment,
+		CreatedAt:      time.Now().Unix(),
+		Extension:      extension,
+	}, nil
+}
+
+// ProduceBeneficiaryEncryptedData -
+func (s *Service) ProduceBeneficiaryEncryptedData(blsSK []byte, order *documents.OrderDoc, req *api.OrderSecretRequest) (encrypted []byte, extension map[string]string, err error) {
+	return nil, nil, nil
+}
+
+// ProduceFinalSecret -
+func (s *Service) ProduceFinalSecret(seed, sikeSK []byte, order, orderPart4 *documents.OrderDoc, req *api.OrderSecretRequest, fulfillSecretRespomse *api.FulfillOrderSecretResponse) (secret, commitment string, extension map[string]string, err error) {
+	finalPrivateKey := orderPart4.OrderDocument.OrderPart4.Secret
+	//Derive the Public key from the supplied Private Key
+	finalPublicKey, _, err := cryptowallet.PublicKeyFromPrivate(finalPrivateKey)
+	return finalPrivateKey, finalPublicKey, nil, err
+}
+
+// OrderSecret -
+func (s *Service) OrderSecret(req *api.OrderSecretRequest) (*api.OrderSecretResponse, error) {
+	orderReference := req.OrderReference
+	var orderPart2CID string
+	if err := s.Store.Get("order", orderReference, &orderPart2CID); err != nil {
+		return nil, err
+	}
+
+	nodeID := s.NodeID()
+	recipientList, err := common.BuildRecipientList(s.Ipfs, nodeID, s.MasterFiduciaryNodeID())
+	if err != nil {
+		return nil, err
+	}
+	remoteIDDoc, err := common.RetrieveIDDocFromIPFS(s.Ipfs, s.MasterFiduciaryNodeID())
+	if err != nil {
+		return nil, err
+	}
+
+	_, _, blsSK, sikeSK, err := common.RetrieveIdentitySecrets(s.Store, nodeID)
+	if err != nil {
+		return nil, err
+	}
+
+	//Retrieve the order from IPFS
+	order, err := common.RetrieveOrderFromIPFS(s.Ipfs, orderPart2CID, sikeSK, nodeID, remoteIDDoc.BLSPublicKey)
+	if err != nil {
+		return nil, errors.Wrap(err, "Fail to retrieve Order from IPFS")
+	}
+
+	var beneficiariesSikeSK []byte
+	var beneficiaryCID string
+
+	if req.BeneficiaryIDDocumentCID != "" {
+		beneficiaryCID = req.BeneficiaryIDDocumentCID
+	} else {
+		beneficiaryCID = order.BeneficiaryCID
+	}
+
+	_, beneficiariesSeed, _, beneficiariesSikeSK, err := common.RetrieveIdentitySecrets(s.Store, beneficiaryCID)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := s.Plugin.ValidateOrderSecretRequest(req, *order); err != nil {
+		return nil, err
+	}
+
+	//Create a piece of data that is destined for the beneficiary, passed via the Master Fiduciary
+
+	beneficiaryEncryptedData, extension, err := s.Plugin.ProduceBeneficiaryEncryptedData(blsSK, order, req)
+	if err != nil {
+		return nil, err
+	}
+
+	//Create a request Object in IPFS
+	orderPart3CID, err := common.CreateAndStorePart3(s.Ipfs, s.Store, order, orderPart2CID, nodeID, beneficiaryEncryptedData, recipientList)
+	if err != nil {
+		return nil, err
+	}
+
+	//Post the address of the updated doc to the custody node
+	request := &api.FulfillOrderSecretRequest{
+		SenderDocumentCID: nodeID,
+		OrderPart3CID:     orderPart3CID,
+		Extension:         extension,
+	}
+	response, err := s.MasterFiduciaryServer.FulfillOrderSecret(request)
+	if err != nil {
+		return nil, err
+	}
+
+	//Retrieve the response Order from IPFS
+	orderPart4, err := common.RetrieveOrderFromIPFS(s.Ipfs, response.OrderPart4CID, sikeSK, nodeID, remoteIDDoc.BLSPublicKey)
+	if err != nil {
+		return nil, err
+	}
+
+	finalPrivateKey, finalPublicKey, ext, err := s.Plugin.ProduceFinalSecret(beneficiariesSeed, beneficiariesSikeSK, order, orderPart4, req, response)
+	if err != nil {
+		return nil, err
+	}
+
+	return &api.OrderSecretResponse{
+		Secret:         finalPrivateKey,
+		Commitment:     finalPublicKey,
+		OrderReference: order.Reference,
+		Extension:      ext,
+	}, nil
+}
diff --git a/pkg/defaultservice/plugable.go b/pkg/defaultservice/plugable.go
new file mode 100644
index 0000000..65014f1
--- /dev/null
+++ b/pkg/defaultservice/plugable.go
@@ -0,0 +1,38 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package defaultservice
+
+import (
+	"github.com/apache/incubator-milagro-dta/libs/documents"
+	"github.com/apache/incubator-milagro-dta/pkg/api"
+)
+
+// Plugable service methods
+type Plugable interface {
+	// service
+	Name() string
+	Vendor() string
+
+	// order
+	ValidateOrderRequest(req *api.OrderRequest) error
+	ValidateOrderSecretRequest(req *api.OrderSecretRequest, order documents.OrderDoc) error
+	PrepareOrderPart1(order *documents.OrderDoc, reqExtension map[string]string) (fulfillExtension map[string]string, err error)
+	PrepareOrderResponse(orderPart2 *documents.OrderDoc, reqExtension, fulfillExtension map[string]string) (commitment string, extension map[string]string, err error)
+	ProduceBeneficiaryEncryptedData(blsSK []byte, order *documents.OrderDoc, req *api.OrderSecretRequest) (encrypted []byte, extension map[string]string, err error)
+	ProduceFinalSecret(seed, sikeSK []byte, order, orderPart4 *documents.OrderDoc, req *api.OrderSecretRequest, fulfillSecretRespomse *api.FulfillOrderSecretResponse) (secret, commitment string, extension map[string]string, err error)
+}
diff --git a/pkg/defaultservice/service.go b/pkg/defaultservice/service.go
new file mode 100644
index 0000000..0c4c671
--- /dev/null
+++ b/pkg/defaultservice/service.go
@@ -0,0 +1,114 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownershis.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package defaultservice - Service that Milagro D-TA provides with no-plugins
+*/
+package defaultservice
+
+import (
+	"io"
+	"time"
+
+	"github.com/apache/incubator-milagro-dta/libs/datastore"
+	"github.com/apache/incubator-milagro-dta/libs/ipfs"
+	"github.com/apache/incubator-milagro-dta/libs/logger"
+	"github.com/apache/incubator-milagro-dta/pkg/api"
+	"github.com/apache/incubator-milagro-dta/pkg/config"
+)
+
+var (
+	extensionVendor = "Milagro"
+	pluginName      = "milagro"
+)
+
+// Service implements the default functionality
+// It also implements the ServicePlugin interface
+type Service struct {
+	Plugin                Plugable
+	Logger                *logger.Logger
+	Rng                   io.Reader
+	Store                 *datastore.Store
+	Ipfs                  ipfs.Connector
+	MasterFiduciaryServer api.ClientService
+	nodeID                string
+	masterFiduciaryNodeID string
+}
+
+//NewService returns a default implementation of Service
+func NewService() *Service {
+	s := &Service{}
+	return s
+}
+
+// Init sets-up the service options. It's called when the plugin gets registered
+func (s *Service) Init(plugin Plugable, logger *logger.Logger, rng io.Reader, store *datastore.Store, ipfsConnector ipfs.Connector, masterFiduciaryServer api.ClientService, cfg *config.Config) error {
+	s.Plugin = plugin
+	s.Logger = logger
+	s.Rng = rng
+	s.Store = store
+	s.Ipfs = ipfsConnector
+	s.MasterFiduciaryServer = masterFiduciaryServer
+
+	s.SetNodeID(cfg.Node.NodeID)
+	s.SetMasterFiduciaryNodeID(cfg.Node.MasterFiduciaryNodeID)
+
+	return nil
+}
+
+// Name of the plugin
+func (s *Service) Name() string {
+	return pluginName
+}
+
+// Vendor of the plugin
+func (s *Service) Vendor() string {
+	return "Milagro"
+}
+
+// NodeID returns the node CID
+func (s *Service) NodeID() string {
+	return s.nodeID
+}
+
+// SetNodeID sets the Node CID
+func (s *Service) SetNodeID(nodeID string) {
+	s.nodeID = nodeID
+}
+
+// MasterFiduciaryNodeID returns the Master Fiduciary NodeID
+func (s *Service) MasterFiduciaryNodeID() string {
+	return s.masterFiduciaryNodeID
+}
+
+// SetMasterFiduciaryNodeID sets the Master Fiduciary NodeID
+func (s *Service) SetMasterFiduciaryNodeID(masterFiduciaryNodeID string) {
+	s.masterFiduciaryNodeID = masterFiduciaryNodeID
+}
+
+// Status of the server
+func (s *Service) Status(apiVersion, nodeType string) (*api.StatusResponse, error) {
+	return &api.StatusResponse{
+		Application:     "Milagro Distributed Trust",
+		APIVersion:      apiVersion,
+		ExtensionVendor: s.Vendor(),
+		NodeType:        nodeType,
+		NodeCID:         s.nodeID,
+		TimeStamp:       time.Now(),
+		Plugin:          s.Plugin.Name(),
+	}, nil
+}
diff --git a/pkg/endpoints/endpoints.go b/pkg/endpoints/endpoints.go
new file mode 100644
index 0000000..947bca2
--- /dev/null
+++ b/pkg/endpoints/endpoints.go
@@ -0,0 +1,381 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+//Package classification Milagro Custody Node API
+//
+//This application creates a distributed network of nodes that collaborate to keep secrets safe
+//swagger:meta
+
+/*
+Package endpoints - HTTP API mapping
+*/
+package endpoints
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+
+	"github.com/apache/incubator-milagro-dta/libs/logger"
+	"github.com/apache/incubator-milagro-dta/libs/transport"
+	"github.com/apache/incubator-milagro-dta/pkg/api"
+	"github.com/apache/incubator-milagro-dta/pkg/service"
+	"github.com/go-kit/kit/endpoint"
+	"github.com/pkg/errors"
+	validator "gopkg.in/go-playground/validator.v9"
+)
+
+var (
+	apiVersion = "v1"
+)
+
+// Endpoints returns all the exported endpoints
+func Endpoints(svc service.Service, corsAllow string, authorizer transport.Authorizer, logger *logger.Logger, nodeType string) transport.HTTPEndpoints {
+	identityEndpoints := transport.HTTPEndpoints{
+		"CreateIdentity": {
+			Path:        "/" + apiVersion + "/identity",
+			Method:      http.MethodPost,
+			Endpoint:    MakeCreateIdentityEndpoint(svc),
+			NewRequest:  func() interface{} { return &api.CreateIdentityRequest{} },
+			NewResponse: func() interface{} { return &api.CreateIdentityResponse{} },
+			Options: transport.ServerOptions(
+				transport.SetCors(corsAllow),
+				transport.AuthorizeOIDC(authorizer, false),
+			),
+			ErrStatus: transport.ErrorStatus{
+				transport.ErrInvalidRequest: http.StatusUnprocessableEntity,
+			},
+		},
+		"GetIdentity": {
+			Path:        "/" + apiVersion + "/identity/{IDDocumentCID}",
+			Method:      http.MethodGet,
+			Endpoint:    MakeGetIdentityEndpoint(svc),
+			NewResponse: func() interface{} { return &api.GetIdentityResponse{} },
+			Options: transport.ServerOptions(
+				transport.SetCors(corsAllow),
+				transport.AuthorizeOIDC(authorizer, false),
+			),
+			ErrStatus: transport.ErrorStatus{
+				transport.ErrInvalidRequest: http.StatusUnprocessableEntity,
+			},
+		},
+		"IdentityList": {
+			Path:        "/" + apiVersion + "/identity",
+			Method:      http.MethodGet,
+			Endpoint:    MakeIdentityListEndpoint(svc),
+			NewResponse: func() interface{} { return &api.IdentityListResponse{} },
+			Options: transport.ServerOptions(
+				transport.SetCors(corsAllow),
+				transport.AuthorizeOIDC(authorizer, false),
+			),
+			ErrStatus: transport.ErrorStatus{
+				transport.ErrInvalidRequest: http.StatusUnprocessableEntity,
+			},
+		},
+	}
+	principalEndpoints := transport.HTTPEndpoints{
+		"Order": {
+			Path:        "/" + apiVersion + "/order",
+			Method:      http.MethodPost,
+			Endpoint:    MakeOrderEndpoint(svc),
+			NewRequest:  func() interface{} { return &api.OrderRequest{} },
+			NewResponse: func() interface{} { return &api.OrderResponse{} },
+			Options: transport.ServerOptions(
+				transport.SetCors(corsAllow),
+				transport.AuthorizeOIDC(authorizer, false),
+			),
+			ErrStatus: transport.ErrorStatus{
+				transport.ErrInvalidRequest: http.StatusUnprocessableEntity,
+			},
+			// ErrStatus: transport.ErrorStatus{
+			// 	transport.ErrInvalidRequest:        http.StatusUnprocessableEntity,
+			// 	ErrCreatingOrderDoc: http.StatusInternalServerError,
+			// },
+		},
+		"GetOrder": {
+			Path:        "/" + apiVersion + "/order/{OrderReference}",
+			Method:      http.MethodGet,
+			Endpoint:    MakeGetOrderEndpoint(svc),
+			NewResponse: func() interface{} { return &api.GetOrderResponse{} },
+			Options: transport.ServerOptions(
+				transport.SetCors(corsAllow),
+				transport.AuthorizeOIDC(authorizer, false),
+			),
+			ErrStatus: transport.ErrorStatus{
+				transport.ErrInvalidRequest: http.StatusUnprocessableEntity,
+			},
+		},
+		"OrderList": {
+			Path:        "/" + apiVersion + "/order",
+			Method:      http.MethodGet,
+			Endpoint:    MakeOrderListEndpoint(svc),
+			NewResponse: func() interface{} { return &api.OrderListResponse{} },
+			Options: transport.ServerOptions(
+				transport.SetCors(corsAllow),
+				transport.AuthorizeOIDC(authorizer, false),
+			),
+			ErrStatus: transport.ErrorStatus{
+				transport.ErrInvalidRequest: http.StatusUnprocessableEntity,
+			},
+		},
+		"OrderSecret": {
+			Path:        "/" + apiVersion + "/order/secret",
+			Method:      http.MethodPost,
+			Endpoint:    MakeOrderSecretEndpoint(svc),
+			NewRequest:  func() interface{} { return &api.OrderSecretRequest{} },
+			NewResponse: func() interface{} { return &api.OrderSecretResponse{} },
+			Options: transport.ServerOptions(
+				transport.SetCors(corsAllow),
+				transport.AuthorizeOIDC(authorizer, false),
+			),
+			ErrStatus: transport.ErrorStatus{
+				transport.ErrInvalidRequest: http.StatusUnprocessableEntity,
+			},
+		},
+	}
+	masterFiduciaryEndpoints := transport.HTTPEndpoints{
+		"FulfillOrder": {
+			Path:        "/" + apiVersion + "/fulfill/order",
+			Method:      http.MethodPost,
+			Endpoint:    MakeFulfillOrderEndpoint(svc),
+			NewRequest:  func() interface{} { return &api.FulfillOrderRequest{} },
+			NewResponse: func() interface{} { return &api.FulfillOrderResponse{} },
+			Options: transport.ServerOptions(
+				transport.SetCors(corsAllow),
+				transport.AuthorizeOIDC(authorizer, false),
+			),
+			ErrStatus: transport.ErrorStatus{
+				transport.ErrInvalidRequest: http.StatusUnprocessableEntity,
+			},
+		},
+		"FulfillOrderSecret": {
+			Path:        "/" + apiVersion + "/fulfill/order/secret",
+			Method:      http.MethodPost,
+			Endpoint:    MakeFulfillOrderSecretEndpoint(svc),
+			NewRequest:  func() interface{} { return &api.FulfillOrderSecretRequest{} },
+			NewResponse: func() interface{} { return &api.FulfillOrderSecretResponse{} },
+			Options: transport.ServerOptions(
+				transport.SetCors(corsAllow),
+				transport.AuthorizeOIDC(authorizer, false),
+			),
+			ErrStatus: transport.ErrorStatus{
+				transport.ErrInvalidRequest: http.StatusUnprocessableEntity,
+			},
+		},
+	}
+
+	statusEndPoints := transport.HTTPEndpoints{
+		"Status": {
+			Path:        "/" + apiVersion + "/status",
+			Method:      http.MethodGet,
+			Endpoint:    MakeStatusEndpoint(svc, nodeType),
+			NewResponse: func() interface{} { return &api.StatusResponse{} },
+			Options: transport.ServerOptions(
+				transport.SetCors(corsAllow),
+				transport.AuthorizeOIDC(authorizer, false),
+			),
+			ErrStatus: transport.ErrorStatus{
+				transport.ErrInvalidRequest: http.StatusUnprocessableEntity,
+			},
+		},
+	}
+
+	switch strings.ToLower(nodeType) {
+	case "multi":
+		return concatEndpoints(masterFiduciaryEndpoints, identityEndpoints, principalEndpoints, statusEndPoints)
+	case "principal":
+		return concatEndpoints(identityEndpoints, principalEndpoints, statusEndPoints)
+	case "fiduciary", "masterfiduciary":
+		return concatEndpoints(masterFiduciaryEndpoints, identityEndpoints, statusEndPoints)
+	}
+
+	return nil
+}
+
+//MakeCreateIdentityEndpoint -
+func MakeCreateIdentityEndpoint(m service.Service) endpoint.Endpoint {
+	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+		req, ok := request.(*api.CreateIdentityRequest)
+		if !ok {
+			return nil, transport.ErrInvalidRequest
+		}
+		if err := validateRequest(req); err != nil {
+			return "", err
+		}
+		return m.CreateIdentity(req)
+	}
+}
+
+//MakeGetIdentityEndpoint -
+func MakeGetIdentityEndpoint(m service.Service) endpoint.Endpoint {
+	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+		params := transport.GetURLParams(ctx)
+		req := &api.GetIdentityRequest{
+			IDDocumentCID: params.Get("IDDocumentCID"),
+		}
+		if err := validateRequest(req); err != nil {
+			return "", err
+		}
+		return m.GetIdentity(req)
+	}
+}
+
+//MakeIdentityListEndpoint -
+func MakeIdentityListEndpoint(m service.Service) endpoint.Endpoint {
+	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+		params := transport.GetParams(ctx)
+		sortBy := params.Get("sortBy")
+		perPage, err := strconv.Atoi(params.Get("perPage"))
+		if err != nil {
+			return nil, transport.ErrInvalidRequest
+		}
+		page, err := strconv.Atoi(params.Get("page"))
+		if err != nil {
+			return nil, transport.ErrInvalidRequest
+		}
+		req := &api.IdentityListRequest{
+			Page:    page,
+			PerPage: perPage,
+			SortBy:  sortBy,
+		}
+		if err := validateRequest(req); err != nil {
+			return "", err
+		}
+		return m.IdentityList(req)
+	}
+}
+
+//MakeOrderListEndpoint -
+func MakeOrderListEndpoint(m service.Service) endpoint.Endpoint {
+	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+		params := transport.GetParams(ctx)
+		sortBy := params.Get("sortBy")
+		perPage, err := strconv.Atoi(params.Get("perPage"))
+		if err != nil {
+			return nil, err
+		}
+		page, err := strconv.Atoi(params.Get("page"))
+		if err != nil {
+			return nil, err
+		}
+		req := &api.OrderListRequest{
+			Page:    page,
+			PerPage: perPage,
+			SortBy:  sortBy,
+		}
+		if err := validateRequest(req); err != nil {
+			return "", err
+		}
+		return m.OrderList(req)
+	}
+}
+
+//MakeGetOrderEndpoint -
+func MakeGetOrderEndpoint(m service.Service) endpoint.Endpoint {
+	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+		params := transport.GetURLParams(ctx)
+		orderReference := params.Get("OrderReference")
+
+		req := &api.GetOrderRequest{
+			OrderReference: orderReference,
+		}
+		return m.GetOrder(req)
+	}
+}
+
+//MakeOrderEndpoint -
+func MakeOrderEndpoint(m service.Service) endpoint.Endpoint {
+	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+		req, ok := request.(*api.OrderRequest)
+		if !ok {
+			return nil, transport.ErrInvalidRequest
+		}
+		if err := validateRequest(req); err != nil {
+			return "", err
+		}
+		return m.Order(req)
+	}
+}
+
+//MakeOrderSecretEndpoint -
+func MakeOrderSecretEndpoint(m service.Service) endpoint.Endpoint {
+	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+		req, ok := request.(*api.OrderSecretRequest)
+		if !ok {
+			return nil, transport.ErrInvalidRequest
+		}
+		if err := validateRequest(req); err != nil {
+			return "", err
+		}
+		return m.OrderSecret(req)
+	}
+}
+
+//MakeFulfillOrderEndpoint -
+func MakeFulfillOrderEndpoint(m service.Service) endpoint.Endpoint {
+	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+		req, ok := request.(*api.FulfillOrderRequest)
+		if !ok {
+			return nil, transport.ErrInvalidRequest
+		}
+		if err := validateRequest(req); err != nil {
+			return "", err
+		}
+		return m.FulfillOrder(req)
+	}
+}
+
+//MakeFulfillOrderSecretEndpoint -
+func MakeFulfillOrderSecretEndpoint(m service.Service) endpoint.Endpoint {
+	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+		req, ok := request.(*api.FulfillOrderSecretRequest)
+		if !ok {
+			return nil, transport.ErrInvalidRequest
+		}
+		if err := validateRequest(req); err != nil {
+			return "", err
+		}
+		return m.FulfillOrderSecret(req)
+	}
+}
+
+//MakeStatusEndpoint -
+func MakeStatusEndpoint(m service.Service, nodeType string) endpoint.Endpoint {
+	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+		return m.Status(apiVersion, nodeType)
+	}
+}
+
+func validateRequest(req interface{}) error {
+	validate := validator.New()
+	validate.RegisterAlias("IPFS", "min=46,max=46,startswith=Q")
+	if err := validate.Struct(req); err != nil {
+		return errors.Wrap(transport.ErrInvalidRequest, err.Error())
+	}
+	return nil
+}
+
+func concatEndpoints(endpoints ...transport.HTTPEndpoints) transport.HTTPEndpoints {
+	var res = make(transport.HTTPEndpoints)
+	for _, endpoint := range endpoints {
+		for k, v := range endpoint {
+			res[k] = v
+		}
+	}
+	return res
+}
diff --git a/pkg/safeguardsecret/README.md b/pkg/safeguardsecret/README.md
new file mode 100644
index 0000000..8126c3d
--- /dev/null
+++ b/pkg/safeguardsecret/README.md
@@ -0,0 +1,34 @@
+# Safeguard secret
+
+This plugin enables you to use Milagro-D-TA to encrypt a string using milagro-crypto-c
+
+**You can see the API spec for this plugin in safeguardsecret-api.yaml**
+
+## Encrypt a String
+
+**Put In Your D-TA server's ID Doc IPFS address**
+
+```
+curl -X POST "http:localhost:5556/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"BeneficiaryIDDocumentCID\":\"QmaJAj18pABdfU777mhv3rBmAqZRbE6vr1JgrZ2BcXwWj3\",\"Extension\":{\"plainText\":\"Let's encrypt s0m3 d@t@\"}}"
+```
+
+
+
+## Decrypt a String
+
+**Swap In the correct Values from above**
+```
+curl -X POST "http:localhost:5556/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"OrderPart2CID\":\"QmXDdLPoeczWxzNFyxgSDkqxw71pnvBqB1xdW7XnyAPMJo\",\"BeneficiaryIDDocumentCID\":\"QmaJAj18pABdfU777mhv3rBmAqZRbE6vr1JgrZ2BcXwWj3\",\"Extension\":{\"cypherText\":\"3752ca1032ddba51b9525833550d509def1a9692d910b048172e7406ad40cbf1\",\"t\":\"b1e72740d16a6587496ec563\",\"v\":\"04dac12c6648f2c8e2f8c8522c46c70fdc0fe37f43ad855a11cb66132f1fab75ab1b8d9c1594a20c0dc947ef604e7339cbbe05a2d59965e0183bbf8d59a4f4821c\"}}"
+```
+
+## To Test the Plugin Code
+
+```
+cd ~/go/src/github.com/apache/incubator-milagro-dta/pkg/safeguardsecret
+
+go test
+
+```
+
+
+
diff --git a/pkg/safeguardsecret/open-api.yaml b/pkg/safeguardsecret/open-api.yaml
new file mode 100644
index 0000000..39f8a51
--- /dev/null
+++ b/pkg/safeguardsecret/open-api.yaml
@@ -0,0 +1,124 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+openapi: 3.0.0 
+info:
+  description: Milagro Secure - distributed / decentralized core security services.
+  title: Apache Milagro Server - Safeguard Secret
+  contact:
+    email: howard@qredo.com
+  license:
+    name: Apache Milagro
+  version: 0.0.1
+paths:  
+  /v1/order:
+    post:
+      summary: Post a string and get back the encrypted version
+      tags:
+        - safeguardSecret
+      requestBody:
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                beneficiaryIDDocumentCID:
+                  type: string                  
+                  example: QmfWg5GffUEzwahd9hkvdnqTGQs5PfusoEpx3kSDSdG4ze
+                extension:
+                  type: object
+                  properties:
+                    plainText:
+                      type: string
+                      example: S0m3 V3ry 1mp0rt@nt T3xt
+      responses:
+        '200':
+          $ref: '#/components/schemas/SafeguardSecret'
+  /v1/order/secret:
+    post:
+      summary: Release secret
+      tags:
+        - safeguardSecret
+      operationId: createkey
+      requestBody:
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                orderReference:
+                  type: string
+                  example: e1b3645e-b9ad-11e9-8d56-acde48001122
+                beneficiaryIDDocumentCID:
+                  type: string
+                  example: QmfWg5GffUEzwahd9hkvdnqTGQs5PfusoEpx3kSDSdG4ze
+                extension:
+                  type: object
+                  properties:
+                    cypherText:
+                      type: string
+                      example: a72d69d8fb151edde606163ff880ae4f572d40b5135816379c7f6438a66dee44
+                    t:
+                      type: string
+                      example: d9591744259dc7969084b659
+                    v: 
+                      type: string
+                      example: 04343b1aad4b00e32fd94c64b024ea387c366d967b5d6713c8ffb7d6b716f0e1b92561b43207f18a475365e1b112e9ae3ba8af0d3aa4cc1b0be880d6918a15fd6b
+      responses:
+        '200':
+          $ref: '#/components/schemas/DecryptAString'  
+servers:
+  - url: 'http://localhost:5556'
+  - url: 'http://localhost:5558'
+components:
+  schemas:
+    SafeguardSecret:
+      type: object
+      properties:
+        orderPart1CID:
+          type: string
+        orderPart2CID:
+          type: string
+        commitment:
+          type: string
+        createdAt:
+          type: integer
+        extension:
+          type: object
+          properties:
+            cypherText:
+              type: string
+            t:
+              type: string
+            v:
+              type: string
+    DecryptAString:
+      type: object
+      properties:
+        secret:
+          type: string
+        commitment:
+          type: string
+        extension:
+          type: object
+          properties:
+            plainText: 
+              type: string
+tags:
+  - name: safeguardSecret
+    description: D-TA Plugin for Encrypting Strings
+    
\ No newline at end of file
diff --git a/pkg/safeguardsecret/service.go b/pkg/safeguardsecret/service.go
new file mode 100644
index 0000000..12564a9
--- /dev/null
+++ b/pkg/safeguardsecret/service.go
@@ -0,0 +1,80 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package safeguardsecret - is an example of a D-TA plugin
+*/
+package safeguardsecret
+
+import (
+	"github.com/apache/incubator-milagro-dta/libs/crypto"
+	"github.com/apache/incubator-milagro-dta/libs/cryptowallet"
+	"github.com/apache/incubator-milagro-dta/libs/documents"
+	"github.com/apache/incubator-milagro-dta/pkg/api"
+	"github.com/apache/incubator-milagro-dta/pkg/defaultservice"
+)
+
+//Constants describe plugin and its creator
+var (
+	extensionVendor = "Milagro"
+	pluginName      = "safeguardsecret"
+)
+
+// Service implements Safeguard secret plugin service
+type Service struct {
+	defaultservice.Service
+}
+
+//NewService returns a new Safeguard secret implementation of Service
+func NewService() *Service {
+	return &Service{}
+}
+
+// Name of the plugin
+func (s *Service) Name() string {
+	return pluginName
+}
+
+// Vendor of the plugin
+func (s *Service) Vendor() string {
+	return extensionVendor
+}
+
+// PrepareOrderResponse gets the updated order and returns the commitment and extension
+func (s *Service) PrepareOrderResponse(orderPart2 *documents.OrderDoc, reqExtension, fulfillExtension map[string]string) (commitment string, extension map[string]string, err error) {
+	finalPublicKey := orderPart2.OrderPart2.CommitmentPublicKey
+	c, v, t, err := crypto.Secp256k1Encrypt(reqExtension["plainText"], finalPublicKey)
+
+	return finalPublicKey, map[string]string{"cypherText": c, "v": v, "t": t}, nil
+}
+
+// ProduceFinalSecret -
+func (s *Service) ProduceFinalSecret(seed, sikeSK []byte, order, orderPart4 *documents.OrderDoc, req *api.OrderSecretRequest, fulfillSecretRespomse *api.FulfillOrderSecretResponse) (secret, commitment string, extension map[string]string, err error) {
+	finalPrivateKey := orderPart4.OrderDocument.OrderPart4.Secret
+	//Derive the Public key from the supplied Private Key
+	finalPublicKey, _, err := cryptowallet.PublicKeyFromPrivate(finalPrivateKey)
+	if err != nil {
+		return "", "", nil, err
+	}
+
+	plainText, err := crypto.Secp256k1Decrypt(req.Extension["cypherText"], req.Extension["v"], req.Extension["t"], finalPrivateKey)
+	if err != nil {
+		return "", "", nil, err
+	}
+
+	return finalPrivateKey, finalPublicKey, map[string]string{"plainText": plainText}, nil
+}
diff --git a/pkg/service/service.go b/pkg/service/service.go
new file mode 100644
index 0000000..f03534a
--- /dev/null
+++ b/pkg/service/service.go
@@ -0,0 +1,51 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package service - defines core Milagro D-TA interface
+*/
+package service
+
+import "github.com/apache/incubator-milagro-dta/pkg/api"
+
+// Service is the CustodyService interface
+type Service interface {
+	//Identity
+	CreateIdentity(req *api.CreateIdentityRequest) (*api.CreateIdentityResponse, error)
+	GetIdentity(req *api.GetIdentityRequest) (*api.GetIdentityResponse, error)
+	IdentityList(req *api.IdentityListRequest) (*api.IdentityListResponse, error)
+
+	//Order
+	GetOrder(req *api.GetOrderRequest) (*api.GetOrderResponse, error)
+	OrderList(req *api.OrderListRequest) (*api.OrderListResponse, error)
+
+	//Order processing
+	OrderSecret(req *api.OrderSecretRequest) (*api.OrderSecretResponse, error)
+	Order(req *api.OrderRequest) (*api.OrderResponse, error)
+
+	//Fullfill processing
+	FulfillOrder(req *api.FulfillOrderRequest) (*api.FulfillOrderResponse, error)
+	FulfillOrderSecret(req *api.FulfillOrderSecretRequest) (*api.FulfillOrderSecretResponse, error)
+
+	NodeID() string
+	MasterFiduciaryNodeID() string
+	SetNodeID(nodeID string)
+	SetMasterFiduciaryNodeID(masterFiduciaryNodeID string)
+
+	//System
+	Status(apiVersion, nopdeType string) (*api.StatusResponse, error)
+}
diff --git a/plugins/bitcoinplugin.go b/plugins/bitcoinplugin.go
new file mode 100644
index 0000000..6dbee3f
--- /dev/null
+++ b/plugins/bitcoinplugin.go
@@ -0,0 +1,26 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package plugins
+
+import (
+	"github.com/apache/incubator-milagro-dta/pkg/bitcoinplugin"
+)
+
+func init() {
+	registerPlugin(bitcoinplugin.NewService())
+}
diff --git a/plugins/milagroplugin.go b/plugins/milagroplugin.go
new file mode 100644
index 0000000..9c80da3
--- /dev/null
+++ b/plugins/milagroplugin.go
@@ -0,0 +1,24 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package plugins
+
+import "github.com/apache/incubator-milagro-dta/pkg/defaultservice"
+
+func init() {
+	registerPlugin(defaultservice.NewService())
+}
diff --git a/plugins/plugin.go b/plugins/plugin.go
new file mode 100644
index 0000000..57f5cd7
--- /dev/null
+++ b/plugins/plugin.go
@@ -0,0 +1,71 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package plugins - registers plugins with the service
+*/
+package plugins
+
+import (
+	"io"
+
+	"github.com/apache/incubator-milagro-dta/libs/datastore"
+	"github.com/apache/incubator-milagro-dta/libs/ipfs"
+	"github.com/apache/incubator-milagro-dta/libs/logger"
+	"github.com/apache/incubator-milagro-dta/pkg/api"
+	"github.com/apache/incubator-milagro-dta/pkg/config"
+	"github.com/apache/incubator-milagro-dta/pkg/defaultservice"
+	"github.com/apache/incubator-milagro-dta/pkg/service"
+)
+
+var plugins []Plugin
+
+// Plugin is the main plugin interface
+type Plugin interface {
+	Name() string
+	Vendor() string
+}
+
+// ServicePlugin interface
+type ServicePlugin interface {
+	defaultservice.Plugable
+	service.Service
+
+	Init(plugin defaultservice.Plugable, logger *logger.Logger, rng io.Reader, store *datastore.Store, ipfsConnector ipfs.Connector, masterFiduciaryServer api.ClientService, cfg *config.Config) error
+}
+
+func registerPlugin(p Plugin) {
+	plugins = append(plugins, p)
+}
+
+// FindServicePlugin returns a registered ServicePlugin by name
+// Returns nil if the plugin is not loaded
+func FindServicePlugin(name string) ServicePlugin {
+
+	for _, p := range plugins {
+		sp, ok := p.(ServicePlugin)
+		if !ok {
+			continue
+		}
+
+		if sp.Name() == name {
+			return sp
+		}
+	}
+
+	return nil
+}
diff --git a/plugins/safeguardsecret.go b/plugins/safeguardsecret.go
new file mode 100644
index 0000000..3f2ceb2
--- /dev/null
+++ b/plugins/safeguardsecret.go
@@ -0,0 +1,26 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package plugins
+
+import (
+	"github.com/apache/incubator-milagro-dta/pkg/safeguardsecret"
+)
+
+func init() {
+	registerPlugin(safeguardsecret.NewService())
+}
diff --git a/test.sh b/test.sh
new file mode 100755
index 0000000..7c9b59c
--- /dev/null
+++ b/test.sh
@@ -0,0 +1,7 @@
+#! /bin/bash
+
+GO111MODULE=on go test -race -cover `go list ./... | grep -v disabled`
+
+status=$?
+
+exit $status