#  Paillier 寮€鍙戞墜鍐�

鏈枃鍒嗕负涓ら儴鍒嗭細

1. 鏂规鎺ュ彛銆佸伐鍏枫€佸悎绾DK浠嬬粛锛氬 ChainMaker 鐨� cmc 宸ュ叿銆佸悎绾� SDK 鍜� common 搴撴彁渚涚殑绠楁硶鐨勪粙缁嶃€�
2. 鐢ㄤ緥锛氫粙缁嶄簡濡備綍浣跨敤 ChainMaker Paillier 鍔熻兘锛屼粠 Paillier 鍏閽ョ敓鎴愩€佺紪鍐欐櫤鑳藉悎绾﹀埌浣跨敤 SDK锛堟湰鏂囦娇鐢� go 鐨� SDK锛� 杩涜鏁版嵁鐨勫姞瀵嗕笂閾俱€侀摼涓婂悓鎬佽繍绠楀拰鑾峰彇杩愮畻缁撴灉瑙e瘑銆�

## 鎺ュ彛銆佸伐鍏枫€佸悎绾DK浠嬬粛

`common`鎻愪緵 paillier 鍗婂悓鎬佸姞瀵嗙殑鍩虹鑳藉姏銆�

`cmc`宸ュ叿鎻愪緵浜嗙敓鎴愬叕绉侀挜銆佸姞瑙e瘑鐨勮兘鍔涳紝鏂逛究鐢ㄦ埛蹇€熶綋楠屽悓鎬佸姞瀵嗗姛鑳姐€�

`鍚堢害SDK`鎻愪緵浜嗛摼涓婂悓鎬佽繍绠楃殑鑳藉姏锛岀洰鍓嶆敮鎸佸悓鎬佽繍绠楃殑鍚堢害 SDK 鏈夛細Go銆丷ust銆�

### CMC 宸ュ叿瀛愬懡浠� paillier 浠嬬粛

绠€浠�

CMC 涓殑 paillier 鍛戒护鏄敤浜庤緟鍔﹑aillier绠楁硶鐨勪娇鐢紝鐢熸垚鍏挜鍜岀閽ワ紝骞朵笖鏍规嵁鍙傛暟淇濆瓨鍒版寚瀹氫綅缃€�

浣跨敤`./cmc paillier -h`鑾峰彇浣跨敤甯姪锛�

```shell
./cmc paillier -h                       
ChainMaker paillier command

Usage:
  cmc paillier [command]

Available Commands:
  genKey      Generate paillier's private, public Keys, and storage.

Flags:
  -h, --help   help for paillier

Use "cmc paillier [command] --help" for more information about a command.

```

genKey绠€浠�

`genKey`鐢ㄤ簬鐢熸垚 paillier 绠楁硶鐨勫叕绉侀挜锛屽苟鏍规嵁鍙傛暟淇濆瓨鍒版寚瀹氫綅缃紝鏌ョ湅鍛戒护璇︽儏锛�

```shell
./cmc paillier genKey -h
generates paillier private public key

Usage:
  cmc paillier genKey [flags]

Flags:
  -h, --help          help for genKey
      --name string
      --path string   the result storage file path, and the file name is the id

```

genKey鍙傛暟璇﹁В锛�

```
-h, --help锛氳幏鍙栦娇鐢ㄥ府鍔�
--name锛氱敤浜庝繚瀛樺叕绉侀挜鐨勬枃浠跺悕锛屽叕閽ュ拰绉侀挜鏂囦欢鍚嶇浉鍚岋紝鍚庣紑鍒嗗埆涓篳.prv`銆乣.pub`
--path锛氬瓨鍌ㄨ矾寰�
```


### common 绠楁硶閮ㄥ垎浠嬬粛

#### 鍏挜鏂规硶

PubKey 鎻愪緵浜嗗簭鍒楀寲銆佸弽搴忓垪鍖栥€佸姞瀵嗗拰鍚屾€佽繍绠楁柟娉曘€�


**Encrypt**锛氬姞瀵嗕竴涓猙ig.Int绫诲瀷鐨勬暟寰楀埌瀵瑰簲鐨勫瘑鏂�

Arguments:

- plaintext锛氱敤浜庡姞瀵嗙殑鏄庢枃

return:

- Ct锛氬姞瀵嗗緱鍒扮殑瀵嗘枃
- error锛氬彲鑳藉嚭鐜扮殑閿欒

```go
Encrypt(plainText *big.Int) (*Ciphertext, error)
```



鍚屾€佽繍绠楁柟娉曪紝鍚屾€佽繍绠椾竴鑸湪閾句笂杩涜锛屾墍浠ヤ竴鑸笉浼氫娇鐢ㄥ埌杩欏嚑涓柟娉曪紝鑰屾槸浣跨敤鍚堢害SDK鎻愪緵鐨勫悓鎬佽繍绠楁柟娉曪紝杩欓噷涓嶅啀璇︾粏鎻忚堪銆�

```go
// 涓や釜瀵嗘枃鐩稿姞锛岃繑鍥炵粨鏋滃瘑鏂�
AddCiphertext(cipher1, cipher2 *Ciphertext) (*Ciphertext, error))

// 瀵嗘枃鍔犳槑鏂囷紝杩斿洖缁撴灉瀵嗘枃
AddPlaintext(cipher *Ciphertext, constant *big.Int) (*Ciphertext, error)

// 瀵嗘枃鍑忓瘑鏂囷紝杩斿洖缁撴灉瀵嗘枃
SubCiphertext(cipher1, cipher2 *Ciphertext) (*Ciphertext, error)

// 瀵嗘枃鍑忔槑鏂囷紝杩斿洖缁撴灉瀵嗘枃
SubPlaintext(cipher *Ciphertext, constant *big.Int) (*Ciphertext, error)

// 瀵嗘枃涔樹互鏄庢枃锛岃繑鍥炵粨鏋滃瘑鏂�
NumMul(cipher *Ciphertext, constant *big.Int)
```

#### 绉侀挜鏂规硶

PrvKey 鎻愪緵浜嗗寘鍚� PubKey 鎵€鏈夌殑鏂规硶浠ュ強鑾峰彇鍏挜銆佽В瀵嗘柟娉曘€�



**Decrypt**锛氳В瀵嗗瘑鏂囧緱鍒板搴旂殑鏄庢枃

Arguments:

- ciphertext锛氱敤浜庤В瀵嗙殑瀵嗘枃

return锛�

- *big.Int锛氳В瀵嗗緱鍒扮殑鏄庢枃
- error锛氬彲鑳藉嚭鐜扮殑閿欒

```go
Decrypt(ciphertext *Ciphertext) (*big.Int, error))
```



**GetPubKey**锛氭牴鎹閽ヨ幏鍙栧叕閽�

return锛�

- *PubKey锛氬叕閽�
- error锛氬彲鑳藉嚭鐜扮殑閿欒

```go
GetPubKey() (*PubKey, error)
```

#### GenKey

GenKey 鐢ㄤ簬鍒濆鍖栧叕绉侀挜瀵�

return锛�

- *PrvKey锛氱敓鎴愮殑绉侀挜锛堝叕閽ュ彲浠ヤ粠绉侀挜涓幏鍙栵級
- error锛氬彲鑳藉嚭鐜扮殑閿欒

```go
GenKey() (*PrvKey, error)
```

### 鏅鸿兘鍚堢害SDK

Go 鍜� Rust 鍚堢害SDK鎻愪緵浜嗚繘琛屽悓鎬佽繍绠楃殑鏂规硶銆�

#### go

PaillierContext 鎺ュ彛鎻愪緵浜嗗悓鎬佽繍绠楁柟娉�

**AddCiphertext**锛氫娇鐢ㄥ叕閽ヨ繘琛屽瘑鏂囧姞瀵嗘枃鐨勫悓鎬佽繍绠�

Arguments:

- pubKey锛氬叕閽ョ殑瀛楄妭鏁扮粍
- ct1锛氬瘑鏂囧瓧鑺傛暟缁�
- ct1锛氬瘑鏂囧瓧鑺傛暟缁�

return锛�

- []byte缁撴灉瀵嗘枃瀛楄妭鏁扮粍
- ResultCode锛氬嚱鏁版墽琛岀姸鎬佺爜

~~~go
AddCiphertext(pubKey []byte, ct1 []byte, ct2 []byte) ([]byte, ResultCode)
~~~

**AddPlaintext**锛氫娇鐢ㄥ叕閽ヨ繘琛屽瘑鏂囧姞鏄庢枃鐨勫悓鎬佽繍绠�

Argumengs:

- pubKey锛氬叕閽ュ瓧鑺傛暟缁�
- ct锛氬瘑鏂囧瓧鑺傛暟缁�
- pt锛氭槑鏂囷紝int64鐨勫瓧绗︿覆琛ㄧず锛岃秴鍑篿nt64閾句笂鎵ц灏嗕細鎶ラ敊

return锛�

- []byte锛氱粨鏋滃瘑鏂囧瓧鑺傛暟缁�
- ResultCode锛氬嚱鏁版墽琛岀姸鎬佺爜

~~~go
AddPlaintext(pubKey, ct []byte, pt string) ([]byte, ResultCode)
~~~

**SubCiphertext**锛氫娇鐢ㄥ叕閽ヨ繘琛屽瘑鏂囧噺瀵嗘枃鐨勫悓鎬佽繍绠�

Arguments:

- pubKey锛氬叕閽ョ殑瀛楄妭鏁扮粍
- ct1锛氬瘑鏂囧瓧鑺傛暟缁�
- ct1锛氬瘑鏂囧瓧鑺傛暟缁�

return锛�

- []byte锛氱粨鏋滃瘑鏂囧瓧鑺傛暟缁�
- ResultCode锛氬嚱鏁版墽琛岀姸鎬佺爜


~~~go
SubCiphertext(pubKey, ct1, ct2 []byte) ([]byte, ResultCode)
~~~

**SubPlaintext**锛氫娇鐢ㄥ叕閽ヨ繘琛屽瘑鏂囧噺鏄庢枃鐨勫悓鎬佽繍绠�

Argumengs:

- pubKey锛氬叕閽ュ瓧鑺傛暟缁�
- ct锛氬瘑鏂囧瓧鑺傛暟缁�
- pt锛氭槑鏂囷紝int64鐨勫瓧绗︿覆琛ㄧず锛岃秴鍑篿nt64閾句笂鎵ц灏嗕細鎶ラ敊

return锛�

- []byte锛氱粨鏋滃瘑鏂囧瓧鑺傛暟缁�
- ResultCode锛氬嚱鏁版墽琛岀姸鎬佺爜


~~~go
SubPlaintext(pubKey, ct []byte, pt string) ([]byte, ResultCode)
~~~

**NumMul**锛氫娇鐢ㄥ叕閽ヨ繘琛屽瘑鏂囦箻鏄庢枃鐨勫悓鎬佽繍绠�

Argumengs:

- pubKey锛氬叕閽ュ瓧鑺傛暟缁�
- ct锛氬瘑鏂囧瓧鑺傛暟缁�
- pt锛氭槑鏂囷紝int64鐨勫瓧绗︿覆琛ㄧず锛岃秴鍑篿nt64閾句笂鎵ц灏嗕細鎶ラ敊

return锛�

- []byte锛氱粨鏋滃瘑鏂囧瓧鑺傛暟缁�
- ResultCode锛氬嚱鏁版墽琛岀姸鎬佺爜


~~~go
NumMul(pubKey, ct []byte, pt string) ([]byte, ResultCode)
~~~

#### rust

rust鍚堢害涓巊o鍚堢害鐩稿悓锛岀敱trait `PaillierSimContext`鎻愪緵浜嗗悓鎬佽繍绠楃殑鏂规硶锛�

**add_ciphertext**锛氫娇鐢ㄥ叕閽ヨ绠椾袱涓瘑鏂囩殑鍜�

Argument锛�

- pubKey锛氫袱涓瘑鏂囩殑鍏挜
- ciphertext1锛氬瘑鏂�
- ciphertext2锛氬瘑鏂�

return锛�

- return1: 璁$畻缁撴灉
- return2: 鍑芥暟鎵ц鐘舵€佺爜锛�0锛歴uccess, 1: failed

```rust
fn add_ciphertext(
    &self,
    pubkey: Vec<u8>,
    ciphertext1: Vec<u8>,
    ciphertext2: Vec<u8>,
) -> Result<Vec<u8>, result_code>;
```

**add_plaintext**锛氫娇鐢ㄥ叕閽ヨ绠楀瘑鏂囦笌鏄庢枃鐨勫拰

Argument锛�

- pubKey锛氫袱涓瘑鏂囩殑鍏挜
- ciphertext锛氬瘑鏂�
- plaintext锛氭槑鏂囷紝i64鐨勫瓧绗︿覆琛ㄧず锛岃秴鍑篿64閾句笂鎵ц灏嗕細鎶ラ敊

return锛�

- return1: 璁$畻缁撴灉
- return2: 鍑芥暟鎵ц鐘舵€佺爜锛�0锛歴uccess, 1: failed

```rust
fn add_plaintext(
    &self,
    pubkey: Vec<u8>,
    ciphertext: Vec<u8>,
    plaintext: &str,
) -> Result<Vec<u8>, result_code>;
```

**sub_ciphertext**锛氫娇鐢ㄥ叕閽ヨ绠楀瘑鏂囧噺鍘诲瘑鏂�

Argument锛�

- pubKey锛氫袱涓瘑鏂囩殑鍏挜
- ciphertext1锛氬瘑鏂�
- ciphertext2锛氬瘑鏂�

return锛�

- return1: 璁$畻缁撴灉
- return2: 鍑芥暟鎵ц鐘舵€佺爜锛�0锛歴uccess, 1: failed

```rust
fn sub_ciphertext(
    &self,
    pubkey: Vec<u8>,
    ciphertext1: Vec<u8>,
    ciphertext2: Vec<u8>,
) -> Result<Vec<u8>, result_code>;
```

**sub_plaintext**锛氫娇鐢ㄥ叕閽ヨ绠楀瘑鏂囧噺鏄庢枃

Argument锛�

- pubKey锛氫袱涓瘑鏂囩殑鍏挜
- ciphertext锛氬瘑鏂�
- plaintext锛氭槑鏂囷紝i64鐨勫瓧绗︿覆琛ㄧず锛岃秴鍑篿64閾句笂鎵ц灏嗕細鎶ラ敊

return锛�

- return1: 璁$畻缁撴灉
- return2: 鍑芥暟鎵ц鐘舵€佺爜锛�0锛歴uccess, 1: failed

```rust
fn sub_plaintext(
     &self,
     pubkey: Vec<u8>,
     ciphertext: Vec<u8>,
     plaintext: &str,
) -> Result<Vec<u8>, result_code>;
```

**num_mul**锛氫娇鐢ㄥ叕閽ヨ绠楀瘑鏂囦箻鏄庢枃

Argument锛�

- pubKey锛氫袱涓瘑鏂囩殑鍏挜
- ciphertext锛氬瘑鏂�
- plaintext锛氭槑鏂囷紝i64鐨勫瓧绗︿覆琛ㄧず锛岃秴鍑篿64閾句笂鎵ц灏嗕細鎶ラ敊

return锛�

- return1: 璁$畻缁撴灉
- return2: 鍑芥暟鎵ц鐘舵€佺爜锛�0锛歴uccess, 1: failed

```rust
fn num_mul(
    &self,
    pubkey: Vec<u8>,
    ciphertext: Vec<u8>,
    plaintext: &str,
) -> Result<Vec<u8>, result_code>;
```



## 鐢ㄤ緥

### 1. 浣跨敤cmc paillier鐢熸垚骞朵繚瀛樿嚜宸辩殑鍏閽�

```sh
./cmc paillier genKey --name=test1 --path=./paillier-key
[paillier Private Key] storage file path: paillier-key/test1.prvKey
[paillier Public Key] storage file path: paillier-key/test1.pubKey
```

浼氬湪褰撳墠鐩綍鐢熸垚锛宲aillier-key鏂囦欢澶癸紝鏉ヤ繚瀛樼敓鎴愮殑鍏閽ユ枃浠讹紝濡備笅锛�

```shell
tree ./paillier-key
./paillier-key
鈹溾攢鈹€ test1.prvKey
鈹斺攢鈹€ test1.pubKey
```



### 2. 缂栧啓鏅鸿兘鍚堢害

go锛�

