Commit 175b6ea3 authored by pengjun's avatar pengjun

init chain33-sdk-go

parent fce9f88a
# chain33-sdk-go
chain33 sdk golang
### 接口文档
#### 1. 账户相关
#### 1.1 创建账户
**函数原型**
```
NewAccount(signType string) (*Account, error)
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|signType|string|是|签名类型,支持"secp256k1",默认"secp256k1"|
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|Account|PrivateKey []byte | 私钥
| |PublicKey []byte| 公钥
| |Address string | 地址
| |SignType string| 签名类型
#### 1.2 交易签名
**函数原型**
```
SignRawTransaction(raw string, privateKey string, signType string) (string, error)
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|raw|string|是|原始交易数据|
|privateKey|string|是|私钥|
|signType|string|是|签名类型|
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|result|string | 签名后的交易
#### 2. 代理重加密
#### 2.1 生成对称加密秘钥
**函数原型**
```
GenerateEncryptKey(pubOwner []byte) ([]byte, string, string)
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|pubOwner|[]byte|是|加密用户非对称秘钥公钥|
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|key |[]byte | 对称加密秘钥
|pub_r |string | 随机公钥r,用于重加密授权
|pub_u |string | 随机公钥u,用于重加密授权
#### 2.2 生成重加密秘钥分片
**函数原型**
```
GenerateKeyFragments(privOwner []byte, pubRecipient []byte, numSplit, threshold int) ([]*KFrag, error)
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|privOwner |[]byte|是|共享用户私钥|
|pubRecipient |[]byte|是|授权用户公钥|
|numSplit |int |是|秘钥分片数|
|threshold |int|是|最小秘钥分片重组阈值,不得大于numSplit|
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|KFrag |Random string | 随机数,每个分片不同
| |Value string | 重加密证明,每个分片不同
| |PrecurPub string | 随机公钥,所有分片相同
|err |error | 错误返回
#### 2.3 重组重加密秘钥分片
**函数原型**
```
AssembleReencryptFragment(privRecipient []byte, reKeyFrags []*ReKeyFrag) ([]byte, error)
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|privRecipient |[]byte|是|授权用户私钥|
|reKeyFrags |ReKeyFrag|是|重加密秘钥分片,从各个重加密节点获取|
```
type ReKeyFrag struct {
ReKeyR string // 重加密证明R
ReKeyU string // 重加密证明U
Random string // 随机数,每个分片不同
PrecurPub string // 随机公钥,所有分片相同
}
```
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|key |[]byte | 重组后的对称秘钥
|err |error | 错误返回
#### 3. RPC客户端
#### 3.1 创建jsonRPC客户端
**函数原型**
```
NewJSONClient(prefix, url string) (*JSONClient, error)
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|prefix |string|是|前缀|
|url |string|是|rpc服务端连接|
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|JSONClient |JSONClient | 客户端对象
|err |error | 错误返回
#### 3.2 rpc调用
**函数原型**
```
JSONClient.Call(method string, params, resp interface{}) error
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|method |string|是|rpc调用方法|
|params |interface|是|调用方法对应的参数|
|resp |interface|是|调用方法对应的返回值|
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|err |error | 错误返回
#### 3.3 发送交易
**函数原型**
```
JSONClient.SendTransaction(signedTx string) (string, error)
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|signedTx |string|是|已签名的交易|
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|string |string | 返回哈希
|err |error | 错误返回
#### 3.4 交易查询
**函数原型**
```
JSONClient.QueryTransaction(hash string) (*TransactionDetail, error)
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|hash |string|是|交易哈希|
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|TransactionDetail |TransactionDetail | 交易详情
|err |error | 错误返回
package sdk
import (
"errors"
"github.com/33cn/chain33-sdk-go/crypto"
"github.com/33cn/chain33-sdk-go/crypto/gm"
)
type Account struct {
PrivateKey []byte
PublicKey []byte
Address string
SignType string
}
func NewAccount(signType string) (*Account, error) {
if signType == "" {
signType = crypto.SECP256K1
}
account := Account{}
account.SignType = signType
if signType == crypto.SECP256K1 {
account.PrivateKey = crypto.GeneratePrivateKey()
account.PublicKey = crypto.PubKeyFromPrivate(account.PrivateKey)
addr, err := crypto.PubKeyToAddress(account.PublicKey)
if err != nil {
return nil, err
}
account.Address = addr
} else if signType == crypto.SM2 {
account.PrivateKey, account.PublicKey = gm.GenetateKey()
addr, err := crypto.PubKeyToAddress(account.PublicKey)
if err != nil {
return nil, err
}
account.Address = addr
} else if signType == crypto.ED25519 {
// TODO
} else {
return nil, errors.New("sign type not support")
}
return &account, nil
}
\ No newline at end of file
// Copyright Fuzamei Corp. 2020 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package jsonclient 实现JSON rpc客户端请求功能
package client
import (
"bytes"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"github.com/golang/protobuf/proto"
"io/ioutil"
"net/http"
"strings"
)
// JSONClient a object of jsonclient
type JSONClient struct {
url string
prefix string
tlsVerify bool
client *http.Client
}
func addPrefix(prefix, name string) string {
if strings.Contains(name, ".") {
return name
}
return prefix + "." + name
}
// NewJSONClient produce a json object
func NewJSONClient(prefix, url string) (*JSONClient, error) {
return new(prefix, url, false)
}
// New produce a jsonclient by perfix and url
func new(prefix, url string, tlsVerify bool) (*JSONClient, error) {
httpcli := http.DefaultClient
if strings.Contains(url, "https") { //暂不校验tls证书
httpcli = &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !tlsVerify}}}
}
return &JSONClient{
url: url,
prefix: prefix,
tlsVerify: tlsVerify,
client: httpcli,
}, nil
}
type clientRequest struct {
Method string `json:"method"`
Params [1]interface{} `json:"params"`
ID uint64 `json:"id"`
}
type clientResponse struct {
ID uint64 `json:"id"`
Result *json.RawMessage `json:"result"`
Error interface{} `json:"error"`
}
func (client *JSONClient) Call(method string, params, resp interface{}) error {
method = addPrefix(client.prefix, method)
req := &clientRequest{}
req.Method = method
req.Params[0] = params
data, err := json.Marshal(req)
if err != nil {
return err
}
postresp, err := client.client.Post(client.url, "application/json", bytes.NewBuffer(data))
if err != nil {
return err
}
defer postresp.Body.Close()
b, err := ioutil.ReadAll(postresp.Body)
if err != nil {
return err
}
cresp := &clientResponse{}
err = json.Unmarshal(b, &cresp)
if err != nil {
return err
}
if cresp.Error != nil {
x, ok := cresp.Error.(string)
if !ok {
return fmt.Errorf("invalid error %v", cresp.Error)
}
if x == "" {
x = "unspecified error"
}
return fmt.Errorf(x)
}
if cresp.Result == nil {
return errors.New("Empty result")
}
if msg, ok := resp.(proto.Message); ok {
var str json.RawMessage
err = json.Unmarshal(*cresp.Result, &str)
if err != nil {
return err
}
b, err := str.MarshalJSON()
if err != nil {
return err
}
err = json.Unmarshal(b, msg)
if err != nil {
fmt.Println("err", err)
return err
}
return nil
}
return json.Unmarshal(*cresp.Result, resp)
}
type ParseFunc func(result json.RawMessage) (interface{},error)
//回调函数,用于自定义解析返回得result数据
func (client *JSONClient) CallBack(method string, params interface{},parseFunc ParseFunc) (interface{}, error) {
method = addPrefix(client.prefix, method)
req := &clientRequest{}
req.Method = method
req.Params[0] = params
data, err := json.Marshal(req)
if err != nil {
return nil, err
}
postresp, err := client.client.Post(client.url, "application/json", bytes.NewBuffer(data))
if err != nil {
return nil, err
}
defer postresp.Body.Close()
b, err := ioutil.ReadAll(postresp.Body)
if err != nil {
return nil, err
}
cresp := &clientResponse{}
err = json.Unmarshal(b, &cresp)
if err != nil {
return nil, err
}
if cresp.Error != nil {
x, ok := cresp.Error.(string)
if !ok {
return nil, fmt.Errorf("invalid error %v", cresp.Error)
}
if x == "" {
x = "unspecified error"
}
return nil, fmt.Errorf(x)
}
if cresp.Result == nil {
return nil, errors.New("Empty result")
}
return parseFunc(*cresp.Result)
}
// 发送交易
func (client *JSONClient) SendTransaction(signedTx string) (string, error) {
var res string
send := &RawParm{
Token: "BTY",
Data: signedTx,
}
err := client.Call("Chain33.SendTransaction", send, &res)
if err != nil {
return "", err
}
return res, nil
}
// 查询交易
func (client *JSONClient) QueryTransaction(hash string) (*TransactionDetail, error) {
query := QueryParm{
Hash: hash,
}
var detail TransactionDetail
err := client.Call("Chain33.QueryTransaction", query, &detail)
if err != nil {
return nil, err
}
return &detail, nil
}
package client
import "encoding/json"
// RawParm defines raw parameter command
type RawParm struct {
Token string `json:"token"`
Data string `json:"data"`
}
// CreateTxIn create tx input
type CreateTxIn struct {
Execer string `json:"execer"`
ActionName string `json:"actionName"`
Payload json.RawMessage `json:"payload"`
}
// QueryParm Query parameter
type QueryParm struct {
Hash string `json:"hash"`
}
// Signature parameter
type Signature struct {
Ty int32 `json:"ty"`
Pubkey string `json:"pubkey"`
Signature string `json:"signature"`
}
// Transaction parameter
type Transaction struct {
Execer string `json:"execer"`
Payload json.RawMessage `json:"payload"`
RawPayload string `json:"rawPayload"`
Signature *Signature `json:"signature"`
Fee int64 `json:"fee"`
FeeFmt string `json:"feefmt"`
Expire int64 `json:"expire"`
Nonce int64 `json:"nonce"`
From string `json:"from,omitempty"`
To string `json:"to"`
Amount int64 `json:"amount,omitempty"`
AmountFmt string `json:"amountfmt,omitempty"`
GroupCount int32 `json:"groupCount,omitempty"`
Header string `json:"header,omitempty"`
Next string `json:"next,omitempty"`
Hash string `json:"hash,omitempty"`
}
// ReceiptDataResult receipt data result
type ReceiptDataResult struct {
Ty int32 `json:"ty"`
TyName string `json:"tyName"`
Logs []*ReceiptLogResult `json:"logs"`
}
// ReceiptLogResult receipt log result
type ReceiptLogResult struct {
Ty int32 `json:"ty"`
TyName string `json:"tyName"`
Log json.RawMessage `json:"log"`
RawLog string `json:"rawLog"`
}
// Asset asset
type Asset struct {
Exec string `json:"exec"`
Symbol string `json:"symbol"`
Amount int64 `json:"amount"`
}
// TxProof :
type TxProof struct {
Proofs []string `json:"proofs"`
Index uint32 `json:"index"`
RootHash string `json:"rootHash"`
}
// TransactionDetail transaction detail
type TransactionDetail struct {
Tx *Transaction `json:"tx"`
Receipt *ReceiptDataResult `json:"receipt"`
Proofs []string `json:"proofs"`
Height int64 `json:"height"`
Index int64 `json:"index"`
Blocktime int64 `json:"blockTime"`
Amount int64 `json:"amount"`
Fromaddr string `json:"fromAddr"`
ActionName string `json:"actionName"`
Assets []*Asset `json:"assets"`
TxProofs []*TxProof `json:"txProofs"`
FullHash string `json:"fullHash"`
}
// Query4Jrpc query jrpc
type Query4Jrpc struct {
Execer string `json:"execer"`
FuncName string `json:"funcName"`
Payload json.RawMessage `json:"payload"`
}
package crypto
import (
"crypto/sha256"
"fmt"
"github.com/mr-tron/base58/base58"
)
//不同币种的前缀版本号
var coinPrefix = map[string][]byte{
"BTC": {0x00},
"BCH": {0x00},
"BTY": {0x00},
"LTC": {0x30},
"ZEC": {0x1c, 0xb8},
"USDT": {0x00},
}
var addrSeed = []byte("address seed bytes for public key")
//MaxExecNameLength 执行器名最大长度
const MaxExecNameLength = 100
func PubKeyToAddress(pub []byte) (addr string, err error) {
if len(pub) != 33 && len(pub) != 65 { //压缩格式 与 非压缩格式
return "", fmt.Errorf("invalid public key byte")
}
//添加版本号
hash160res := append(coinPrefix["BTY"], Rimp160(pub)...)
//添加校验码
cksum := checksum(hash160res)
address := append(hash160res, cksum[:]...)
//地址进行base58编码
addr = base58.Encode(address)
return
}
//checksum: first four bytes of double-SHA256.
func checksum(input []byte) (cksum [4]byte) {
h := sha256.New()
_, err := h.Write(input)
if err != nil {
return
}
intermediateHash := h.Sum(nil)
h.Reset()
_, err = h.Write(intermediateHash)
if err != nil {
return
}
finalHash := h.Sum(nil)
copy(cksum[:], finalHash[:])
return
}
func GetExecAddress(name string) string {
if len(name) > MaxExecNameLength {
panic("name too long")
}
var bname [200]byte
buf := append(bname[:0], addrSeed...)
buf = append(buf, []byte(name)...)
pub := Sha2Sum(buf)
var ad [25]byte
ad[0] = 0
copy(ad[1:21], Rimp160(pub))
sh := Sha2Sum(ad[0:21])
checksum := make([]byte, 4)
copy(checksum, sh[:4])
copy(ad[21:25], checksum[:])
addr := base58.Encode(ad[:])
return addr
}
\ No newline at end of file
package crypto
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"errors"
"io"
)
const (
AESPrivateKeyLength = 16
)
func pkcs7Padding(src []byte) []byte {
padding := aes.BlockSize - len(src)%aes.BlockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(src, padtext...)
}
func aesCBCEncrypt(key, s []byte) ([]byte, error) {
return aesCBCEncryptWithRand(rand.Reader, key, s)
}
func aesCBCEncryptWithRand(prng io.Reader, key, s []byte) ([]byte, error) {
if len(s)%aes.BlockSize != 0 {
return nil, errors.New("Invalid plaintext. It must be a multiple of the block size")
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
ciphertext := make([]byte, aes.BlockSize+len(s))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(prng, iv); err != nil {
return nil, err
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], s)
return ciphertext, nil
}
func aesCBCDecrypt(key, src []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(src) < aes.BlockSize {
return nil, errors.New("Invalid ciphertext. It must be a multiple of the block size")
}
iv := src[:aes.BlockSize]
src = src[aes.BlockSize:]
if len(src)%aes.BlockSize != 0 {
return nil, errors.New("Invalid ciphertext. It must be a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(src, src)
return src, nil
}
func pkcs7UnPadding(src []byte) ([]byte, error) {
length := len(src)
unpadding := int(src[length-1])
if unpadding > aes.BlockSize || unpadding == 0 {
return nil, errors.New("Invalid pkcs7 padding (unpadding > aes.BlockSize || unpadding == 0)")
}
pad := src[len(src)-unpadding:]
for i := 0; i < unpadding; i++ {
if pad[i] != byte(unpadding) {
return nil, errors.New("Invalid pkcs7 padding (pad[i] != unpadding)")
}
}
return src[:(length - unpadding)], nil
}
func AESCBCPKCS7Encrypt(key, src []byte) ([]byte, error) {
tmp := pkcs7Padding(src)
return aesCBCEncrypt(key, tmp)
}
func AESCBCPKCS7Decrypt(key, src []byte) ([]byte, error) {
pt, err := aesCBCDecrypt(key, src)
if err == nil {
return pkcs7UnPadding(pt)
}
return nil, err
}
func GenetateAESKey() []byte {
return getRandBytes(AESPrivateKeyLength)
}
\ No newline at end of file
package crypto
import (
"bytes"
"crypto/rand"
secp256k1 "github.com/btcsuite/btcd/btcec"
)
var (
SECP256K1 = "secp256k1"
SM2 = "sm2"
ED25519 = "ed25519" //TODO
)
func GeneratePrivateKey() []byte {
privKeyBytes := make([]byte, 32)
for {
key := getRandBytes(32)
if bytes.Compare(key, secp256k1.S256().Params().N.Bytes()) >= 0 {
continue
}
copy(privKeyBytes[:], key)
break
}
priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKeyBytes[:])
copy(privKeyBytes[:], priv.Serialize())
return privKeyBytes
}
func PubKeyFromPrivate(privKey []byte) []byte {
_, pub := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey[:])
pubSecp256k1 := make([]byte, 33)
copy(pubSecp256k1[:], pub.SerializeCompressed())
return pubSecp256k1
}
func Sign(msg []byte, privKey []byte) []byte {
priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey[:])
sig, err := priv.Sign(Sha256(msg))
if err != nil {
panic("Error signing secp256k1" + err.Error())
}
return sig.Serialize()
}
func PrivateFromByte(privKey []byte) *secp256k1.PrivateKey {
priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey[:])
return priv
}
func PublicFromByte(pubKey []byte) *secp256k1.PublicKey {
pub, _ := secp256k1.ParsePubKey(pubKey, secp256k1.S256())
return pub
}
func getRandBytes(numBytes int) []byte {
b := make([]byte, numBytes)
_, err := rand.Read(b)
if err != nil {
panic("Panic on a Crisis" + err.Error())
}
return b
}
\ No newline at end of file
package crypto
import (
"fmt"
"github.com/33cn/chain33-sdk-go/crypto/gm"
"github.com/33cn/chain33-sdk-go/types"
"github.com/stretchr/testify/assert"
"testing"
)
func TestAES(t *testing.T) {
var text = "hello aes"
var key = getRandBytes(16)
cipherText, err := AESCBCPKCS7Encrypt(key, []byte(text))
if err != nil {
fmt.Println(err)
return
}
cipher, err := AESCBCPKCS7Decrypt(key, cipherText)
if err != nil {
fmt.Println(err)
return
}
assert.Equal(t, text, string(cipher))
}
func TestSign(t *testing.T) {
priv, _ := types.FromHex("0xc2b31057b8692a56c7dd18199df71c1d21b781c0b6858c52997c9dbf778e8550")
msg := []byte("sign test")
sig := Sign(msg, priv)
fmt.Printf("sig = %x\n", sig)
}
func TestSM2(t *testing.T) {
priv, pub := gm.GenetateKey()
fmt.Println(types.ToHex(pub))
msg := []byte("sign test")
sig := gm.SM2Sign(msg, priv, nil)
fmt.Printf("sig = %x\n", sig)
result := gm.SM2Verify(msg, pub, sig, nil)
fmt.Println(result)
}
func TestSM4(t *testing.T) {
key := []byte{0x1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}
fmt.Printf("key = %v\n", key)
data := []byte{0x1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}
fmt.Printf("data = %x\n", data)
d0 := gm.SM4Encrypt(key, data)
fmt.Printf("d0 = %x\n", d0)
d1 := gm.SM4Decrypt(key, d0)
fmt.Printf("d1 = %x\n", d1)
assert.Equal(t, data, d1)
}
func TestAddress(t *testing.T) {
priv, _ := types.FromHex("0xc2b31057b8692a56c7dd18199df71c1d21b781c0b6858c52997c9dbf778e8550")
pub := PubKeyFromPrivate(priv)
fmt.Println(types.ToHex(pub))
addr, err := PubKeyToAddress(pub)
if err != nil {
panic(err)
}
fmt.Println(addr)
}
\ No newline at end of file
package gm
import (
"bytes"
"crypto/elliptic"
"crypto/rand"
"fmt"
"github.com/btcsuite/btcd/btcec"
"github.com/tjfoc/gmsm/sm2"
"math/big"
)
const (
SM2PrivateKeyLength = 32
)
var DefaultUID = []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, 0x83}
func getRandBytes(numBytes int) []byte {
b := make([]byte, numBytes)
_, err := rand.Read(b)
if err != nil {
panic("Panic on a Crisis" + err.Error())
}
return b
}
func privKeyFromBytes(curve elliptic.Curve, pk []byte) (*sm2.PrivateKey, *sm2.PublicKey) {
x, y := curve.ScalarBaseMult(pk)
priv := &sm2.PrivateKey{
PublicKey: sm2.PublicKey{
Curve: curve,
X: x,
Y: y,
},
D: new(big.Int).SetBytes(pk),
}
return priv, &priv.PublicKey
}
func parsePubKey(pubKeyStr []byte) (key *sm2.PublicKey) {
return sm2.Decompress(pubKeyStr)
}
//SerializePrivateKey 私钥序列化
func serializePrivateKey(p *sm2.PrivateKey) []byte {
b := make([]byte, 0, SM2PrivateKeyLength)
return paddedAppend(SM2PrivateKeyLength, b, p.D.Bytes())
}
//SerializePublicKey 公钥序列化
func serializePublicKey(p *sm2.PublicKey) []byte {
return sm2.Compress(p)
}
func paddedAppend(size uint, dst, src []byte) []byte {
for i := 0; i < int(size)-len(src); i++ {
dst = append(dst, 0)
}
return append(dst, src...)
}
func canonicalizeInt(val *big.Int) []byte {
b := val.Bytes()
if len(b) == 0 {
b = []byte{0x00}
}
if b[0]&0x80 != 0 {
paddedBytes := make([]byte, len(b)+1)
copy(paddedBytes[1:], b)
b = paddedBytes
}
return b
}
func serializeSignature(r, s *big.Int) []byte {
rb := canonicalizeInt(r)
sb := canonicalizeInt(s)
length := 6 + len(rb) + len(sb)
b := make([]byte, length)
b[0] = 0x30
b[1] = byte(length - 2)
b[2] = 0x02
b[3] = byte(len(rb))
offset := copy(b[4:], rb) + 4
b[offset] = 0x02
b[offset+1] = byte(len(sb))
copy(b[offset+2:], sb)
return b
}
func deserializeSignature(sigStr []byte) (*big.Int, *big.Int, error) {
sig, err := btcec.ParseDERSignature(sigStr, sm2.P256Sm2())
if err != nil {
return nil, nil, err
}
return sig.R, sig.S, nil
}
func GenetateKey() ([]byte, []byte) {
privKeyBytes := [SM2PrivateKeyLength]byte{}
for {
key := getRandBytes(32)
if bytes.Compare(key, sm2.P256Sm2().Params().N.Bytes()) >= 0 {
continue
}
copy(privKeyBytes[:], key)
break
}
priv, pub := privKeyFromBytes(sm2.P256Sm2(), privKeyBytes[:])
return serializePrivateKey(priv), serializePublicKey(pub)
}
func SM2Sign(msg []byte, privateKey []byte, uid []byte) []byte {
if uid == nil {
uid = DefaultUID
}
priv, _ := privKeyFromBytes(sm2.P256Sm2(), privateKey)
r, s, err := sm2.Sm2Sign(priv, msg, uid)
if err != nil {
return nil
}
return serializeSignature(r, s)
}
func SM2Verify(msg []byte, publicKey []byte, sig []byte, uid []byte) bool {
if uid == nil {
uid = DefaultUID
}
pub := parsePubKey(publicKey[:])
r, s, err := deserializeSignature(sig)
if err != nil {
fmt.Errorf("unmarshal sign failed")
return false
}
return sm2.Sm2Verify(pub, msg, uid, r, s)
}
func SM2Encrypt(publicKey []byte, data []byte) ([]byte, error) {
pub := parsePubKey(publicKey[:])
return sm2.Encrypt(pub, data)
}
func SM2Decrypt(privateKey []byte, data []byte) ([]byte, error) {
priv, _ := privKeyFromBytes(sm2.P256Sm2(), privateKey)
return sm2.Decrypt(priv, data)
}
func PubKeyFromPrivate(privKey []byte) []byte {
_, pub := privKeyFromBytes(sm2.P256Sm2(), privKey)
return serializePublicKey(pub)
}
\ No newline at end of file
package gm
import "github.com/tjfoc/gmsm/sm3"
//SM3Hash 加密算法
func SM3Hash(msg []byte) []byte {
c := sm3.New()
c.Write(msg)
return c.Sum(nil)
}
package gm
import (
"github.com/tjfoc/gmsm/sm4"
"log"
)
const (
SM4PrivateKeyLength = 16
)
func GenetateSM4Key() []byte {
return getRandBytes(SM4PrivateKeyLength)
}
func SM4Encrypt(key []byte, data []byte) []byte {
c, err := sm4.NewCipher(key)
if err != nil {
log.Fatal(err)
}
cipher := make([]byte, 16)
c.Encrypt(cipher, data)
return cipher
}
func SM4Decrypt(key []byte, data []byte) []byte {
c, err := sm4.NewCipher(key)
if err != nil {
log.Fatal(err)
}
cipher := make([]byte, 16)
c.Decrypt(cipher, data)
return cipher
}
\ No newline at end of file
package crypto
import (
"crypto/sha256"
"golang.org/x/crypto/ripemd160"
)
func Sha256(b []byte) []byte {
hasher := sha256.New()
hasher.Write(b)
return hasher.Sum(nil)
}
func Sha2Sum(b []byte) []byte {
tmp := sha256.Sum256(b)
tmp = sha256.Sum256(tmp[:])
return tmp[:]
}
func rimpHash(in []byte, out []byte) {
sha := sha256.New()
_, err := sha.Write(in)
if err != nil {
return
}
rim := ripemd160.New()
_, err = rim.Write(sha.Sum(nil)[:])
if err != nil {
return
}
copy(out, rim.Sum(nil))
}
// Rimp160 Returns hash: RIMP160( SHA256( data ) )
// Where possible, using RimpHash() should be a bit faster
func Rimp160(b []byte) []byte {
out := make([]byte, 20)
rimpHash(b, out[:])
return out[:]
}
# storage 合约sdk 使用
## 直接调用github.com/33cn/chain33-sdk-go/dapp/storage下面封装得函数
#### storage
#### 1.1 创建明文存证交易
**函数原型**
```
CreateContentStorageTx(paraName string, op int32, key string, content []byte, value string) (*types.Transaction, error)
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|paraName |string|是|平行链链名前缀,主链填空字符串|
|op |string|否|操作类型,0为新建存储,1为追加|
|key |string|否|不填默认采用txhash为key值|
|content |bytes|否|content和value二选一填值|
|value |string|否|content和value二选一填值|
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|*types.Transaction|*types.Transaction | 未签名的交易
|err |error | 错误返回
#### 1.2 创建hash存证交易
**函数原型**
```
CreateHashStorageTx(paraName string, key string, hash []byte, value string) (*types.Transaction, error)
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|paraName |string|是|平行链链名前缀,主链填空字符串|
|key |string|否|不填默认采用txhash为key值|
|hash |bytes|否|hash和value二选一填值|
|value |string|否|hash和value二选一填值|
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|*types.Transaction|*types.Transaction | 未签名的交易
|err |error | 错误返回
#### 1.3 创建链接存证交易
**函数原型**
```
CreateLinkStorageTx(paraName string, key string, link []byte, value string) (*types.Transaction, error)
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|paraName |string|是|平行链链名前缀,主链填空字符串|
|key |string|否|不填默认采用txhash为key值|
|link |bytes|否|link和value二选一填值|
|value |string|否|link和value二选一填值|
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|*types.Transaction|*types.Transaction | 未签名的交易
|err |error | 错误返回
#### 1.4 创建隐私存证交易
**函数原型**
```
CreateEncryptStorageTx(paraName string, key string, contentHash, encryptContent, nonce []byte, value string) *types.Transaction
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|paraName |string|是|平行链链名前缀,主链填空字符串|
|key |string|否|不填默认采用txhash为key值|
|contentHash |bytes|是|明文hash值用于校验结果一致性|
|encryptContent |bytes|是|源文件的密文,由加密key及nonce对明文加密得到该值|
|nonce |bytes|是|加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值|
|value |string|否|预留字段|
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|*types.Transaction|*types.Transaction | 未签名的交易
|err |error | 错误返回
#### 1.4 创建分享隐私交易
**函数原型**
```
CreateEncryptShareStorageTx(paraName string, key string, contentHash, encryptContent, publickey []byte, value string) *types.Transaction
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|paraName |string|是|平行链链名前缀,主链填空字符串|
|key |string|否|不填默认采用txhash为key值|
|contentHash |bytes|是|明文hash值用于校验结果一致性|
|encryptContent |bytes|是|源文件得密文,采用非对称加密,用公钥地址加密,用私钥解密|
|publickey |bytes|是|公钥|
|value |string|否|预留字段|
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|*types.Transaction|*types.Transaction | 未签名的交易
|err |error | 错误返回
#### 1.5 根据key查询存储内容
**函数原型**
```
QueryStorageByKey(prefix, url, key string) (*types.Storage, error)
```
**请求参数**
|参数|类型|是否必填|说明|
|----|----|----|----|
|prefix |string|是|平行链链名前缀,主链填空字符串|
|url |string|是|地址|
|key |string|是|key值|
**返回字段:**
|返回字段|字段类型|说明|
|----|----|----|
|*types.Storage|*types.Storage| 存证内容
|err |error | 错误返回
字段信息,可参考github.com/33cn/chain33-sdk-go/proto/sotrage.proto文件
\ No newline at end of file
package storage
const (
TyUnknowAction = iota
TyContentStorageAction
TyHashStorageAction
TyLinkStorageAction
TyEncryptStorageAction
TyEncryptShareStorageAction
FuncNameQueryStorage = "QueryStorage"
)
const (
OpCreate = int32(iota)
OpAdd
)
const StorageX = "storage"
const Addr = "1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs"
package storage
import (
"encoding/json"
"fmt"
. "github.com/bitly/go-simplejson"
"github.com/33cn/chain33-sdk-go/client"
"github.com/33cn/chain33-sdk-go/types"
)
func QueryStorageByKey(prefix, url, key string) (*types.Storage, error) {
jsonClient, err := client.NewJSONClient(prefix, url)
if err != nil {
return nil, err
}
jsonraw, err := json.Marshal(&types.QueryStorage{TxHash: key})
if err != nil {
return nil, err
}
query := client.Query4Jrpc{
Execer: prefix + StorageX,
FuncName: FuncNameQueryStorage,
Payload: jsonraw,
}
//var storage types.Storage
data, err := jsonClient.CallBack("Chain33.Query", query, ParseStorage)
if err != nil {
return nil, err
}
return data.(*types.Storage), nil
}
//回调解析函数
func ParseStorage(raw json.RawMessage) (interface{}, error) {
js, err := NewJson(raw)
if err != nil {
return nil, err
}
if contentStorge, ok := js.CheckGet("contentStorage"); ok {
contentHex, _ := contentStorge.Get("content").String()
content, _ := types.FromHex(contentHex)
key, _ := contentStorge.Get("key").String()
value, _ := contentStorge.Get("value").String()
op, _ := contentStorge.Get("op").Int()
storage := &types.Storage{Ty: TyContentStorageAction, Value: &types.Storage_ContentStorage{ContentStorage: &types.ContentOnlyNotaryStorage{
Content: content,
Key: key,
Op: int32(op),
Value: value,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
}}}
return storage, nil
}
if linkStorge, ok := js.CheckGet("linkStorage"); ok {
linkHex, _ := linkStorge.Get("link").String()
link, _ := types.FromHex(linkHex)
key, _ := linkStorge.Get("key").String()
value, _ := linkStorge.Get("value").String()
storage := &types.Storage{Ty: TyLinkStorageAction, Value: &types.Storage_LinkStorage{LinkStorage: &types.LinkNotaryStorage{
Link: link,
Key: key,
Value: value,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
}}}
return storage, nil
}
if hashStorge, ok := js.CheckGet("hashStorage"); ok {
hashHex, _ := hashStorge.Get("hash").String()
hash, _ := types.FromHex(hashHex)
key, _ := hashStorge.Get("key").String()
value, _ := hashStorge.Get("value").String()
storage := &types.Storage{Ty: TyHashStorageAction, Value: &types.Storage_HashStorage{HashStorage: &types.HashOnlyNotaryStorage{
Hash: hash,
Key: key,
Value: value,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
}}}
return storage, nil
}
if encryptStorage, ok := js.CheckGet("encryptStorage"); ok {
contentHashHex, _ := encryptStorage.Get("contentHash").String()
contentHash, _ := types.FromHex(contentHashHex)
encryptContentHex, _ := encryptStorage.Get("encryptContent").String()
encryptContent, _ := types.FromHex(encryptContentHex)
nonceHex, _ := encryptStorage.Get("nonce").String()
nonce, _ := types.FromHex(nonceHex)
key, _ := encryptStorage.Get("key").String()
value, _ := encryptStorage.Get("value").String()
storage := &types.Storage{Ty: TyEncryptStorageAction, Value: &types.Storage_EncryptStorage{EncryptStorage: &types.EncryptNotaryStorage{
EncryptContent: encryptContent,
ContentHash: contentHash,
Nonce: nonce,
Key: key,
Value: value,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
}}}
return storage, nil
}
if encryptStorage, ok := js.CheckGet("encryptShareStorage"); ok {
contentHashHex, _ := encryptStorage.Get("contentHash").String()
contentHash, _ := types.FromHex(contentHashHex)
encryptContentHex, _ := encryptStorage.Get("encryptContent").String()
encryptContent, _ := types.FromHex(encryptContentHex)
pubKeyHex, _ := encryptStorage.Get("pubKey").String()
pubKey, _ := types.FromHex(pubKeyHex)
key, _ := encryptStorage.Get("key").String()
value, _ := encryptStorage.Get("value").String()
storage := &types.Storage{Ty: TyEncryptShareStorageAction, Value: &types.Storage_EncryptShareStorage{EncryptShareStorage: &types.EncryptShareNotaryStorage{
EncryptContent: encryptContent,
ContentHash: contentHash,
PubKey: pubKey,
Key: key,
Value: value,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
}}}
return storage, nil
}
return nil, fmt.Errorf("unknow type!")
}
package storage
import (
"fmt"
"github.com/33cn/chain33-sdk-go/crypto"
. "github.com/33cn/chain33-sdk-go/types"
"math/rand"
)
/*
//Op 0表示创建 1表示追加add (新版本才支持)
int32 op = 1;
//存在内容
bytes content = 2;
//自定义的主键,可以为空,如果没传,则用txhash为key
string key = 3;
//字符串值
string value = 4;
value 为预留字段
content和value只能有一个有效值
*/
//明文存证溯源
func CreateContentStorageTx(paraName string, op int32, key string, content []byte, value string) (*Transaction, error) {
if op != 0 && op != 1 {
return nil, fmt.Errorf("unknow op..,op only 0 or 1,please check!")
}
payload := &StorageAction{Ty: TyContentStorageAction, Value: &StorageAction_ContentStorage{&ContentOnlyNotaryStorage{
Content: content,
Op: op,
Key: key,
Value: value,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
}},
}
if paraName == "" {
tx := &Transaction{Execer: []byte(StorageX), Payload: Encode(payload), Fee: 1e5, Nonce: rand.Int63(), To: Addr}
return tx, nil
} else {
tx := &Transaction{Execer: []byte(paraName + StorageX), Payload: Encode(payload), Fee: 1e5, Nonce: rand.Int63(), To: crypto.GetExecAddress(paraName + StorageX)}
return tx, nil
}
}
//链接存证 paraName 平行链前缀,如果是主链则为空字符串,key唯一性,如果不填默认采用txhash为key
func CreateLinkStorageTx(paraName string, key string, link []byte, value string) (*Transaction, error) {
payload := &StorageAction{Ty: TyLinkStorageAction, Value: &StorageAction_LinkStorage{&LinkNotaryStorage{
Link: link,
Key: key,
Value: value,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
}},
}
if paraName == "" {
tx := &Transaction{Execer: []byte(StorageX), Payload: Encode(payload), Fee: 1e5, Nonce: rand.Int63(), To: Addr}
return tx, nil
} else {
tx := &Transaction{Execer: []byte(paraName + StorageX), Payload: Encode(payload), Fee: 1e5, Nonce: rand.Int63(), To: crypto.GetExecAddress(paraName + StorageX)}
return tx, nil
}
}
//hash存证
func CreateHashStorageTx(paraName string, key string, hash []byte, value string) (*Transaction, error) {
payload := &StorageAction{Ty: TyHashStorageAction, Value: &StorageAction_HashStorage{&HashOnlyNotaryStorage{
Hash: hash,
Key: key,
Value: value,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
}},
}
if paraName == "" {
tx := &Transaction{Execer: []byte(StorageX), Payload: Encode(payload), Fee: 1e5, Nonce: rand.Int63(), To: Addr}
return tx, nil
} else {
tx := &Transaction{Execer: []byte(paraName + StorageX), Payload: Encode(payload), Fee: 1e5, Nonce: rand.Int63(), To: crypto.GetExecAddress(paraName + StorageX)}
return tx, nil
}
}
//隐私加密存储
func CreateEncryptStorageTx(paraName string, key string, contentHash, encryptContent, nonce []byte, value string) *Transaction {
payload := &StorageAction{Ty: TyEncryptStorageAction, Value: &StorageAction_EncryptStorage{&EncryptNotaryStorage{
ContentHash: contentHash,
EncryptContent: encryptContent,
Nonce: nonce,
Key: key,
Value: value,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
}},
}
if paraName == "" {
tx := &Transaction{Execer: []byte(StorageX), Payload: Encode(payload), Fee: 1e5, Nonce: rand.Int63(), To: Addr}
return tx
} else {
tx := &Transaction{Execer: []byte(paraName + StorageX), Payload: Encode(payload), Fee: 1e5, Nonce: rand.Int63(), To: crypto.GetExecAddress(paraName + StorageX)}
return tx
}
}
//分享隐私加密存储
func CreateEncryptShareStorageTx(paraName string, key string, contentHash, encryptContent, publickey []byte, value string) *Transaction {
payload := &StorageAction{Ty: TyEncryptShareStorageAction, Value: &StorageAction_EncryptShareStorage{&EncryptShareNotaryStorage{
ContentHash: contentHash,
EncryptContent: encryptContent,
PubKey: publickey,
Key: key,
Value: value,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
}},
}
if paraName == "" {
tx := &Transaction{Execer: []byte(StorageX), Payload: Encode(payload), Fee: 1e5, Nonce: rand.Int63(), To: Addr}
return tx
} else {
tx := &Transaction{Execer: []byte(paraName + StorageX), Payload: Encode(payload), Fee: 1e5, Nonce: rand.Int63(), To: crypto.GetExecAddress(paraName + StorageX)}
return tx
}
}
package storage
import (
sdk "github.com/33cn/chain33-sdk-go"
"github.com/33cn/chain33-sdk-go/client"
"github.com/33cn/chain33-sdk-go/crypto"
"github.com/33cn/chain33-sdk-go/types"
"github.com/stretchr/testify/assert"
"testing"
"time"
)
var (
privkey = "cc38546e9e659d15e6b4893f0ab32a06d103931a8230b0bde71459d2b27d6944"
url = "http://fd.33.cn:1276"
)
func TestCreateContentStorageTx(t *testing.T) {
//第一次存储
tx, err := CreateContentStorageTx("", OpCreate, "", []byte("hello"), "")
assert.Nil(t, err)
hexbytes, _ := types.FromHex(privkey)
sdk.Sign(tx, hexbytes, crypto.SECP256K1)
txhash := types.ToHexPrefix(sdk.Hash(tx))
jsonclient, err := client.NewJSONClient("", url)
assert.Nil(t, err)
signTx := types.ToHexPrefix(types.Encode(tx))
reply, err := jsonclient.SendTransaction(signTx)
assert.Nil(t, err)
assert.Equal(t, txhash, reply)
time.Sleep(2 * time.Second)
detail, err := jsonclient.QueryTransaction(txhash)
assert.Nil(t, err)
assert.Equal(t, types.ExecOk, int(detail.Receipt.Ty))
//查询
storage, err := QueryStorageByKey("", url, txhash)
assert.Nil(t, err)
assert.Equal(t, []byte("hello"), storage.GetContentStorage().Content)
//第二次追加 老版本不支持
//tx,err=CreateContentStorageTx("",OpAdd,txhash,[]byte("world"),"")
//assert.Nil(t,err)
//tx.Sign(types.SECP256K1, priv)
//signTx =common.ToHexPrefix(types.Encode(tx))
//_,err=jsonclient.SendTransaction(signTx)
//assert.Nil(t,err)
//time.Sleep(2*time.Second)
////查询
//storage,err=QueryStorageByKey("",url,txhash)
//assert.Nil(t,err)
//assert.Equal(t,[]byte("hello,world"),storage.GetContentStorage().Content)
}
//hash,or link 存证
func TestCreateHashStorageTx(t *testing.T) {
tx, err := CreateHashStorageTx("", "", []byte("123456harrylee"), "")
assert.Nil(t, err)
//签名
hexbytes, _ := types.FromHex(privkey)
sdk.Sign(tx, hexbytes, crypto.SECP256K1)
txhash := types.ToHexPrefix(sdk.Hash(tx))
jsonclient, err := client.NewJSONClient("", url)
assert.Nil(t, err)
signTx := types.ToHexPrefix(types.Encode(tx))
reply, err := jsonclient.SendTransaction(signTx)
assert.Nil(t, err)
assert.Equal(t, txhash, reply)
time.Sleep(time.Second)
detail, err := jsonclient.QueryTransaction(txhash)
assert.Nil(t, err)
assert.Equal(t, types.ExecOk, int(detail.Receipt.Ty))
//查询
storage, err := QueryStorageByKey("", url, txhash)
assert.Nil(t, err)
assert.Equal(t, []byte("123456harrylee"), storage.GetHashStorage().Hash)
}
//hash,or link 存证
func TestCreateLinkStorageTx(t *testing.T) {
tx, err := CreateLinkStorageTx("", "", []byte("hello"), "")
assert.Nil(t, err)
hexbytes, _ := types.FromHex(privkey)
sdk.Sign(tx, hexbytes, crypto.SECP256K1)
txhash := types.ToHexPrefix(sdk.Hash(tx))
jsonclient, err := client.NewJSONClient("", url)
assert.Nil(t, err)
signTx := types.ToHexPrefix(types.Encode(tx))
reply, err := jsonclient.SendTransaction(signTx)
assert.Nil(t, err)
assert.Equal(t, txhash, reply)
time.Sleep(time.Second)
storage, err := QueryStorageByKey("", url, txhash)
assert.Nil(t, err)
assert.Equal(t, []byte("hello"), storage.GetLinkStorage().Link)
}
func TestByteFromHex(t *testing.T) {
hex := "0x313233343536"
data, err := types.FromHex(hex)
if err != nil {
t.Error(err)
}
t.Log(string(data))
}
module github.com/33cn/chain33-sdk-go
go 1.12
require (
github.com/NebulousLabs/Sia v1.3.7 // indirect
github.com/NebulousLabs/entropy-mnemonics v0.0.0-20181203154559-bc7e13c5ccd8 // indirect
github.com/NebulousLabs/errors v0.0.0-20181203160057-9f787ce8f69e // indirect
github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e // indirect
github.com/NebulousLabs/merkletree v0.0.0-20181203152040-08d5d54b07f5 // indirect
github.com/XiaoMi/pegasus-go-client v0.0.0-20200509085530-e2f054e1ad99 // indirect
github.com/bitly/go-simplejson v0.5.0
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3
github.com/decred/base58 v1.0.2 // indirect
github.com/dgraph-io/badger v1.6.1 // indirect
github.com/golang/protobuf v1.3.4
github.com/haltingstate/secp256k1-go v0.0.0-20151224084235-572209b26df6 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/huin/goupnp v1.0.0 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/mattn/go-colorable v0.1.6 // indirect
github.com/mr-tron/base58 v1.1.3
github.com/pkg/errors v0.9.1 // indirect
github.com/rs/cors v1.7.0 // indirect
github.com/spf13/cobra v1.0.0 // indirect
github.com/stretchr/testify v1.5.1
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/tjfoc/gmsm v1.3.1
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915
google.golang.org/grpc v1.29.1 // indirect
)
This diff is collapsed.
package sdk
import (
"crypto/rand"
"errors"
"fmt"
secp256k1 "github.com/btcsuite/btcd/btcec"
"github.com/33cn/chain33-sdk-go/crypto"
"github.com/33cn/chain33-sdk-go/types"
"golang.org/x/crypto/blake2b"
"math/big"
)
var baseN = secp256k1.S256().Params().N
type KFrag struct {
Random string
Value string
PrecurPub string
}
type ReKeyFrag struct {
ReKeyR string
ReKeyU string
Random string
PrecurPub string
}
type EccPoit struct {
x *big.Int
y *big.Int
}
func NewEccPoint(pubStr string) (*EccPoit, error) {
reKeyRByte, err := types.FromHex(pubStr)
if err != nil {
fmt.Errorf("get reKeyRByte err", err)
return nil, err
}
reKeyR := crypto.PublicFromByte(reKeyRByte)
return &EccPoit{x: reKeyR.X, y: reKeyR.Y}, nil
}
func (p *EccPoit) Add(v *EccPoit) *EccPoit {
if v == nil {
return p
}
p.x, p.y = secp256k1.S256().Add(p.x, p.y, v.x, v.y)
return p
}
func (p *EccPoit) MulInt(i *big.Int) *EccPoit {
p.x, p.y = secp256k1.S256().ScalarMult(p.x, p.y, i.Bytes())
return p
}
func (p *EccPoit) ToPublicKey() *secp256k1.PublicKey {
return &secp256k1.PublicKey{
X: p.x,
Y: p.y,
Curve: secp256k1.S256(),
}
}
func hashToModInt(digest []byte) *big.Int {
sum := new(big.Int).SetBytes(digest)
one := big.NewInt(1)
order_minus_1 := big.NewInt(0)
order_minus_1.Sub(baseN, one)
bigNum := big.NewInt(0)
bigNum.Mod(sum, order_minus_1).Add(bigNum, one)
return bigNum
}
func makeShamirPolyCoeff(threshold int) []*big.Int {
coeffs := make([]*big.Int, threshold-1)
for i,_ := range coeffs {
coeffs[i] = new(big.Int).SetBytes(crypto.GeneratePrivateKey())
}
return coeffs
}
// p0*x^2 + p1 * x + p2
func hornerPolyEval(poly []*big.Int, x *big.Int) *big.Int {
result := big.NewInt(0)
result.Add(result, poly[0])
for i := 1; i < len(poly); i++ {
result = result.Mul(result, x).Add(result, poly[i])
}
return result.Mod(result, baseN)
}
func calcPart(a *big.Int, b *big.Int) *big.Int {
p := big.NewInt(0)
p.Sub(a, b).Mod(p, baseN)
res := big.NewInt(0)
res.Mul(a, p.ModInverse(p, baseN)).Mod(res, baseN)
return res
}
func calcLambdaCoeff(inId *big.Int, selectedIds []*big.Int) *big.Int {
var ids []*big.Int
for _, id := range selectedIds {
if inId.Cmp(id) == 0 {
continue
}
ids = append(ids, id)
}
if len(ids) == 0 {
return big.NewInt(1)
}
result := calcPart(ids[0], inId)
if len(ids) > 1 {
for _, id_j := range ids[1:] {
result.Mul(result, calcPart(id_j, inId)).Mod(result, baseN)
}
}
return result
}
func getRandomInt(order *big.Int) *big.Int {
randInt, err := rand.Int(rand.Reader, order)
if err != nil {
panic(err)
}
return randInt
}
func GeneratePreEncryptKey(pubOwner []byte) ([]byte, string, string) {
pubOwnerKey := crypto.PublicFromByte(pubOwner)
priv_r := crypto.PrivateFromByte(crypto.GeneratePrivateKey())
priv_u := crypto.PrivateFromByte(crypto.GeneratePrivateKey())
result := &secp256k1.PublicKey{}
result.Curve = pubOwnerKey.Curve
sum := big.NewInt(0)
sum.Add(priv_u.D, priv_r.D).Mod(sum, baseN)
result.X, result.Y = secp256k1.S256().ScalarMult(pubOwnerKey.X, pubOwnerKey.Y, sum.Bytes())
pub_r := types.ToHex((*secp256k1.PublicKey)(&priv_r.PublicKey).SerializeCompressed())
pub_u := types.ToHex((*secp256k1.PublicKey)(&priv_u.PublicKey).SerializeCompressed())
return result.SerializeCompressed()[1:], pub_r, pub_u
}
func GenerateKeyFragments(privOwner []byte, pubRecipient []byte, numSplit, threshold int) ([]*KFrag, error) {
precursor := crypto.PrivateFromByte(crypto.GeneratePrivateKey())
precurPub := types.ToHex((*secp256k1.PublicKey)(&precursor.PublicKey).SerializeCompressed())
privOwnerKey := crypto.PrivateFromByte(privOwner)
pubRecipientKey := crypto.PublicFromByte(pubRecipient)
dh_Alice_poit_x := types.ECDH(precursor, pubRecipientKey)
dAliceHash, err := blake2b.New256(precursor.X.Bytes())
if err != nil {
fmt.Errorf("Generate precursor Key err", err)
return nil, err
}
dAliceHash.Write(pubRecipientKey.X.Bytes())
dAliceHash.Write(dh_Alice_poit_x)
dAlice := dAliceHash.Sum(nil)
dAliceBN := hashToModInt(dAlice)
// c0, c1, c2
f0 := big.NewInt(0)
f0.Mul(privOwnerKey.D, f0.ModInverse(dAliceBN, baseN)).Mod(f0, baseN)
kFrags := make([]*KFrag, numSplit)
if numSplit == 1 {
id := getRandomInt(baseN)
kFrags[0] = &KFrag{Random: id.String(), Value: f0.String(), PrecurPub: precurPub}
} else {
coeffs := makeShamirPolyCoeff(threshold)
coeffs = append(coeffs, f0)
// rk[i] = f2*id^2 + f1*id + f0
for i, _ := range kFrags {
id := getRandomInt(baseN)
dShareHash, err := blake2b.New256(precursor.X.Bytes())
if err != nil {
fmt.Errorf("Generate precursor Key err", err)
return nil, err
}
dShareHash.Write(pubRecipientKey.X.Bytes())
dShareHash.Write(dh_Alice_poit_x)
dShareHash.Write(id.Bytes())
share := hashToModInt(dShareHash.Sum(nil))
rk := hornerPolyEval(coeffs, share)
kFrags[i] = &KFrag{Random: id.String(), Value: rk.String(), PrecurPub: precurPub}
}
}
return kFrags, nil
}
func AssembleReencryptFragment(privRecipient []byte, reKeyFrags []*ReKeyFrag) ([]byte, error) {
privRecipientKey := crypto.PrivateFromByte(privRecipient)
precursor, err := types.FromHex(reKeyFrags[0].PrecurPub)
if err != nil {
fmt.Errorf("FromHex", err)
return nil, err
}
precursorPubKey := crypto.PublicFromByte(precursor)
dh_Bob_poit_x := types.ECDH(privRecipientKey, precursorPubKey)
dBobHash, err := blake2b.New256(precursorPubKey.X.Bytes())
if err != nil {
fmt.Errorf("Generate precursor Key err", err)
return nil, err
}
dBobHash.Write(privRecipientKey.X.Bytes())
dBobHash.Write(dh_Bob_poit_x)
dhBob := dBobHash.Sum(nil)
dhBobBN := hashToModInt(dhBob)
var share_key *EccPoit
if len(reKeyFrags) == 1 {
rPoint, err := NewEccPoint(reKeyFrags[0].ReKeyR)
if err != nil {
fmt.Errorf("get reKeyRByte err", err)
return nil, err
}
uPoint, err := NewEccPoint(reKeyFrags[0].ReKeyU)
if err != nil {
fmt.Errorf("get reKeyRByte err", err)
return nil, err
}
share_key = rPoint.Add(uPoint).MulInt(dhBobBN)
} else {
var eFinal, vFinal *EccPoit
ids := make([]*big.Int, len(reKeyFrags))
for x, _ := range ids {
xs, err := blake2b.New256(precursorPubKey.X.Bytes())
if err != nil {
fmt.Errorf("Generate precursor Key err", err)
return nil, err
}
xs.Write(privRecipientKey.X.Bytes())
xs.Write(dh_Bob_poit_x)
random, ret := new(big.Int).SetString(reKeyFrags[x].Random, 10)
if !ret {
fmt.Errorf("AssembleReencryptFragment.get value int",)
return nil, errors.New("get big int value from keyFragment failed")
}
xs.Write(random.Bytes())
ids[x] = hashToModInt(xs.Sum(nil))
}
for i, id := range ids {
lambda := calcLambdaCoeff(id, ids)
if lambda == nil {
continue
}
rPoint, err := NewEccPoint(reKeyFrags[i].ReKeyR)
if err != nil {
fmt.Errorf("get reKeyRByte err", err)
return nil, err
}
uPoint, err := NewEccPoint(reKeyFrags[i].ReKeyU)
if err != nil {
fmt.Errorf("get reKeyRByte err", err)
return nil, err
}
e := rPoint.MulInt(lambda)
v := uPoint.MulInt(lambda)
eFinal = e.Add(eFinal)
vFinal = v.Add(vFinal)
}
share_key = eFinal.Add(vFinal).MulInt(dhBobBN)
}
return share_key.ToPublicKey().SerializeCompressed(), nil
}
\ No newline at end of file
#!/bin/sh
protoc --go_out=plugins=grpc:../types/ ./*.proto --proto_path=.
syntax = "proto3";
package types;
message Transaction {
bytes execer = 1;
bytes payload = 2;
Signature signature = 3;
int64 fee = 4;
int64 expire = 5;
//随机ID,可以防止payload 相同的时候,交易重复
int64 nonce = 6;
//对方地址,如果没有对方地址,可以为空
string to = 7;
int32 groupCount = 8;
bytes header = 9;
bytes next = 10;
}
message Signature {
int32 ty = 1;
bytes pubkey = 2;
//当ty为5时,格式应该用RingSignature去解析
bytes signature = 3;
}
syntax = "proto3";
package types;
//后面如果有其他数据模型可继续往上面添加
message Storage {
oneof value {
ContentOnlyNotaryStorage contentStorage = 1;
HashOnlyNotaryStorage hashStorage = 2;
LinkNotaryStorage linkStorage = 3;
EncryptNotaryStorage encryptStorage = 4;
EncryptShareNotaryStorage encryptShareStorage = 5;
}
int32 ty = 6;
}
message StorageAction {
oneof value {
ContentOnlyNotaryStorage contentStorage = 1;
HashOnlyNotaryStorage hashStorage = 2;
LinkNotaryStorage linkStorage = 3;
EncryptNotaryStorage encryptStorage = 4;
EncryptShareNotaryStorage encryptShareStorage = 5;
}
int32 ty = 6;
}
// 内容存证模型
message ContentOnlyNotaryStorage {
//长度需要小于512k
bytes content = 1;
//自定义的主键,可以为空,如果没传,则用txhash为key
string key = 2;
// Op 0表示创建 1表示追加add
int32 op = 3;
//字符串值
string value = 4;
}
//哈希存证模型,推荐使用sha256哈希,限制256位得摘要值
message HashOnlyNotaryStorage {
//长度固定为32字节
bytes hash = 1;
//自定义的主键,可以为空,如果没传,则用txhash为key
string key = 2;
//字符串值
string value = 3;
}
// 链接存证模型
message LinkNotaryStorage {
//存证内容的链接,可以写入URL,或者其他可用于定位源文件得线索.
bytes link = 1;
//源文件得hash值,推荐使用sha256哈希,限制256位得摘要值
bytes hash = 2;
//自定义的主键,可以为空,如果没传,则用txhash为key
string key = 3;
//字符串值
string value = 4;
}
// 隐私存证模型,如果一个文件需要存证,且不公开内容,可以选择将源文件通过对称加密算法加密后上链
message EncryptNotaryStorage {
//存证明文内容的hash值,推荐使用sha256哈希,限制256位得摘要值
bytes contentHash = 1;
//源文件得密文,由加密key及nonce对明文加密得到该值。
bytes encryptContent = 2;
//加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值
bytes nonce = 3;
//自定义的主键,可以为空,如果没传,则用txhash为key
string key = 4;
//字符串值
string value = 5;
}
// 分享隐私存证模型,需要完备的sdk或者相应的密钥库支持
message EncryptShareNotaryStorage {
//存证明文内容的hash值,推荐使用sha256哈希,限制256位得摘要值
bytes contentHash = 1;
//源文件得密文。,用公钥地址加密
bytes encryptContent = 2;
//公钥
bytes pubKey = 3;
//自定义的主键,可以为空,如果没传,则用txhash为key
string key = 4;
//字符串值
string value = 5;
}
//根据txhash去状态数据库中查询存储内容
message QueryStorage {
string txHash = 1;
}
//批量查询有可能导致数据库崩溃
message BatchQueryStorage {
repeated string txHashs = 1;
}
message BatchReplyStorage {
repeated Storage storages = 1;
}
message ReceiptStorage {
}
\ No newline at end of file
package sdk
import (
"errors"
"github.com/33cn/chain33-sdk-go/crypto"
"github.com/33cn/chain33-sdk-go/crypto/gm"
. "github.com/33cn/chain33-sdk-go/types"
)
func Sign(tx *Transaction, privateKey []byte, signType string) (*Transaction, error) {
if signType == "" {
signType = crypto.SECP256K1
}
tx.Signature = nil
if signType == crypto.SECP256K1 {
pub := crypto.PubKeyFromPrivate(privateKey)
data := Encode(tx)
signature := crypto.Sign(data, privateKey)
tx.Signature = &Signature{
Ty: 1,
Pubkey: pub,
Signature: signature,
}
} else if signType == crypto.SM2 {
pub := gm.PubKeyFromPrivate(privateKey)
data := Encode(tx)
signature := gm.SM2Sign(data, privateKey, nil)
tx.Signature = &Signature{
Ty: 1,
Pubkey: pub,
Signature: signature,
}
} else if signType == crypto.ED25519 {
// TODO
} else {
return nil, errors.New("sign type not support")
}
return tx, nil
}
func cloneTx(tx *Transaction) *Transaction {
copytx := &Transaction{}
copytx.Execer = tx.Execer
copytx.Payload = tx.Payload
copytx.Signature = tx.Signature
copytx.Fee = tx.Fee
copytx.Expire = tx.Expire
copytx.Nonce = tx.Nonce
copytx.To = tx.To
copytx.GroupCount = tx.GroupCount
copytx.Header = tx.Header
copytx.Next = tx.Next
return copytx
}
func Hash(tx *Transaction) []byte {
copytx := cloneTx(tx)
copytx.Signature = nil
copytx.Header = nil
data := Encode(copytx)
return crypto.Sha256(data)
}
\ No newline at end of file
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: sdk.proto
package types
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
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 Transaction struct {
Execer []byte `protobuf:"bytes,1,opt,name=execer,proto3" json:"execer,omitempty"`
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
Signature *Signature `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"`
Fee int64 `protobuf:"varint,4,opt,name=fee,proto3" json:"fee,omitempty"`
Expire int64 `protobuf:"varint,5,opt,name=expire,proto3" json:"expire,omitempty"`
//随机ID,可以防止payload 相同的时候,交易重复
Nonce int64 `protobuf:"varint,6,opt,name=nonce,proto3" json:"nonce,omitempty"`
//对方地址,如果没有对方地址,可以为空
To string `protobuf:"bytes,7,opt,name=to,proto3" json:"to,omitempty"`
GroupCount int32 `protobuf:"varint,8,opt,name=groupCount,proto3" json:"groupCount,omitempty"`
Header []byte `protobuf:"bytes,9,opt,name=header,proto3" json:"header,omitempty"`
Next []byte `protobuf:"bytes,10,opt,name=next,proto3" json:"next,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Transaction) Reset() { *m = Transaction{} }
func (m *Transaction) String() string { return proto.CompactTextString(m) }
func (*Transaction) ProtoMessage() {}
func (*Transaction) Descriptor() ([]byte, []int) {
return fileDescriptor_70decb0fb6f436df, []int{0}
}
func (m *Transaction) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Transaction.Unmarshal(m, b)
}
func (m *Transaction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Transaction.Marshal(b, m, deterministic)
}
func (m *Transaction) XXX_Merge(src proto.Message) {
xxx_messageInfo_Transaction.Merge(m, src)
}
func (m *Transaction) XXX_Size() int {
return xxx_messageInfo_Transaction.Size(m)
}
func (m *Transaction) XXX_DiscardUnknown() {
xxx_messageInfo_Transaction.DiscardUnknown(m)
}
var xxx_messageInfo_Transaction proto.InternalMessageInfo
func (m *Transaction) GetExecer() []byte {
if m != nil {
return m.Execer
}
return nil
}
func (m *Transaction) GetPayload() []byte {
if m != nil {
return m.Payload
}
return nil
}
func (m *Transaction) GetSignature() *Signature {
if m != nil {
return m.Signature
}
return nil
}
func (m *Transaction) GetFee() int64 {
if m != nil {
return m.Fee
}
return 0
}
func (m *Transaction) GetExpire() int64 {
if m != nil {
return m.Expire
}
return 0
}
func (m *Transaction) GetNonce() int64 {
if m != nil {
return m.Nonce
}
return 0
}
func (m *Transaction) GetTo() string {
if m != nil {
return m.To
}
return ""
}
func (m *Transaction) GetGroupCount() int32 {
if m != nil {
return m.GroupCount
}
return 0
}
func (m *Transaction) GetHeader() []byte {
if m != nil {
return m.Header
}
return nil
}
func (m *Transaction) GetNext() []byte {
if m != nil {
return m.Next
}
return nil
}
type Signature struct {
Ty int32 `protobuf:"varint,1,opt,name=ty,proto3" json:"ty,omitempty"`
Pubkey []byte `protobuf:"bytes,2,opt,name=pubkey,proto3" json:"pubkey,omitempty"`
//当ty为5时,格式应该用RingSignature去解析
Signature []byte `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Signature) Reset() { *m = Signature{} }
func (m *Signature) String() string { return proto.CompactTextString(m) }
func (*Signature) ProtoMessage() {}
func (*Signature) Descriptor() ([]byte, []int) {
return fileDescriptor_70decb0fb6f436df, []int{1}
}
func (m *Signature) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Signature.Unmarshal(m, b)
}
func (m *Signature) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Signature.Marshal(b, m, deterministic)
}
func (m *Signature) XXX_Merge(src proto.Message) {
xxx_messageInfo_Signature.Merge(m, src)
}
func (m *Signature) XXX_Size() int {
return xxx_messageInfo_Signature.Size(m)
}
func (m *Signature) XXX_DiscardUnknown() {
xxx_messageInfo_Signature.DiscardUnknown(m)
}
var xxx_messageInfo_Signature proto.InternalMessageInfo
func (m *Signature) GetTy() int32 {
if m != nil {
return m.Ty
}
return 0
}
func (m *Signature) GetPubkey() []byte {
if m != nil {
return m.Pubkey
}
return nil
}
func (m *Signature) GetSignature() []byte {
if m != nil {
return m.Signature
}
return nil
}
func init() {
proto.RegisterType((*Transaction)(nil), "types.Transaction")
proto.RegisterType((*Signature)(nil), "types.Signature")
}
func init() {
proto.RegisterFile("sdk.proto", fileDescriptor_70decb0fb6f436df)
}
var fileDescriptor_70decb0fb6f436df = []byte{
// 255 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x90, 0x41, 0x4e, 0xc3, 0x30,
0x10, 0x45, 0xe5, 0xa4, 0x49, 0xc9, 0xb4, 0x42, 0xd5, 0x08, 0xa1, 0x59, 0x20, 0x14, 0x75, 0xe5,
0x55, 0x16, 0x70, 0x04, 0x4e, 0x80, 0xe1, 0x02, 0x6e, 0x32, 0x94, 0xa8, 0xc8, 0xb6, 0x1c, 0x47,
0xaa, 0xcf, 0xc0, 0xa5, 0x51, 0x9c, 0x14, 0x2a, 0x76, 0xf3, 0x5e, 0xa2, 0x3f, 0x9e, 0x0f, 0xd5,
0xd0, 0x9d, 0x1a, 0xe7, 0x6d, 0xb0, 0x58, 0x84, 0xe8, 0x78, 0xd8, 0x7f, 0x67, 0xb0, 0x79, 0xf7,
0xda, 0x0c, 0xba, 0x0d, 0xbd, 0x35, 0x78, 0x0f, 0x25, 0x9f, 0xb9, 0x65, 0x4f, 0xa2, 0x16, 0x72,
0xab, 0x16, 0x42, 0x82, 0xb5, 0xd3, 0xf1, 0xcb, 0xea, 0x8e, 0xb2, 0xf4, 0xe1, 0x82, 0xd8, 0x40,
0x35, 0xf4, 0x47, 0xa3, 0xc3, 0xe8, 0x99, 0xf2, 0x5a, 0xc8, 0xcd, 0xd3, 0xae, 0x49, 0xe1, 0xcd,
0xdb, 0xc5, 0xab, 0xbf, 0x5f, 0x70, 0x07, 0xf9, 0x07, 0x33, 0xad, 0x6a, 0x21, 0x73, 0x35, 0x8d,
0xf3, 0x4e, 0xd7, 0x7b, 0xa6, 0x22, 0xc9, 0x85, 0xf0, 0x0e, 0x0a, 0x63, 0x4d, 0xcb, 0x54, 0x26,
0x3d, 0x03, 0xde, 0x42, 0x16, 0x2c, 0xad, 0x6b, 0x21, 0x2b, 0x95, 0x05, 0x8b, 0x8f, 0x00, 0x47,
0x6f, 0x47, 0xf7, 0x62, 0x47, 0x13, 0xe8, 0xa6, 0x16, 0xb2, 0x50, 0x57, 0x66, 0x4a, 0xff, 0x64,
0xdd, 0xb1, 0xa7, 0x6a, 0xbe, 0x68, 0x26, 0x44, 0x58, 0x19, 0x3e, 0x07, 0x82, 0x64, 0xd3, 0xbc,
0x7f, 0x85, 0xea, 0xf7, 0xcd, 0x69, 0x51, 0x4c, 0x35, 0x14, 0x2a, 0x0b, 0x71, 0x0a, 0x72, 0xe3,
0xe1, 0xc4, 0x71, 0x69, 0x60, 0x21, 0x7c, 0xf8, 0x5f, 0xc0, 0xf6, 0xea, 0xdc, 0x43, 0x99, 0xea,
0x7e, 0xfe, 0x09, 0x00, 0x00, 0xff, 0xff, 0x21, 0x50, 0x6b, 0x04, 0x7b, 0x01, 0x00, 0x00,
}
This diff is collapsed.
package types
import (
"encoding/hex"
secp256k1 "github.com/btcsuite/btcd/btcec"
"github.com/golang/protobuf/proto"
)
//exec type
const (
ExecErr = 0
ExecPack = 1
ExecOk = 2
)
//FromHex hex -> []byte
func FromHex(s string) ([]byte, error) {
if len(s) > 1 {
if s[0:2] == "0x" || s[0:2] == "0X" {
s = s[2:]
}
if len(s)%2 == 1 {
s = "0" + s
}
return hex.DecodeString(s)
}
return []byte{}, nil
}
//ToHex []byte -> hex
func ToHex(b []byte) string {
hex := hex.EncodeToString(b)
// Prefer output of "0x0" instead of "0x"
if len(hex) == 0 {
return ""
}
return hex
}
//ToHex []byte -> hex
func ToHexPrefix(b []byte) string {
hex := hex.EncodeToString(b)
// Prefer output of "0x0" instead of "0x"
if len(hex) == 0 {
return ""
}
return "0x" + hex
}
//Encode 编码
func Encode(data proto.Message) []byte {
b, err := proto.Marshal(data)
if err != nil {
panic(err)
}
return b
}
//Decode 解码
func Decode(data []byte, msg proto.Message) error {
return proto.Unmarshal(data, msg)
}
// ECDH Calculate a shared secret using elliptic curve Diffie-Hellman
func ECDH(priv *secp256k1.PrivateKey, pub *secp256k1.PublicKey) []byte {
ecKey := &secp256k1.PublicKey{}
ecKey.X, ecKey.Y = secp256k1.S256().ScalarMult(pub.X, pub.Y, priv.D.Bytes())
return ecKey.SerializeCompressed()
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment