You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@milagro.apache.org by sm...@apache.org on 2019/10/01 08:41:51 UTC

[incubator-milagro-dta] 01/03: CreateIdentity as a new package

This is an automated email from the ASF dual-hosted git repository.

smihaylov pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-dta.git

commit ef993c8e3f195fdf930dbecd0a37183889c04870
Author: Stanislav Mihaylov <sm...@gmail.com>
AuthorDate: Tue Sep 24 13:49:12 2019 +0300

    CreateIdentity as a new package
---
 go.sum                         |  5 +++
 libs/documents/crypto.go       |  2 +-
 libs/documents/docs.go         | 21 ++++-----
 libs/documents/docs_test.go    | 19 ++++----
 pkg/bitcoinplugin/helpers.go   |  2 +-
 pkg/common/common.go           | 41 +++++-------------
 pkg/defaultservice/identity.go | 54 ++---------------------
 pkg/identity/identity.go       | 98 ++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 135 insertions(+), 107 deletions(-)

diff --git a/go.sum b/go.sum
index c31086c..aed6fea 100644
--- a/go.sum
+++ b/go.sum
@@ -56,6 +56,7 @@ 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=
@@ -85,6 +86,7 @@ github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3yg
 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/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 v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
 github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
@@ -537,6 +539,7 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
 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=
@@ -594,6 +597,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
 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/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
 github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
@@ -760,6 +764,7 @@ gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76
 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=
diff --git a/libs/documents/crypto.go b/libs/documents/crypto.go
index f504ec0..cfb7b05 100644
--- a/libs/documents/crypto.go
+++ b/libs/documents/crypto.go
@@ -56,7 +56,7 @@ func decapsulateWithRecipient(recipient Recipient, sikeSK []byte) ([]byte, error
 	return recreatedAesKey, nil
 }
 
-func encapsulateKeyForRecipient(recipientsIDDocs map[string]IDDoc, secret []byte) (recipientList []*Recipient, err error) {
+func encapsulateKeyForRecipient(recipientsIDDocs map[string]*IDDoc, secret []byte) (recipientList []*Recipient, err error) {
 	for id, idDocument := range recipientsIDDocs {
 		r := &Recipient{}
 		iv, err := cryptowallet.RandomBytes(16)
diff --git a/libs/documents/docs.go b/libs/documents/docs.go
index ae36c11..1b190a6 100644
--- a/libs/documents/docs.go
+++ b/libs/documents/docs.go
@@ -46,11 +46,11 @@ type OrderDoc struct {
 }
 
 //NewIDDoc generate a new empty IDDoc
-func NewIDDoc() IDDoc {
-	ret := IDDoc{}
-	ret.Header = &Header{}
-	ret.IDDocument = &IDDocument{}
-	return ret
+func NewIDDoc() *IDDoc {
+	return &IDDoc{
+		&Header{},
+		&IDDocument{},
+	}
 }
 
 //NewOrderDoc generate a new order
@@ -62,17 +62,14 @@ func NewOrderDoc() OrderDoc {
 }
 
 //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)
+func EncodeIDDocument(idDocument *IDDoc, blsSK []byte) ([]byte, error) {
+	rawDoc, err := Encode("", idDocument.IDDocument, nil, idDocument.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) {
+func EncodeOrderDocument(nodeID string, orderDoc OrderDoc, blsSK []byte, 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
@@ -169,7 +166,7 @@ func Decode(rawDoc []byte, tag string, sikeSK []byte, recipientID string, plainT
 
 //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) {
+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")
diff --git a/libs/documents/docs_test.go b/libs/documents/docs_test.go
index 40509e1..513fc7b 100644
--- a/libs/documents/docs_test.go
+++ b/libs/documents/docs_test.go
@@ -40,13 +40,13 @@ func Test_EnvelopeEncryption(t *testing.T) {
 
 	order, _ := BuildTestOrderDoc()
 	order.IPFSID = "NEW IPFS ID"
-	recipients := map[string]IDDoc{
+	recipients := map[string]*IDDoc{
 		id1: s1,
 	}
 	testText := "SEARCH_FOR_THIS123"
 	testTextBytes := []byte(testText)
 	order.Reference = testText
-	raw, _ := EncodeOrderDocument(id1, order, blsSK, "", recipients)
+	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")
 
@@ -64,10 +64,10 @@ func Test_EncodeDecodeOrderDoc(t *testing.T) {
 	s1, id1, _, sikeSK, blsPK, blsSK := BuildTestIDDoc()
 	order, _ := BuildTestOrderDoc()
 	order.IPFSID = "NEW IPFS ID"
-	recipients := map[string]IDDoc{
+	recipients := map[string]*IDDoc{
 		id1: s1,
 	}
-	raw, _ := EncodeOrderDocument(id1, order, blsSK, "PREVIOUSCID", recipients)
+	raw, _ := EncodeOrderDocument(id1, order, blsSK, recipients)
 	reconstitutedOrder := OrderDoc{}
 	_ = DecodeOrderDocument(raw, "NEW IPFS ID", &reconstitutedOrder, sikeSK, id1, blsPK)
 	order.Header.Recipients[0].CipherText = reconstitutedOrder.Header.Recipients[0].CipherText
@@ -87,7 +87,7 @@ func Test_EncodeDecodeID(t *testing.T) {
 	iddoc, tag, _, _, _, blsSK := BuildTestIDDoc()
 	raw, _ := EncodeIDDocument(iddoc, blsSK)
 	reconstitutedIDDoc := NewIDDoc()
-	_ = DecodeIDDocument(raw, tag, &reconstitutedIDDoc)
+	_ = DecodeIDDocument(raw, tag, reconstitutedIDDoc)
 	differences := deep.Equal(reconstitutedIDDoc, iddoc)
 	var failed = false
 	for _, diff := range differences {
@@ -112,7 +112,7 @@ func Test_AESPadding(t *testing.T) {
 func Test_EncodeDecode(t *testing.T) {
 	//These are some DocID for local user
 	s1, id1, _, sikeSK1, _, _ := BuildTestIDDoc()
-	recipients := map[string]IDDoc{
+	recipients := map[string]*IDDoc{
 		id1: s1,
 	}
 	seed, _ := cryptowallet.RandomBytes(16)
@@ -121,8 +121,6 @@ func Test_EncodeDecode(t *testing.T) {
 	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")
 
@@ -142,7 +140,6 @@ func Test_EncodeDecode(t *testing.T) {
 	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")
 }
 
@@ -181,7 +178,7 @@ func BuildTestOrderDoc() (OrderDoc, error) {
 	return order, nil
 }
 
-func BuildTestIDDoc() (IDDoc, string, []byte, []byte, []byte, []byte) {
+func BuildTestIDDoc() (*IDDoc, string, []byte, []byte, []byte, []byte) {
 	//make some test ID docs
 	seed, _ := cryptowallet.RandomBytes(16)
 
@@ -206,7 +203,7 @@ func BuildTestIDDoc() (IDDoc, string, []byte, []byte, []byte, []byte) {
 	iddoc := &IDDoc{}
 	rawDocI, _ := proto.Marshal(&signedEnvelope)
 	_ = DecodeIDDocument(rawDocI, ipfsID, iddoc)
-	return *iddoc, ipfsID, sikePK, sikeSK, blsPK, blsSK
+	return iddoc, ipfsID, sikePK, sikeSK, blsPK, blsSK
 }
 
 //createIDForSignedEnvelope - create a hash for the document to be used as an ID
diff --git a/pkg/bitcoinplugin/helpers.go b/pkg/bitcoinplugin/helpers.go
index eb65167..3a7880c 100644
--- a/pkg/bitcoinplugin/helpers.go
+++ b/pkg/bitcoinplugin/helpers.go
@@ -99,7 +99,7 @@ func adhocEncryptedEnvelopeEncode(s *Service, nodeID string, beneficiaryIDDocume
 	}
 	secretBody := &documents.SimpleString{Content: privateKeyPart1of2}
 	header := &documents.Header{}
-	recipients := map[string]documents.IDDoc{
+	recipients := map[string]*documents.IDDoc{
 		beneficiaryIDDocumentCID: beneficiaryIDDocument,
 	}
 	docEnv, err := documents.Encode(nodeID, nil, secretBody, header, blsSK, recipients)
diff --git a/pkg/common/common.go b/pkg/common/common.go
index b8b6b0c..6fefee7 100644
--- a/pkg/common/common.go
+++ b/pkg/common/common.go
@@ -22,9 +22,7 @@ package common
 
 import (
 	"encoding/hex"
-	"fmt"
 	"io"
-	"sync"
 	"time"
 
 	"github.com/apache/incubator-milagro-dta/libs/cryptowallet"
@@ -35,8 +33,6 @@ import (
 	"github.com/pkg/errors"
 )
 
-var previousIDMutex = &sync.Mutex{}
-
 //IdentitySecrets - keys required for decryption and signing
 type IdentitySecrets struct {
 	Name          string `json:"Name"`
@@ -74,14 +70,14 @@ func RetrieveOrderFromIPFS(ipfs ipfs.Connector, ipfsID string, sikeSK []byte, re
 }
 
 // RetrieveIDDocFromIPFS finds and parses the IDDocument
-func RetrieveIDDocFromIPFS(ipfs ipfs.Connector, ipfsID string) (documents.IDDoc, error) {
+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
+		return nil, err
 	}
 	err = documents.DecodeIDDocument(rawDocI, ipfsID, iddoc)
-	return *iddoc, err
+	return iddoc, err
 }
 
 // MakeRandomSeedAndStore genefates and stores a random seed
@@ -112,7 +108,7 @@ func RetrieveSeed(store *datastore.Store, reference string) (seedHex string, err
 }
 
 // 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) {
+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,
@@ -128,7 +124,7 @@ func CreateAndStoreOrderPart2(ipfs ipfs.Connector, store *datastore.Store, order
 }
 
 // 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) {
+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
@@ -147,7 +143,7 @@ func CreateAndStorePart3(ipfs ipfs.Connector, store *datastore.Store, order *doc
 }
 
 // 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) {
+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,
@@ -163,7 +159,7 @@ func CreateAndStoreOrderPart4(ipfs ipfs.Connector, store *datastore.Store, order
 }
 
 // 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
+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")
@@ -173,18 +169,7 @@ func WriteOrderToIPFS(nodeID string, ipfs ipfs.Connector, store *datastore.Store
 		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)
+	rawDoc, err := documents.EncodeOrderDocument(nodeID, *order, blsSecretKey, recipients)
 	if err != nil {
 		return "", errors.Wrap(err, "Failed to encode IDDocument")
 	}
@@ -192,13 +177,7 @@ func WriteOrderToIPFS(nodeID string, ipfs ipfs.Connector, store *datastore.Store
 	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")
 	}
@@ -241,7 +220,7 @@ func RetrieveIdentitySecrets(store *datastore.Store, nodeID string) (name string
 }
 
 // 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) {
+func BuildRecipientList(ipfs ipfs.Connector, localNodeDocCID, remoteNodeDocCID string) (map[string]*documents.IDDoc, error) {
 	remoteNodeDoc, err := RetrieveIDDocFromIPFS(ipfs, remoteNodeDocCID)
 	if err != nil {
 		return nil, err
@@ -252,7 +231,7 @@ func BuildRecipientList(ipfs ipfs.Connector, localNodeDocCID, remoteNodeDocCID s
 		return nil, err
 	}
 
-	recipients := map[string]documents.IDDoc{
+	recipients := map[string]*documents.IDDoc{
 		remoteNodeDocCID: remoteNodeDoc,
 		localNodeDocCID:  localNodeDoc,
 	}
diff --git a/pkg/defaultservice/identity.go b/pkg/defaultservice/identity.go
index d58aee8..ae256e5 100644
--- a/pkg/defaultservice/identity.go
+++ b/pkg/defaultservice/identity.go
@@ -19,67 +19,19 @@ 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/apache/incubator-milagro-dta/pkg/identity"
 	"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)
+	idDocumentCID, err := identity.CreateIdentity(req.Name, s.Ipfs, s.Store)
 	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 nil, err
 	}
 
 	return &api.CreateIdentityResponse{
diff --git a/pkg/identity/identity.go b/pkg/identity/identity.go
new file mode 100644
index 0000000..edbba97
--- /dev/null
+++ b/pkg/identity/identity.go
@@ -0,0 +1,98 @@
+// 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 identity - manage Identity document and keys
+*/
+package identity
+
+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/datastore"
+	"github.com/apache/incubator-milagro-dta/libs/documents"
+	"github.com/apache/incubator-milagro-dta/libs/ipfs"
+	"github.com/apache/incubator-milagro-dta/pkg/common"
+	"github.com/pkg/errors"
+)
+
+// CreateIdentity creates a new identity
+// returns Identity secrets and Identity document
+func CreateIdentity(name string, ipfsConn ipfs.Connector, store *datastore.Store) (idDocumentCID string, err error) {
+	//generate crypto random seed
+	seed, err := cryptowallet.RandomBytes(48)
+	if err != nil {
+		err = errors.Wrap(err, "Failed to generate random seed")
+		return
+	}
+
+	//Generate SIKE keys
+	rc1, sikePublicKey, sikeSecretKey := crypto.SIKEKeys(seed)
+	if rc1 != 0 {
+		err = errors.New("Failed to generate SIKE keys")
+		return
+	}
+
+	//Generate BLS keys
+	rc1, blsPublicKey, blsSecretKey := crypto.BLSKeys(seed, nil)
+	if rc1 != 0 {
+		err = errors.New("Failed to generate BLS keys")
+		return
+	}
+
+	ecPubKey, err := common.InitECKeys(seed)
+	if err != nil {
+		err = errors.Wrap(err, "Failed to generate EC Public Key")
+		return
+	}
+
+	//build ID Doc
+	idDocument := documents.NewIDDoc()
+	idDocument.AuthenticationReference = name
+	idDocument.BeneficiaryECPublicKey = ecPubKey
+	idDocument.SikePublicKey = sikePublicKey
+	idDocument.BLSPublicKey = blsPublicKey
+	idDocument.Timestamp = time.Now().Unix()
+
+	rawIDDoc, err := documents.EncodeIDDocument(idDocument, blsSecretKey)
+	if err != nil {
+		err = errors.Wrap(err, "Failed to encode IDDocument")
+		return
+	}
+
+	idDocumentCID, err = ipfsConn.Add(rawIDDoc)
+
+	secrets := common.IdentitySecrets{
+		Name:          name,
+		Seed:          hex.EncodeToString(seed),
+		BLSSecretKey:  hex.EncodeToString(blsSecretKey),
+		SikeSecretKey: hex.EncodeToString(sikeSecretKey),
+	}
+
+	if store != nil {
+		err = store.Set("id-doc", idDocumentCID, secrets, map[string]string{"time": time.Now().UTC().Format(time.RFC3339)})
+		if err != nil {
+			err = errors.Wrap(err, "Failed to store ID Document")
+			return
+		}
+	}
+
+	return idDocumentCID, nil
+}