```go
package main

import (
	"encoding/base64"
	"strconv"
)

// 瀹夎鍚堢害鏃朵細鎵ц姝ゆ柟娉曪紝蹇呴』
//export init_contract
func initContract() {
	// 姝ゅ鍙啓瀹夎鍚堢害鐨勫垵濮嬪寲閫昏緫

}

// 鍗囩骇鍚堢害鏃朵細鎵ц姝ゆ柟娉曪紝蹇呴』
//export upgrade
func upgrade() {
	// 姝ゅ鍙啓鍗囩骇鍚堢害鐨勯€昏緫

}

//export paillier_test_set
func paillier_test_set() {
	pubkeyBytes, _ := Arg("pubkey")
	handletype, _ := Arg("handletype")
	encodePara1, _ := Arg("para1")
	encodePara2, _ := Arg("para2")

	para1Bytes, _ := base64.StdEncoding.DecodeString(encodePara1)
	var result_code ResultCode
	var result_data []byte
	var result_data_str string
	test := NewPaillierContext()
	if handletype == "AddCiphertext" {
		para2Bytes, _ := base64.StdEncoding.DecodeString(encodePara2)
		result_data, result_code = test.AddCiphertext([]byte(pubkeyBytes), para1Bytes, para2Bytes)
	} else if handletype == "AddPlaintext" {
		result_data, result_code = test.AddPlaintext([]byte(pubkeyBytes), para1Bytes, encodePara2)
	} else if handletype == "SubCiphertext" {
		para2Bytes, _ := base64.StdEncoding.DecodeString(encodePara2)
		result_data, result_code = test.SubCiphertext([]byte(pubkeyBytes), para1Bytes, para2Bytes)
	} else if handletype == "SubPlaintext" {
		result_data, result_code = test.SubPlaintext([]byte(pubkeyBytes), para1Bytes, encodePara2)
	} else if handletype == "NumMul" {
		result_data, result_code = test.NumMul([]byte(pubkeyBytes), para1Bytes, encodePara2)
	} else {
		ErrorResult("finish paillier_test_set failure: error para: " + handletype)
	}
    
	if result_code != SUCCESS {
		ErrorResult("finish paillier_test_set failure: error result code: " + string(result_code))
	}

	result_data_str = base64.StdEncoding.EncodeToString(result_data)

	result := PutState("paillier_test", handletype, result_data_str)
	if result_code == 0 {
		SuccessResult("finish paillier_test_set success")
	} else {
		ErrorResult("finish paillier_test_set failure")
	}
}

//export paillier_test_get
func paillier_test_get() {
	handletype, _ := Arg("handletype")
	value, result := GetState("paillier_test", handletype)
	SuccessResult(value)
}

//export bulletproofs_test_set
func bulletproofs_test_set() {
	LogMessage("[bulletproofs] ========================================start")
	LogMessage("[bulletproofs] bulletproofs_test_set")
	handleType, _ := Arg("handletype")
	param1, _ := Arg("para1")
	param2, _ := Arg("para2")

	param1Bytes, _ := base64.StdEncoding.DecodeString(param1)
	var result_code ResultCode
	var result_data []byte
	var result_data_str string
	bulletproofsContext := NewBulletproofsContext()
	switch handleType {
	case BulletproofsOpTypePedersenAddNum:
		result_data, result_code = bulletproofsContext.PedersenAddNum(param1Bytes, param2)
	case BulletproofsOpTypePedersenAddCommitment:
		param2Bytes, _ := base64.StdEncoding.DecodeString(param2)
		result_data, result_code = bulletproofsContext.PedersenAddCommitment(param1Bytes, param2Bytes)
	case BulletproofsOpTypePedersenSubNum:
		result_data, result_code = bulletproofsContext.PedersenSubNum(param1Bytes, param2)
	case BulletproofsOpTypePedersenSubCommitment:
		param2Bytes, _ := base64.StdEncoding.DecodeString(param2)
		result_data, result_code = bulletproofsContext.PedersenSubCommitment(param1Bytes, param2Bytes)
	case BulletproofsOpTypePedersenMulNum:
		result_data, result_code = bulletproofsContext.PedersenMulNum(param1Bytes, param2)
	case BulletproofsVerify:
		param2Bytes, _ := base64.StdEncoding.DecodeString(param2)
		result_data, result_code = bulletproofsContext.Verify(param1Bytes, param2Bytes)
	default:
		ErrorResult("bulletproofs_test_set failed, error: " + handleType)
		result_code = 1
	}

	if result_code != SUCCESS {
		ErrorResult("bulletproofs_test_set failed, error: " + string(rune(result_code)))
	}

	result_data_str = base64.StdEncoding.EncodeToString(result_data)

	result := PutState("bulletproofs_test", handleType, result_data_str)
    
	if result_code == 0 {
		SuccessResult("bulletproofs_test_set success")
	} else {
		ErrorResult("bulletproofs_test_set failure")
	}
}

//export bulletproofs_test_get
func bulletproofs_test_get() {
	handletype, _ := Arg("handletype")
	value, result := GetState("bulletproofs_test", handletype)
    
	if handletype == "BulletproofsVerify" {
		decodeValue, err := base64.StdEncoding.DecodeString(value)
		if err != nil {
			ErrorResult("base64.StdEncoding.DecodeString(value) failed")
		}
		LogMessage(handletype)
		SuccessResult(string(decodeValue))
	} else {
		LogMessage(handletype)
		SuccessResult(value)
	}
}

func main() {

}
```

缂栬瘧鐢熸垚wasm鏂囦欢锛�

```shell
tinygo build -no-debug -opt=s -o contract-paillier.wasm -target wasm
```



