Updated on 2022-09-08 GMT+08:00

Sample Application

This section provides an example application code and the corresponding chaincode to describe the use of the homomorphic encryption library. The main function of this application is money transfer between users, and the homomorphic encryption library is used to protect the transfer transaction information of the users.

The application involves three steps: user registration (including initializing the users' balances), money transfer, and balance query.

The application uses the command line interface (CLI) to perform service operations. The procedure is as follows.

Note

Query the domain names of orderers and peers in the downloaded sdk.yaml file, and add "EIP + Domain name of each orderer" and "EIP + Domain name of each peer" to the /etc/hosts file. When Fabric v1.1 is used, set public network IP addresses as the EIPs of peers. When Fabric1.4 is used, set private network IP addresses for the peers. Otherwise, the network cannot be connected, causing transaction verification failures.

Perform the following steps to add the domain name mapping of the orderers and peers to the /etc/hosts file:

X.X.X.X orderer-e5ad7831affbe8e6e2e7984b098f92406930a688-0.orderer-e5ad7831affbe8e6e2e7984b098f92406930a688.default.svc.cluster.local
X.X.X.X peer-d524b0817aaed85490368776cb88042a149a56b5-0.peer-d524b0817aaed85490368776cb88042a149a56b5.default.svc.cluster.local
X.X.X.X peer-d524b0817aaed85490368776cb88042a149a56b5-1.peer-d524b0817aaed85490368776cb88042a149a56b5.default.svc.cluster.local

Use real EIPs to replace X.X.X.X.

Registration

Usage:
  appdemo register [flags]
Flags:
  -C, --channel string       channel id (default "mychannel")
  -c, --config string        configuration file path (default "./config_test.yaml")
  -I, --idcc string          idendity chaincode name (default "IDChaincode")
  -i, --initbalance string   init initbalance
  -o, --orgid string         organization id (default "org1")
  -p, --protectpwd string    protect pwd
  -T, --txcc string          transaction chaincode name (default "TxChaincode")
  -u, --userid string        user id 
./appdemo register -u A -p test -i 100 

If you do not set certain parameters, the default values are used. For the default values, see the Flags part. If a configured value is different from the default value, specify it for the parameter.

  • Generating a pair of public and private keys for homogenous encryption

When a new user registers, a pair of public and private keys are generated for the user (identified by the user ID). This demo writes the key pair to the local ${userid} .data file for each user.

privKeyStr, pubKeyStr, err := pswapi_sdk.GenerateKey(propwd)
check(err)
fmt.Println("key is nil")
userdata.PubKey = pubKeyStr
userdata.PriKey = privKeyStr
  • Registering the public key

The Fabric SDK API is invoked to initiate registration with the IDChaincode, carrying the generated public key.

The registration is implemented using the chaincode function of blockchains. Public keys are registered for sharing. During the money transfer transaction, the public key of the payer is used to encrypt the transaction data to protect privacy. Only the private key holder can decrypt the transaction data.

res, err := sdk_client.Invoke(setup, "Register", [][]byte{[]byte(userdata.PubKey), []byte(senderAddr)})  
if err != nil {
     fmt.Println("Fail to register user pk ", err.Error())  
} else {
     addrByte := res[0].ProposalResponse.GetResponse().Payload
     fmt.Println("Register addr: ", string(addrByte))
  }
  • Registering the initial balance
    1. The sdk.InitBalance API is used to initialize and encrypt the balance, generating the initial balanceinfo.
    2. The balanceinfo is sent to the transaction chaincode.
balanceInfo, err := pswapi_sdk.InitBalance(initbalance, userdata.PubKey) check(err)
setup.ChainCodeID = txchaincode
_, err = sdk_client.Invoke(setup, "init", [][]byte{[]byte(userdata.PubKey), []byte(balanceInfo)})
 if err != nil {
    fmt.Println("Initbalance error for user: ", senderAddr, err.Error())
 } else {
    fmt.Println("init balance successfully: ", senderAddr)
 }
 check(err)

Transaction

Usage:
  appdemo transaction [flags]
Flags:
  -b, --AddrB string        B' addr
  -t, --Tx string           Transaction Num
  -C, --channel string      channel id (default "mychannel")
  -c, --config string       configuration file path (default "./config_test.yaml")
  -I, --idcc string         idendity chaincode name (default "IDChaincode")
  -o, --orgid string        organization id (default "org1")
  -p, --protectpwd string   protect pwd
  -T, --txcc string         transaction chaincode name (default "TxChaincode")
  -u, --userid string       user id 
./appdemo transaction -u A -p test -b a0760184f7ed24e0d86f5b2df40a973a9e1b5da9a1ae886532ac9cd634b59d59 -t 10
// Note: The character string following -b is the account address of user B (displayed upon successful registration of user B).

Query

Usage:
  appdemo querybalance [flags]
Flags:
  -C, --channel string      channel id (default "mychannel")
  -c, --config string       configuration file path (default "./config_test.yaml")
  -I, --idcc string         idendity chaincode name (default "IDChaincode")
  -o, --orgid string        organization id (default "org1")
  -p, --protectpwd string   protect pwd
  -T, --txcc string         transaction chaincode name (default "TxChaincode")
  -u, --userid string       user id
./appdemo querybalance -p test -u A

Query code:

  1. The InitBalance API provided by the SDK is invoked to initialize the balance.
  2. The Fabirc SDK is invoked to send the transaction information.
    get balance
     setup.ChainCodeID = txchaincode
     transRec := sdk_client.TransRecord{}
    
     fmt.Println("query balance")
    
     resps, err := sdk_client.Query(setup, "QueryBalance", [][]byte{[]byte(addrA)})
     if err != nil {
      fmt.Println("Fail to query balance :", err.Error())
      return err
     }
    
     err = json.Unmarshal(resps[0].ProposalResponse.GetResponse().Payload, &transRec)
     if err != nil {
      fmt.Println("unmarshal query result error: ", err.Error())
      return err
     }

    decrypt balance
    
     curbalance, err := pswapi_sdk.Decrypt(transRec.Balance, userdata.PriKey, propwd)
     if err != nil {
      fmt.Println("sdk Decrypt error: ", err.Error())
      return err
     }
    
     fmt.Println("current balance:" + curbalance.String())