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

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

commit c8dab8c507da4d5de7e2e51046c0ff9f7bd32d1d
Author: Christopher Morris <[email protected]>
AuthorDate: Wed Aug 28 14:43:28 2019 +0100

    Qredo Plugin
---
 pkg/qredoplugin/coin.go         | 176 +++++++++++++++++++++++++++++++
 pkg/qredoplugin/coin_test.go    |  52 ++++++++++
 pkg/qredoplugin/helpers.go      | 225 ++++++++++++++++++++++++++++++++++++++++
 pkg/qredoplugin/helpers_test.go |  47 +++++++++
 pkg/qredoplugin/service.go      | 103 ++++++++++++++++++
 plugins/qredoplugin.go          |   9 ++
 6 files changed, 612 insertions(+)

diff --git a/pkg/qredoplugin/coin.go b/pkg/qredoplugin/coin.go
new file mode 100644
index 0000000..c2a6cfa
--- /dev/null
+++ b/pkg/qredoplugin/coin.go
@@ -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.
+
+package qredoplugin
+
+/*
+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"
+       "fmt"
+       "strings"
+
+       "github.com/btcsuite/btcd/btcec"
+       "github.com/btcsuite/btcd/chaincfg"
+       "github.com/btcsuite/btcutil"
+       ethcrypto "github.com/ethereum/go-ethereum/crypto"
+       "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{
+       "rdd":     {name: "reddcoin", symbol: "rdd", xpubkey: 0x3d, 
xprivatekey: 0xbd},
+       "dgb":     {name: "digibyte", symbol: "dgb", xpubkey: 0x1e, 
xprivatekey: 0x80},
+       "doge":    {name: "dogecoin", symbol: "doge", xpubkey: 0x1e, 
xprivatekey: 0x9e},
+       "via":     {name: "viacoin", symbol: "via", xpubkey: 0x47, xprivatekey: 
0xc7},
+       "btc":     {name: "bitcoin", symbol: "btc", xpubkey: 0x00, xprivatekey: 
0x80},
+       "testbtc": {name: "bitcoin testnet", symbol: "btc", xpubkey: 0x6f, 
xprivatekey: 0xef},
+       "ltc":     {name: "litecoin", symbol: "ltc", xpubkey: 0x30, 
xprivatekey: 0xb0},
+}
+
+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)
+       case 2: //litecoin
+               return network["ltc"].pubkeyToAddress(pubKeyBytes, false)
+       case 3: //Dogecoin
+               return network["doge"].pubkeyToAddress(pubKeyBytes, false)
+       case 60: //Ethereum
+               compByte, err := hex.DecodeString(publicKey)
+               pubKey, err := btcec.ParsePubKey([]byte(compByte), btcec.S256())
+               if err != nil {
+                       return "", errors.Wrap(err, "Failed to generate 
Ethereum Address")
+               }
+               pubECDSA := pubKey.ToECDSA()
+               address1 := ethcrypto.PubkeyToAddress(*pubECDSA)
+               retAddress := fmt.Sprintf("%x", address1)
+               return retAddress, nil
+               // case 128: //Monero
+               // case 144: //Ripple
+               // case 145: //Bitcoin Cash
+               // case 148: //Stellar
+               // case 1815: //Cardano
+       }
+       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)
+       case 2: //litecoin
+               return network["ltc"].privkeyToAddress(privateKey, false)
+       case 3: //Dogecoin
+               return network["doge"].privkeyToAddress(privateKey, false)
+       case 60: //Ethereum
+               _, cpub1 := btcec.PrivKeyFromBytes(btcec.S256(), privateKey)
+               pubKey := cpub1.SerializeUncompressed()
+               address := ethcrypto.Keccak256(pubKey[1:])[12:]
+               addRet := strings.ToLower(fmt.Sprintf("%x", address))
+               return addRet, nil
+               // case 128: //Monero
+               // case 144: //Ripple
+               // case 145: //Bitcoin Cash
+               // case 148: //Stellar
+               // case 1815: //Cardano
+       }
+       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/qredoplugin/coin_test.go b/pkg/qredoplugin/coin_test.go
new file mode 100644
index 0000000..9d9cff6
--- /dev/null
+++ b/pkg/qredoplugin/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 qredoplugin
+
+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/qredoplugin/helpers.go b/pkg/qredoplugin/helpers.go
new file mode 100644
index 0000000..9295106
--- /dev/null
+++ b/pkg/qredoplugin/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 qredoplugin
+
+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/qredoplugin/helpers_test.go b/pkg/qredoplugin/helpers_test.go
new file mode 100644
index 0000000..857e2fa
--- /dev/null
+++ b/pkg/qredoplugin/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 qredoplugin
+
+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/qredoplugin/service.go b/pkg/qredoplugin/service.go
new file mode 100644
index 0000000..855b2fe
--- /dev/null
+++ b/pkg/qredoplugin/service.go
@@ -0,0 +1,103 @@
+package qredoplugin
+
+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 = "Qredo"
+       pluginName      = "qredoplugin"
+)
+
+// Service is the Qredo Plugin 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
+}
+
+// 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) {
+       //There is no beneficiary supplided in either the Deposit or Redemption
+       if order.BeneficiaryCID == "" && req.BeneficiaryIDDocumentCID == "" {
+               return nil, nil, errors.New("Beneficiary must be supplied")
+       }
+
+       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/plugins/qredoplugin.go b/plugins/qredoplugin.go
new file mode 100644
index 0000000..68bf54d
--- /dev/null
+++ b/plugins/qredoplugin.go
@@ -0,0 +1,9 @@
+package plugins
+
+import (
+       "github.com/apache/incubator-milagro-dta/pkg/qredoplugin"
+)
+
+func init() {
+       registerPlugin(qredoplugin.NewService())
+}

Reply via email to