rust:

```rust
// 瀹夎鍚堢害鏃朵細鎵ц姝ゆ柟娉曪紝蹇呴』
#[no_mangle]
pub extern "C" fn init_contract() {
    // 瀹夎鏃剁殑涓氬姟閫昏緫锛屽彲涓虹┖
    sim_context::log("init_contract");
}

// 鍗囩骇鍚堢害鏃朵細鎵ц姝ゆ柟娉曪紝蹇呴』
#[no_mangle]
pub extern "C" fn upgrade() {
    // 鍗囩骇鏃剁殑涓氬姟閫昏緫锛屽彲涓虹┖
    sim_context::log("upgrade success");
}

#[no_mangle]
pub extern "C" fn paillier_test_set() {
    sim_context::log("[paillier] ========================================start");
    sim_context::log("[paillier] input func: paillier_test_set");

    let ctx = sim_context::get_sim_context();
    let pubkey = ctx.arg_default_blank("pubkey");

    let handletype = ctx.arg_default_blank("handletype");

    let para1 = ctx.arg_default_blank("para1");
    let decode_para1 = decode(para1.as_bytes()).unwrap();

    let para2 = ctx.arg_default_blank("para2");

    let test = ctx.get_paillier_sim_context();
    let r: Result<Vec<u8>, i32>;
    if handletype == "AddCiphertext" {
        let decode_para2 = decode(para2.as_bytes()).unwrap();
        r = test.add_ciphertext(pubkey.into_bytes(), decode_para1, decode_para2);
    } else if handletype == "AddPlaintext" {
        r = test.add_plaintext(pubkey.into_bytes(), decode_para1, &para2);
    } else if handletype == "SubCiphertext" {
        let decode_para2 = decode(para2.as_bytes()).unwrap();
        r = test.sub_ciphertext(pubkey.into_bytes(), decode_para1, decode_para2);
    } else if handletype == "SubPlaintext" {
        r = test.sub_plaintext(pubkey.into_bytes(), decode_para1, &para2);
    } else if handletype == "NumMul" {
        r = test.num_mul(pubkey.into_bytes(), decode_para1, &para2);
    } else {
        ctx.error(&format!(
            "finish paillier_test_set failure: error para: {}",
            handletype
        ));
        return;
    }
    if r.is_err() {
        ctx.error("finish paillier_test_set failure");
        return;
    }

    let data = r.unwrap();
    let data_u8 = data.as_slice();
    let data_str = encode(data_u8);

    let put_code = ctx.put_state("paillier_test", &handletype, data_str.as_bytes());
    ctx.ok("finish paillier_test_set success".as_bytes());
}

#[no_mangle]
pub extern "C" fn paillier_test_get() {
    let ctx = sim_context::get_sim_context();
    let handletype = ctx.arg_default_blank("handletype");
    let r = ctx.get_state("paillier_test", &handletype);
    if r.is_err() {
        sim_context::log("[zitao] paillier_test_get error");
        ctx.error("finish paillier_test_get failure");
        return;
    }
    let data = r.unwrap();

    let result = String::from_utf8(data);
    let result_str = result.unwrap();

    ctx.ok(result_str.as_bytes());
}
```

缂栬瘧鐢熸垚wasm瀛楄妭鐮佹枃浠�

```shell
make build
```



### 3. 浣跨敤SDK缂栧啓娴嬭瘯鐢ㄤ緥

> SDK骞舵湭鎻愪緵 paillier 鐩稿叧鎺ュ彛锛屽紑鍙戣€呴渶瑕佺洿鎺ヨ皟鐢╟ommon搴撲腑鐨� *chainmaker.org/sdk-go/common/crypto/paillier*鍖呫€�

鎬绘祴璇曞嚱鏁帮細

```go
const (
	sdkConfigOrg1Client1Path = "../sdk_configs/sdk_config_org1_client1.yml"

	createContractTimeout = 5
)

const (

	// go 鍚堢害
	paillierContractName = "pailliergo100001"
	paillierByteCodePath = "../../testdata/paillier-wasm-demo/contract-paillier.wasm"
	runtime              = common.RuntimeType_GASM

	// rust 鍚堢害
	//paillierContractName = "paillier-rust-10001"
	//paillierByteCodePath = "./testdata/counter-go-demo/chainmaker_contract.wasm"
	//runtime              = common.RuntimeType_WASMER

	paillierPubKeyFilePath = "../../testdata/paillier-key/test1.pubKey"
	paillierPrvKeyFilePath = "../../testdata/paillier-key/test1.prvKey"
)

func main() {
	TestPaillierContractCounterGo()
}

func TestPaillierContractCounterGo() {
	t := new(testing.T)
	client, err := examples.CreateChainClientWithSDKConf(sdkConfigOrg1Client1Path)
	require.Nil(t, err)

	fmt.Println("======================================= 鍒涘缓鍚堢害锛堝紓姝ワ級=======================================")
	testPaillierCreate(client, examples.UserNameOrg1Admin1, examples.UserNameOrg2Admin1, examples.UserNameOrg3Admin1, examples.UserNameOrg4Admin1, false)
	time.Sleep(5 * time.Second)

	fmt.Println("======================================= 璋冪敤鍚堢害杩愮畻锛堝紓姝ワ級=======================================")
	testPaillierOperation(client, "paillier_test_set", false)
	time.Sleep(5 * time.Second)

	fmt.Println("======================================= 鏌ヨ缁撴灉骞惰В瀵嗭紙寮傛锛�=======================================")
	testPaillierQueryResult(t, client, "paillier_test_get")
}
```

鍒涘缓鍚堢害锛�

```go
// 鍒涘缓鍚堢害
func testPaillierCreate(client *sdk.ChainClient, admin1, admin2, admin3,
	admin4 string, withSyncResult bool) {
	resp, err := createUserContract(client, admin1, admin2, admin3, admin4,
		paillierContractName, examples.Version, paillierByteCodePath, runtime, []*common.KeyValuePair{}, withSyncResult)
	if err != nil {
		log.Fatalln(err)
	}

	fmt.Printf("CREATE contract-hibe-1 contract resp: %+v\n", resp)
}

func createUserContract(client *sdk.ChainClient, admin1, admin2, admin3, admin4 string,
	contractName, version, byteCodePath string, runtime common.RuntimeType, kvs []*common.KeyValuePair, withSyncResult bool) (*common.TxResponse, error) {

	payload, err := client.CreateContractCreatePayload(contractName, version, byteCodePath, runtime, kvs)
	if err != nil {
		return nil, err
	}

	endorsers, err := examples.GetEndorsers(payload, admin1, admin2, admin3, admin4)
	if err != nil {
		return nil, err
	}

	resp, err := client.SendContractManageRequest(payload, endorsers, createContractTimeout, withSyncResult)
	if err != nil {
		return nil, err
	}

	return resp, nil
}
```



璋冪敤鍚堢害鏂规硶杩涜閾句笂鍚屾€佽繍绠楋細

```go
// 璋冪敤鍚堢害杩涜鍚屾€佽繍绠�
func testPaillierOperation(client *sdk.ChainClient, s string, b bool) {
	pubKeyBytes, err := ioutil.ReadFile(paillierPubKeyFilePath)
	//require.Nil(t, err)
	if err != nil {
		log.Fatalln(err)
	}
	payloadParams, err := CreatePaillierTransactionPayloadParams(pubKeyBytes, 1, 1000000)
	resp, err := client.InvokeContract(paillierContractName, s, "", payloadParams, -1, b)
	//require.Nil(t, err)
	if err != nil {
		log.Fatalln(err)
	}

	if resp.Code != common.TxStatusCode_SUCCESS {
		fmt.Printf("invoke contract failed, [code:%d]/[msg:%s]\n", resp.Code, resp.Message)
	}

}

func CreatePaillierTransactionPayloadParams(pubKeyBytes []byte, plaintext1, plaintext2 int64) ([]*common.KeyValuePair, error) {
	pubKey := new(paillier.PubKey)
	err := pubKey.Unmarshal(pubKeyBytes)
	if err != nil {

	}

	pt1 := new(big.Int).SetInt64(plaintext1)
	ciphertext1, err := pubKey.Encrypt(pt1)
	if err != nil {
		return nil, err
	}
	ct1Bytes, err := ciphertext1.Marshal()
	if err != nil {
		return nil, err
	}

	prv2, _ := paillier.GenKey()

	pub2, _ := prv2.GetPubKey()
	_, _ = pub2.Marshal()

	pt2 := new(big.Int).SetInt64(plaintext2)
	ciphertext2, err := pubKey.Encrypt(pt2)
	if err != nil {
		return nil, err
	}
	ct2Bytes, err := ciphertext2.Marshal()
	if err != nil {
		return nil, err
	}

	ct1Str := base64.StdEncoding.EncodeToString(ct1Bytes)
	ct2Str := base64.StdEncoding.EncodeToString(ct2Bytes)

	payloadParams := []*common.KeyValuePair{
		{
			Key:   "handletype",
			Value: []byte("SubCiphertext"),
		},
		{
			Key:   "para1",
			Value: []byte(ct1Str),
		},
		{
			Key:   "para2",
			Value: []byte(ct2Str),
		},
		{
			Key:   "pubkey",
			Value: pubKeyBytes,
		},
	}
	/*
		old
		payloadParams := make(map[string]string)
		//payloadParams["handletype"] = "AddCiphertext"
		//payloadParams["handletype"] = "AddPlaintext"
		payloadParams["handletype"] = "SubCiphertext"
		//payloadParams["handletype"] = "SubCiphertextStr"
		//payloadParams["handletype"] = "SubPlaintext"
		//payloadParams["handletype"] = "NumMul"

		payloadParams["para1"] = ct1Str
		payloadParams["para2"] = ct2Str
		payloadParams["pubkey"] = string(pubKeyBytes)
	*/

	return payloadParams, nil
}
```

鏌ヨ杩愮畻缁撴灉骞惰В瀵嗭細

```go
// 鏌ヨ鍚屾€佹墽琛岀粨鏋滃苟瑙e瘑
func testPaillierQueryResult(t *testing.T, c *sdk.ChainClient, s string) {
	//paillierMethod := "AddCiphertext"
	//paillierMethod := "AddPlaintext"
	paillierMethod := "SubCiphertext"
	//paillierMethod := "SubCiphertextStr"
	//paillierMethod := "SubPlaintext"
	params1, err := QueryPaillierResult(c, paillierContractName, s, paillierMethod, -1, paillierPrvKeyFilePath)
	require.Nil(t, err)
	fmt.Printf("QUERY %s contract resp -> encrypt(cipher 10): %d\n", paillierContractName, params1)
}

func QueryPaillierResult(c *sdk.ChainClient, contractName, method, paillierDataItemId string, timeout int64, paillierPrvKeyPath string) (int64, error) {

	resultStr, err := QueryPaillierResultById(c, contractName, method, paillierDataItemId, timeout)
	if err != nil {
		return 0, err
	}

	ct := new(paillier.Ciphertext)
	resultBytes, err := base64.StdEncoding.DecodeString(string(resultStr))
	if err != nil {
		return 0, err
	}
	err = ct.Unmarshal(resultBytes)
	if err != nil {
		return 0, err
	}

	prvKey := new(paillier.PrvKey)

	prvKeyBytes, err := ioutil.ReadFile(paillierPrvKeyPath)
	if err != nil {
		return 0, fmt.Errorf("open paillierKey file failed, [err:%s]", err)
	}

	err = prvKey.Unmarshal(prvKeyBytes)
	if err != nil {
		return 0, err
	}

	decrypt, err := prvKey.Decrypt(ct)
	if err != nil {
		return 0, err
	}

	return decrypt.Int64(), nil
}

func QueryPaillierResultById(c *sdk.ChainClient, contractName, method, paillierMethod string, timeout int64) ([]byte, error) {
	pairs := []*common.KeyValuePair{
		{Key: "handletype", Value: []byte(paillierMethod)},
	}

	/*
		old
		pairsMap := make(map[string]string)
		pairsMap["handletype"] = paillierMethod
	*/

	resp, err := c.QueryContract(contractName, method, pairs, timeout)
	if err != nil {
		return nil, err
	}

	result := resp.ContractResult.Result

	return result, nil
}

```

鎵ц娴嬭瘯锛岀粨鏋滃涓嬶細

```go
=== RUN   TestPaillierContractCounterGo
======================================= 鍒涘缓鍚堢害锛堝紓姝ワ級=======================================
CREATE contract-paillier-1 contract resp: message:"OK" contract_result:<result:"5aa609367c8342e08459ec1ec1321b954d88569399284277bcc5887b72d8d2c5" message:"OK" > 
======================================= 璋冪敤鍚堢害杩愮畻锛堝紓姝ワ級=======================================
invoke contract success, resp: [code:0]/[msg:OK]/[txId:81ac75ccc8914ce694a0df6ddebe2c5fddea319d784a461cb52ec9b5fc373125]
======================================= 鏌ヨ缁撴灉骞惰В瀵嗭紙寮傛锛�=======================================
QUERY paillier-rust-10001 contract resp -> encrypt(cipher 10): -999999
--- PASS: TestPaillierContractCounterGo (19.23s)
PASS
```