Commit 9ff24cd5 authored by madengji's avatar madengji Committed by vipwzw

add merkle tree

parent 0baa7ba6
......@@ -45,8 +45,6 @@ func TestTransferOutput(t *testing.T) {
good.Assign(backend.Secret, "noteRandom", "2824204835")
good.Assign(backend.Secret, "noteHash", "16308793397024662832064523892418908145900866571524124093537199035808550255649")
assert.Solved(&r1csBN256, good, nil)
}
......
public, treeRootHash,0x2afea5c28f761f42f35cca471170ca072cbe4b69b6b18c4a3b45637e974783c4
public, authorizePubKey,9940039130125917226477779823200431190767730273667531970219395440191717439673
public, authorizeHash,0x2afea5c28f761f42f35cca471170ca072cbe4b69b6b18c4a3b45637e974783c4
public, authorizeSpendHash,0x2afea5c28f761f42f35cca471170ca072cbe4b69b6b18c4a3b45637e974783c4
public, treeRootHash,10531321614990797034921282585661869614556487056951485265320464926630499341310
public, authorizePubKey,13519883267141251871527102103999205179714486518503885909948192364772977661583
public, authorizeHash,1267825436937766239630340333349685320927256968591056373125946583184548355070
public, authorizeSpendHash,14468512365438613046028281588661351435476168610934165547900473609197783547663
secret, spendAmount,28242048
secret, spendPubKey,9940039130125917226477779823200431190767730273667531970219395440191717439673
secret, returnPubKey,9940039130125917226477779823200431190767730273667531970219395440191717439673
secret, authorizePubKey,9940039130125917226477779823200431190767730273667531970219395440191717439673
secret, authorizePriKey,19226210204356004706765360050059680583735587569269469539941275797408975356275
secret, spendFlag,0
secret, noteRandom,28242048
secret, path0,1e44c73ba7980b0450a8e997c9d9c78be5a9d7ceaf597df781469a1c9db4e4c9
secret, path1,191a80e377af9e0d04e1d75e8d702d4c2db21b952b9fff6bcca31f9e9fd5de00
secret, path2,220dc2041a8c81086a9bc8084e7f9ee0788ae2c8b7928e0b2e2672339b2933b3
secret, path3,295d631fcf0ed0d34742ac560fe7a0c0585225cff9194806d4d9d8e1f00e1747
secret, path4,215849ad7bd4344a807f4f0c9aefd2131572e3cb21a8b21aa96e8a11c4a214e5
secret, spendPubKey,13735985067536865723202617343666111332145536963656464451727087263423649028705
secret, returnPubKey,16067249407809359746114321133992130903102335882983385972747813693681808870497
secret, authorizePriKey,17822967620457187568904804290291537271142779717280482398091401115827760898835
secret, spendFlag,1
secret, noteRandom,2824204835
secret, path1,19561523370160677851616596032513161448778901506614020103852017946679781620105
secret, path2,13898857070666440684265042188056372750257678232709763835292910585848522658637
secret, path3,15019169196974879571470243100379529757970866395477207575033769902587972032431
secret, path4,0
secret, path5,0
secret, path6,0
secret, path7,0
......@@ -36,11 +34,10 @@ secret, helper9,1
secret, helper10,1
secret, valid0,1
secret, valid1,1
secret, valid2,1
secret, valid3,1
secret, valid4,1
secret, valid4,0
secret, valid5,0
secret, valid6,0
secret, valid7,0
......
public, nodeHash,0x2afea5c28f761f42f35cca471170ca072cbe4b69b6b18c4a3b45637e974783c4
public, amount,1000
public, nodeHash,16308793397024662832064523892418908145900866571524124093537199035808550255649
public, amount,28242048
secret, spendPubKey,9940039130125917226477779823200431190767730273667531970219395440191717439673
secret, returnPubKey,9940039130125917226477779823200431190767730273667531970219395440191717439673
secret, authorizePubKey,9940039130125917226477779823200431190767730273667531970219395440191717439673
secret, noteRandom,28242048
secret, spendPubKey,13735985067536865723202617343666111332145536963656464451727087263423649028705
secret, returnPubKey,16067249407809359746114321133992130903102335882983385972747813693681808870497
secret, authorizePubKey,13519883267141251871527102103999205179714486518503885909948192364772977661583
secret, noteRandom,2824204835
......
......@@ -14,8 +14,8 @@ secret, spendPriKey,101904778353009275576499342388203605294586816720738661162328
secret, spendFlag,1
secret, authorizeFlag,1
secret, noteRandom,2824204835
secret, noteHash,16308793397024662832064523892418908145900866571524124093537199035808550255649
secret, noteHash,16308793397024662832064523892418908145900866571524124093537199035808550255649
secret, path1,19561523370160677851616596032513161448778901506614020103852017946679781620105
secret, path2,13898857070666440684265042188056372750257678232709763835292910585848522658637
secret, path3,15019169196974879571470243100379529757970866395477207575033769902587972032431
......
public, commitValueX,9940039130125917226477779823200431190767730273667531970219395440191717439673
public, commitValueY,9940039130125917226477779823200431190767730273667531970219395440191717439673
public, nodeHash,0x2afea5c28f761f42f35cca471170ca072cbe4b69b6b18c4a3b45637e974783c4
public, commitValueX,14087975867275911077371231345227824611951436822132762463787130558957838320348
public, commitValueY,15113519960384204624879642069520481336224311978035289236693658603675385299879
public, nodeHash,16308793397024662832064523892418908145900866571524124093537199035808550255649
secret, spendAmount,28242048
secret, spendRandom,28242048
secret, spendPubKey,9940039130125917226477779823200431190767730273667531970219395440191717439673
secret, returnPubKey,9940039130125917226477779823200431190767730273667531970219395440191717439673
secret, authorizePubKey,9940039130125917226477779823200431190767730273667531970219395440191717439673
secret, noteRandom,28242048
secret, spendRandom,35
secret, spendPubKey,13735985067536865723202617343666111332145536963656464451727087263423649028705
secret, returnPubKey,16067249407809359746114321133992130903102335882983385972747813693681808870497
secret, authorizePubKey,13519883267141251871527102103999205179714486518503885909948192364772977661583
secret, noteRandom,2824204835
public, treeRootHash,0x2afea5c28f761f42f35cca471170ca072cbe4b69b6b18c4a3b45637e974783c4
public, authorizeHash,0x2afea5c28f761f42f35cca471170ca072cbe4b69b6b18c4a3b45637e974783c4
public, nullifierHash,0x2afea5c28f761f42f35cca471170ca072cbe4b69b6b18c4a3b45637e974783c4
public, treeRootHash,10531321614990797034921282585661869614556487056951485265320464926630499341310
public, authorizeSpendHash,14468512365438613046028281588661351435476168610934165547900473609197783547663
public, nullifierHash,6747518781649068310795677405858353007442326529625450860668944156162052335195
public, amount,28242048
secret, spendPubKey,9940039130125917226477779823200431190767730273667531970219395440191717439673
secret, returnPubKey,9940039130125917226477779823200431190767730273667531970219395440191717439673
secret, authorizePubKey,9940039130125917226477779823200431190767730273667531970219395440191717439673
secret, spendPriKey,19226210204356004706765360050059680583735587569269469539941275797408975356275
secret, spendFlag,0
secret, authorizeFlag,0
secret, noteRandom,28242048
secret, spendPubKey,13735985067536865723202617343666111332145536963656464451727087263423649028705
secret, returnPubKey,16067249407809359746114321133992130903102335882983385972747813693681808870497
secret, authorizePubKey,13519883267141251871527102103999205179714486518503885909948192364772977661583
secret, spendPriKey,10190477835300927557649934238820360529458681672073866116232821892325659279502
secret, spendFlag,1
secret, authorizeFlag,1
secret, noteRandom,2824204835
secret, path0,1e44c73ba7980b0450a8e997c9d9c78be5a9d7ceaf597df781469a1c9db4e4c9
secret, path1,191a80e377af9e0d04e1d75e8d702d4c2db21b952b9fff6bcca31f9e9fd5de00
secret, path2,220dc2041a8c81086a9bc8084e7f9ee0788ae2c8b7928e0b2e2672339b2933b3
secret, path3,295d631fcf0ed0d34742ac560fe7a0c0585225cff9194806d4d9d8e1f00e1747
secret, path4,215849ad7bd4344a807f4f0c9aefd2131572e3cb21a8b21aa96e8a11c4a214e5
secret, noteHash,16308793397024662832064523892418908145900866571524124093537199035808550255649
secret, path1,19561523370160677851616596032513161448778901506614020103852017946679781620105
secret, path2,13898857070666440684265042188056372750257678232709763835292910585848522658637
secret, path3,15019169196974879571470243100379529757970866395477207575033769902587972032431
secret, path4,0
secret, path5,0
secret, path6,0
secret, path7,0
......@@ -33,19 +33,17 @@ secret, helper6,1
secret, helper7,1
secret, helper8,1
secret, helper9,1
secret, helper10,1
secret, valid0,1
secret, valid1,1
secret, valid2,1
secret, valid3,1
secret, valid4,1
secret, valid4,0
secret, valid5,0
secret, valid6,0
secret, valid7,0
secret, valid8,0
secret, valid9,0
secret, valid10,0
......@@ -7,6 +7,7 @@ package executor
import (
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/client"
"github.com/consensys/gurvy/bn256/fr"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/system/dapp"
......@@ -79,3 +80,15 @@ func makeReceipt(key []byte, logTy int32, data proto.Message) *types.Receipt {
},
}
}
func transferFr2Bytes(v string) []byte {
var leaf fr.Element
leaf.SetString(v)
return leaf.Bytes()
}
func transferFr2String(val []byte) string {
var leaf fr.Element
leaf.SetBytes(val)
return leaf.String()
}
......@@ -8,8 +8,6 @@ import (
"encoding/hex"
"encoding/json"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/types"
mixTy "github.com/33cn/plugin/plugin/dapp/mix/types"
......@@ -19,18 +17,18 @@ import (
func (a *action) authParamCheck(input *mixTy.AuthorizePublicInput) error {
//check tree rootHash exist
if !checkTreeRootHashExist(a.db, input.TreeRootHash) {
return errors.Wrapf(mixTy.ErrTreeRootHashNotFound, "roothash=%s", common.ToHex(input.TreeRootHash))
if !checkTreeRootHashExist(a.db, transferFr2Bytes(input.TreeRootHash)) {
return errors.Wrapf(mixTy.ErrTreeRootHashNotFound, "roothash=%s", input.TreeRootHash)
}
//authorize key should not exist
authKey := calcAuthorizeHashKey(common.ToHex(input.AuthorizeHash))
authKey := calcAuthorizeHashKey(input.AuthorizeHash)
_, err := a.db.Get(authKey)
if err == nil {
return errors.Wrapf(mixTy.ErrAuthorizeHashExist, "auth=%s", common.ToHex(input.AuthorizeHash))
return errors.Wrapf(mixTy.ErrAuthorizeHashExist, "auth=%s", input.AuthorizeHash)
}
if !isNotFound(err) {
return errors.Wrapf(err, "auth=%s", common.ToHex(input.AuthorizeHash))
return errors.Wrapf(err, "auth=%s", input.AuthorizeHash)
}
authPubKeys, err := a.getAuthKeys()
......@@ -97,9 +95,9 @@ func (a *action) Authorize(authorize *mixTy.MixAuthorizeAction) (*types.Receipt,
receipt := &types.Receipt{Ty: types.ExecOk}
for _, in := range inputs {
r := makeReceipt(calcAuthorizeHashKey(common.ToHex(in.AuthorizeHash)), mixTy.TyLogAuthorizeSet, &mixTy.ExistValue{Data: true})
r := makeReceipt(calcAuthorizeHashKey(in.AuthorizeHash), mixTy.TyLogAuthorizeSet, &mixTy.ExistValue{Data: true})
mergeReceipt(receipt, r)
r = makeReceipt(calcAuthorizeSpendHashKey(common.ToHex(in.AuthorizeSpendHash)), mixTy.TyLogAuthorizeSpendSet, &mixTy.ExistValue{Data: true})
r = makeReceipt(calcAuthorizeSpendHashKey(in.AuthorizeSpendHash), mixTy.TyLogAuthorizeSpendSet, &mixTy.ExistValue{Data: true})
mergeReceipt(receipt, r)
}
......
......@@ -6,28 +6,17 @@ package executor
import (
"bytes"
"strconv"
"strings"
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/types"
"github.com/33cn/plugin/plugin/dapp/mix/executor/merkletree"
mixTy "github.com/33cn/plugin/plugin/dapp/mix/types"
"github.com/NebulousLabs/merkletree"
"github.com/consensys/gnark/crypto/hash/mimc/bn256"
"github.com/pkg/errors"
)
//func makeTreeReceipt(key []byte, logTy int32, data proto.Message) *types.Receipt {
// return &types.Receipt{
// Ty: types.ExecOk,
// KV: []*types.KeyValue{
// {Key: key, Value: types.Encode(data)},
// },
// Logs: []*types.ReceiptLog{
// {Ty: logTy, Log: types.Encode(data)},
// },
// }
//}
func makeTreeLeavesReceipt(data *mixTy.CommitTreeLeaves) *types.Receipt {
return makeReceipt(calcCurrentCommitLeavesKey(), mixTy.TyLogCurrentCommitTreeLeaves, data)
}
......@@ -42,8 +31,8 @@ func makeCurrentTreeReceipt(leaves *mixTy.CommitTreeLeaves, roots *mixTy.CommitT
return mergeReceipt(r1, r2)
}
func makeTreeRootLeavesReceipt(root []byte, data *mixTy.CommitTreeLeaves) *types.Receipt {
return makeReceipt(calcCommitTreeRootLeaves(common.ToHex(root)), mixTy.TyLogCommitTreeRootLeaves, data)
func makeTreeRootLeavesReceipt(root string, data *mixTy.CommitTreeLeaves) *types.Receipt {
return makeReceipt(calcCommitTreeRootLeaves(root), mixTy.TyLogCommitTreeRootLeaves, data)
}
func makeTreeArchiveRootsReceipt(data *mixTy.CommitTreeRoots) *types.Receipt {
......@@ -68,8 +57,8 @@ func getCurrentCommitTreeLeaves(db dbm.KV) (*mixTy.CommitTreeLeaves, error) {
return getCommitLeaves(db, calcCurrentCommitLeavesKey())
}
func getCommitRootLeaves(db dbm.KV, rootHash []byte) (*mixTy.CommitTreeLeaves, error) {
return getCommitLeaves(db, calcCommitTreeRootLeaves(common.ToHex(rootHash)))
func getCommitRootLeaves(db dbm.KV, rootHash string) (*mixTy.CommitTreeLeaves, error) {
return getCommitLeaves(db, calcCommitTreeRootLeaves(rootHash))
}
func getCommitTreeRoots(db dbm.KV, key []byte) (*mixTy.CommitTreeRoots, error) {
......@@ -130,7 +119,7 @@ func initNewLeaves(leaf []byte) *types.Receipt {
}
func archiveRoots(db dbm.KV, root []byte, leaves *mixTy.CommitTreeLeaves) (*types.Receipt, error) {
receiptRootLeaves := makeTreeRootLeavesReceipt(root, leaves)
receiptRootLeaves := makeTreeRootLeavesReceipt(transferFr2String(root), leaves)
archiveRoots, err := getArchiveCommitRoots(db)
if isNotFound(errors.Cause(err)) {
......@@ -216,14 +205,16 @@ func checkTreeRootHashExist(db dbm.KV, hash []byte) bool {
func getProveData(targetLeaf []byte, leaves [][]byte) (*mixTy.CommitTreeProve, error) {
index := 0
found := false
for i, key := range leaves {
if bytes.Equal(key, targetLeaf) {
index = i
found = true
break
}
}
//index=0的leaf是占位"00",不会和leaf相等
if index == 0 {
if !found {
return nil, mixTy.ErrLeafNotFound
}
......@@ -232,22 +223,35 @@ func getProveData(targetLeaf []byte, leaves [][]byte) (*mixTy.CommitTreeProve, e
for _, key := range leaves {
tree.Push(key)
}
root, set, proofIndex, num := tree.Prove()
root, proofSet, proofIndex, num := tree.Prove()
var prove mixTy.CommitTreeProve
prove.RootHash = common.ToHex(root)
prove.RootHash = transferFr2String(root)
prove.ProofIndex = uint32(proofIndex)
prove.NumLeaves = uint32(num)
for _, s := range set {
prove.ProofSet = append(prove.ProofSet, common.ToHex(s))
//set[0] 是targetLeaf
for _, s := range proofSet {
prove.ProofSet = append(prove.ProofSet, transferFr2String(s))
}
helpers := merkletree.GenerateProofHelper(proofSet, proofIndex, num)
var helpStr []string
for _, i := range helpers {
helpStr = append(helpStr, strconv.Itoa(i))
}
prove.Helpers = strings.Join(helpStr, ",")
return &prove, nil
}
func CalcTreeProve(db dbm.KV, rootHash, leaf []byte) (*mixTy.CommitTreeProve, error) {
func CalcTreeProve(db dbm.KV, rootHash, leaf string) (*mixTy.CommitTreeProve, error) {
if len(leaf) <= 0 {
return nil, errors.Wrap(types.ErrInvalidParam, "leaf is null")
}
leaves, err := getCurrentCommitTreeLeaves(db)
if err == nil {
p, err := getProveData(leaf, leaves.Data)
p, err := getProveData(transferFr2Bytes(leaf), leaves.Data)
if err == nil {
return p, nil
}
......@@ -258,9 +262,9 @@ func CalcTreeProve(db dbm.KV, rootHash, leaf []byte) (*mixTy.CommitTreeProve, er
if err != nil {
return nil, err
}
p, err := getProveData(leaf, leaves.Data)
p, err := getProveData(transferFr2Bytes(leaf), leaves.Data)
if err != nil {
return nil, errors.Wrapf(err, "hash=%s,leaf=%s", common.ToHex(rootHash), common.ToHex(leaf))
return nil, errors.Wrapf(err, "hash=%s,leaf=%s", rootHash, leaf)
}
return p, nil
}
......@@ -268,9 +272,9 @@ func CalcTreeProve(db dbm.KV, rootHash, leaf []byte) (*mixTy.CommitTreeProve, er
roots, err := getArchiveCommitRoots(db)
if err == nil {
for _, root := range roots.Data {
leaves, err := getCommitRootLeaves(db, root)
leaves, err := getCommitRootLeaves(db, transferFr2String(root))
if err == nil {
p, err := getProveData(leaf, leaves.Data)
p, err := getProveData(transferFr2Bytes(leaf), leaves.Data)
if err == nil {
return p, nil
}
......@@ -279,6 +283,6 @@ func CalcTreeProve(db dbm.KV, rootHash, leaf []byte) (*mixTy.CommitTreeProve, er
}
}
return nil, errors.Wrapf(err, "hash=%s,leaf=%s", common.ToHex(rootHash), common.ToHex(leaf))
return nil, errors.Wrapf(err, "hash=%s,leaf=%s", rootHash, leaf)
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package executor
import (
"testing"
"github.com/stretchr/testify/assert"
)
/*
leaf0 = "16308793397024662832064523892418908145900866571524124093537199035808550255649"
hexstr 240e732fc90c3a88a11f3f60bbbe412f6b4b56d007cf34fdb2500195071c7c21
leaf1 = 21467822781369104390668289189963532506973289112396605437823854946060028754354
leaf hash 17799daf83d82530d70343bc44578bdabafcb134332d4949883695a1ec9d1ba9
leaf2= 4178471437305290899835614805415999986197321812505352791035422725360758750328
leaf hash 29ded1ba9ed45d829f458ce511e013a8d11058db9d6f03fea14267082087b151
leaf3= 10407830929890509544473717262275616077696950294748419792758056545898949331744
leaf hash 1b757026b07fd17150c5d23081bddd52e77dc26b0c7c46b4e0150ca7ccfed35a
leaf4= 11032604436245646157001636966356016502073301224837385665550497706958264582086
leaf hash 24a8d61af8e16abaf9ccb1051c882799121c6ece1094655b5b93f837aead2f30
merkleroot= 6988991286454436061784929049510388415076132311642532433013500389938249229356
0 proof str= 21467822781369104390668289189963532506973289112396605437823854946060028754354
1 proof str= 12096317366724227951683802305909172775715878134489527031786909074403605889217
2 proof str= 14541527209424185878803689752018034974129079647509824805270353433359922459228
3 proof str= 16581570556767364549626991605903512613557832602774591000372759906303762837296
*/
func TestGetProveData(t *testing.T) {
leaves := []string{
"16308793397024662832064523892418908145900866571524124093537199035808550255649",
"21467822781369104390668289189963532506973289112396605437823854946060028754354",
"4178471437305290899835614805415999986197321812505352791035422725360758750328",
"10407830929890509544473717262275616077696950294748419792758056545898949331744",
"11032604436245646157001636966356016502073301224837385665550497706958264582086",
}
proves := []string{
"21467822781369104390668289189963532506973289112396605437823854946060028754354",
"12096317366724227951683802305909172775715878134489527031786909074403605889217",
"14541527209424185878803689752018034974129079647509824805270353433359922459228",
"16581570556767364549626991605903512613557832602774591000372759906303762837296",
}
var leave [][]byte
for _, l := range leaves {
leave = append(leave, transferFr2Bytes(l))
}
ret, err := getProveData(leave[1], leave)
assert.Nil(t, err)
assert.Equal(t, uint32(5), ret.NumLeaves)
assert.Equal(t, uint32(1), ret.ProofIndex)
assert.Equal(t, "6988991286454436061784929049510388415076132311642532433013500389938249229356", ret.RootHash)
assert.Equal(t, len(proves), len(ret.ProofSet))
for i, k := range proves {
assert.Equal(t, k, ret.ProofSet[i])
}
assert.Equal(t, "0,1,1", ret.Helpers)
}
......@@ -26,7 +26,7 @@ func isSuperManager(cfg *types.Chain33Config, addr string) bool {
func (a *action) Config(config *mixTy.MixConfigAction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
if !isSuperManager(cfg, a.fromaddr) {
return nil, types.ErrNotAllow
return nil, errors.Wrapf(types.ErrNotAllow, "not super manager,%s", a.fromaddr)
}
switch config.Ty {
case mixTy.MixConfigType_VerifyKey:
......
......@@ -9,8 +9,6 @@ import (
"encoding/json"
"strconv"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/types"
"github.com/33cn/plugin/plugin/dapp/mix/executor/zksnark"
......@@ -20,8 +18,8 @@ import (
"github.com/pkg/errors"
)
func makeNullifierSetReceipt(hash []byte, data proto.Message) *types.Receipt {
return makeReceipt(calcNullifierHashKey(common.ToHex(hash)), mixTy.TyLogNulliferSet, data)
func makeNullifierSetReceipt(hash string, data proto.Message) *types.Receipt {
return makeReceipt(calcNullifierHashKey(hash), mixTy.TyLogNulliferSet, data)
}
......@@ -72,7 +70,7 @@ func (a *action) depositVerify(proof *mixTy.ZkProofInfo) ([]byte, uint64, error)
return nil, 0, err
}
return input.NodeHash, val, nil
return transferFr2Bytes(input.NodeHash), val, nil
}
......
// from https://gitlab.com/NebulousLabs/merkletree
package merkletree
import (
"errors"
"hash"
"io"
)
// ReadAll will read segments of size 'segmentSize' and push them into the tree
// until EOF is reached. Success will return 'err == nil', not 'err == EOF'. No
// padding is added to the data, so the last element may be smaller than
// 'segmentSize'.
func (t *Tree) ReadAll(r io.Reader, segmentSize int) error {
for {
segment := make([]byte, segmentSize)
n, readErr := io.ReadFull(r, segment)
if readErr == io.EOF {
// All data has been read.
break
} else if readErr == io.ErrUnexpectedEOF {
// This is the last segment, and there aren't enough bytes to fill
// the entire segment. Note that the next call will return io.EOF.
segment = segment[:n]
} else if readErr != nil {
return readErr
}
t.Push(segment)
}
return nil
}
// ReaderRoot returns the Merkle root of the data read from the reader, where
// each leaf is 'segmentSize' long and 'h' is used as the hashing function. All
// leaves will be 'segmentSize' bytes except the last leaf, which will not be
// padded out if there are not enough bytes remaining in the reader.
func ReaderRoot(r io.Reader, h hash.Hash, segmentSize int) (root []byte, err error) {
tree := New(h)
err = tree.ReadAll(r, segmentSize)
if err != nil {
return
}
root = tree.Root()
return
}
// BuildReaderProof returns a proof that certain data is in the merkle tree
// created by the data in the reader. The merkle root, set of proofs, and the
// number of leaves in the Merkle tree are all returned. All leaves will we
// 'segmentSize' bytes except the last leaf, which will not be padded out if
// there are not enough bytes remaining in the reader.
func BuildReaderProof(r io.Reader, h hash.Hash, segmentSize int, index uint64) (root []byte, proofSet [][]byte, numLeaves uint64, err error) {
tree := New(h)
err = tree.SetIndex(index)
if err != nil {
// This code should be unreachable - SetIndex will only return an error
// if the tree is not empty, and yet the tree should be empty at this
// point.
panic(err)
}
err = tree.ReadAll(r, segmentSize)
if err != nil {
return
}
root, proofSet, _, numLeaves = tree.Prove()
if len(proofSet) == 0 {
err = errors.New("index was not reached while creating proof")
return
}
return
}
This diff is collapsed.
// from https://gitlab.com/NebulousLabs/merkletree
package merkletree
import (
"bytes"
"hash"
)
// VerifyProof takes a Merkle root, a proofSet, and a proofIndex and returns
// true if the first element of the proof set is a leaf of data in the Merkle
// root. False is returned if the proof set or Merkle root is nil, and if
// 'numLeaves' equals 0.
func VerifyProof(h hash.Hash, merkleRoot []byte, proofSet [][]byte, proofIndex uint64, numLeaves uint64) bool {
// Return false for nonsense input. A switch statement is used so that the
// cover tool will reveal if a case is not covered by the test suite. This
// would not be possible using a single if statement due to the limitations
// of the cover tool.
if merkleRoot == nil {
return false
}
if proofIndex >= numLeaves {
return false
}
// In a Merkle tree, every node except the root node has a sibling.
// Combining the two siblings in the correct order will create the parent
// node. Each of the remaining hashes in the proof set is a sibling to a
// node that can be built from all of the previous elements of the proof
// set. The next node is built by taking:
//
// H(0x01 || sibling A || sibling B)
//
// The difficulty of the algorithm lies in determining whether the supplied
// hash is sibling A or sibling B. This information can be determined by
// using the proof index and the total number of leaves in the tree.
//
// A pair of two siblings forms a subtree. The subtree is complete if it
// has 1 << height total leaves. When the subtree is complete, the position
// of the proof index within the subtree can be determined by looking at
// the bounds of the subtree and determining if the proof index is in the
// first or second half of the subtree.
//
// When the subtree is not complete, either 1 or 0 of the remaining hashes
// will be sibling B. All remaining hashes after that will be sibling A.
// This is true because of the way that orphans are merged into the Merkle
// tree - an orphan at height n is elevated to height n + 1, and only
// hashed when it is no longer an orphan. Each subtree will therefore merge
// with at most 1 orphan to the right before becoming an orphan itself.
// Orphan nodes are always merged with larger subtrees to the left.
//
// One vulnerability with the proof verification is that the proofSet may
// not be long enough. Before looking at an element of proofSet, a check
// needs to be made that the element exists.
// The first element of the set is the original data. A sibling at height 1
// is created by getting the leafSum of the original data.
height := 0
if len(proofSet) <= height {
return false
}
sum := leafSum(h, proofSet[height])
height++
// While the current subtree (of height 'height') is complete, determine
// the position of the next sibling using the complete subtree algorithm.
// 'stableEnd' tells us the ending index of the last full subtree. It gets
// initialized to 'proofIndex' because the first full subtree was the
// subtree of height 1, created above (and had an ending index of
// 'proofIndex').
stableEnd := proofIndex
for {
// Determine if the subtree is complete. This is accomplished by
// rounding down the proofIndex to the nearest 1 << 'height', adding 1
// << 'height', and comparing the result to the number of leaves in the
// Merkle tree.
subTreeStartIndex := (proofIndex / (1 << uint(height))) * (1 << uint(height)) // round down to the nearest 1 << height
subTreeEndIndex := subTreeStartIndex + (1 << (uint(height))) - 1 // subtract 1 because the start index is inclusive
if subTreeEndIndex >= numLeaves {
// If the Merkle tree does not have a leaf at index
// 'subTreeEndIndex', then the subtree of the current height is not
// a complete subtree.
break
}
stableEnd = subTreeEndIndex
// Determine if the proofIndex is in the first or the second half of
// the subtree.
if len(proofSet) <= height {
return false
}
if proofIndex-subTreeStartIndex < 1<<uint(height-1) {
sum = nodeSum(h, sum, proofSet[height])
} else {
sum = nodeSum(h, proofSet[height], sum)
}
height++
}
// Determine if the next hash belongs to an orphan that was elevated. This
// is the case IFF 'stableEnd' (the last index of the largest full subtree)
// is equal to the number of leaves in the Merkle tree.
if stableEnd != numLeaves-1 {
if len(proofSet) <= height {
return false
}
sum = nodeSum(h, sum, proofSet[height])
height++
}
// All remaining elements in the proof set will belong to a left sibling.
for height < len(proofSet) {
sum = nodeSum(h, proofSet[height], sum)
height++
}
// Compare our calculated Merkle root to the desired Merkle root.
if bytes.Equal(sum, merkleRoot) {
return true
}
return false
}
// GenerateProofHelper generates an array of 1 or 0 telling if during the proof verification
// the hash to compute is h(sum, proof[i]) or h(proof[i], sum). The size of the resulting slice is
// len(proofSet)-1.
// cf gitlab.com/NebulousLabs/merkletree for the algorithm
func GenerateProofHelper(proofSet [][]byte, proofIndex, numLeaves uint64) []int {
res := make([]int, len(proofSet)-1)
height := 1
// While the current subtree (of height 'height') is complete, determine
// the position of the next sibling using the complete subtree algorithm.
// 'stableEnd' tells us the ending index of the last full subtree. It gets
// initialized to 'proofIndex' because the first full subtree was the
// subtree of height 1, created above (and had an ending index of
// 'proofIndex').
stableEnd := proofIndex
for {
// Determine if the subtree is complete. This is accomplished by
// rounding down the proofIndex to the nearest 1 << 'height', adding 1
// << 'height', and comparing the result to the number of leaves in the
// Merkle tree.
subTreeStartIndex := (proofIndex / (1 << uint(height))) * (1 << uint(height)) // round down to the nearest 1 << height
subTreeEndIndex := subTreeStartIndex + (1 << (uint(height))) - 1 // subtract 1 because the start index is inclusive
if subTreeEndIndex >= numLeaves {
// If the Merkle tree does not have a leaf at index
// 'subTreeEndIndex', then the subtree of the current height is not
// a complete subtree.
break
}
stableEnd = subTreeEndIndex
if proofIndex-subTreeStartIndex < 1<<uint(height-1) {
res[height-1] = 1
} else {
res[height-1] = 0
}
height++
}
// Determine if the next hash belongs to an orphan that was elevated. This
// is the case IFF 'stableEnd' (the last index of the largest full subtree)
// is equal to the number of leaves in the Merkle tree.
if stableEnd != numLeaves-1 {
res[height-1] = 1
height++
}
// All remaining elements in the proof set will belong to a left sibling.
for height < len(proofSet) {
res[height-1] = 0
height++
}
return res
}
......@@ -5,8 +5,6 @@
package executor
import (
pt "github.com/33cn/plugin/plugin/dapp/paracross/types"
log "github.com/33cn/chain33/common/log/log15"
drivers "github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
......@@ -49,6 +47,6 @@ func newMix() drivers.Driver {
}
// GetDriverName return paracross driver name
func (c *Mix) GetDriverName() string {
return pt.ParaX
func (m *Mix) GetDriverName() string {
return mixTy.MixX
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package executor
import (
"github.com/33cn/chain33/types"
mixTy "github.com/33cn/plugin/plugin/dapp/mix/types"
)
// Query_GetTitle query paracross title
func (m *Mix) Query_GetTreePath(in *mixTy.TreePathReq) (types.Message, error) {
if in == nil {
return nil, types.ErrInvalidParam
}
return CalcTreeProve(m.GetStateDB(), in.RootHash, in.LeafHash)
}
......@@ -31,7 +31,7 @@ func (a *action) transferInputVerify(proof *mixTy.ZkProofInfo) (*mixTy.TransferI
return nil, errors.Wrapf(err, "unmarshal string=%s", proof.PublicInput)
}
err = a.spendVerify(input.TreeRootHash, input.NullifierHash, input.AuthorizeHash)
err = a.spendVerify(input.TreeRootHash, input.NullifierHash, input.AuthorizeSpendHash)
if err != nil {
return nil, err
}
......@@ -138,7 +138,7 @@ func (a *action) Transfer(transfer *mixTy.MixTransferAction) (*types.Receipt, er
//push new commit to merkle tree
for _, h := range outputs {
rpt, err := pushTree(a.db, h.NodeHash)
rpt, err := pushTree(a.db, transferFr2Bytes(h.NodeHash))
if err != nil {
return nil, err
}
......
......@@ -9,37 +9,35 @@ import (
"encoding/json"
"strconv"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/types"
mixTy "github.com/33cn/plugin/plugin/dapp/mix/types"
"github.com/pkg/errors"
)
func (a *action) spendVerify(treeRootHash, nulliferHash, authorizeHash []byte) error {
func (a *action) spendVerify(treeRootHash, nulliferHash, authorizeSpendHash string) error {
//zk-proof校验
//check tree rootHash exist
if !checkTreeRootHashExist(a.db, treeRootHash) {
return errors.Wrapf(mixTy.ErrTreeRootHashNotFound, "roothash=%s", common.ToHex(treeRootHash))
if !checkTreeRootHashExist(a.db, transferFr2Bytes(treeRootHash)) {
return errors.Wrapf(mixTy.ErrTreeRootHashNotFound, "roothash=%s", treeRootHash)
}
//nullifier should not exist
nullifierKey := calcNullifierHashKey(common.ToHex(nulliferHash))
nullifierKey := calcNullifierHashKey(nulliferHash)
_, err := a.db.Get(nullifierKey)
if err == nil {
return errors.Wrapf(mixTy.ErrNulliferHashExist, "nullifier=%s", common.ToHex(nulliferHash))
return errors.Wrapf(mixTy.ErrNulliferHashExist, "nullifier=%s", nulliferHash)
}
if !isNotFound(err) {
return errors.Wrapf(err, "nullifier=%s", common.ToHex(nulliferHash))
return errors.Wrapf(err, "nullifier=%s", nulliferHash)
}
// authorize should exist if needed
if len(authorizeHash) > 0 {
authKey := calcAuthorizeHashKey(common.ToHex(authorizeHash))
if len(authorizeSpendHash) > 0 {
authKey := calcAuthorizeHashKey(authorizeSpendHash)
_, err = a.db.Get(authKey)
if err != nil {
return errors.Wrapf(err, "authorize=%s", common.ToHex(authorizeHash))
return errors.Wrapf(err, "authorize=%s", authorizeSpendHash)
}
}
......@@ -47,29 +45,29 @@ func (a *action) spendVerify(treeRootHash, nulliferHash, authorizeHash []byte) e
}
func (a *action) withdrawVerify(proof *mixTy.ZkProofInfo) ([]byte, uint64, error) {
func (a *action) withdrawVerify(proof *mixTy.ZkProofInfo) (string, uint64, error) {
var input mixTy.WithdrawPublicInput
data, err := hex.DecodeString(proof.PublicInput)
if err != nil {
return nil, 0, errors.Wrapf(err, "decode string=%s", proof.PublicInput)
return "", 0, errors.Wrapf(err, "decode string=%s", proof.PublicInput)
}
err = json.Unmarshal(data, &input)
if err != nil {
return nil, 0, errors.Wrapf(err, "unmarshal string=%s", proof.PublicInput)
return "", 0, errors.Wrapf(err, "unmarshal string=%s", proof.PublicInput)
}
val, err := strconv.ParseUint(input.Amount, 10, 64)
if err != nil {
return nil, 0, errors.Wrapf(err, "parseUint=%s", input.Amount)
return "", 0, errors.Wrapf(err, "parseUint=%s", input.Amount)
}
err = a.spendVerify(input.TreeRootHash, input.NullifierHash, input.AuthorizeHash)
err = a.spendVerify(input.TreeRootHash, input.NullifierHash, input.AuthorizeSpendHash)
if err != nil {
return nil, 0, err
return "", 0, err
}
err = a.zkProofVerify(proof, mixTy.VerifyType_WITHDRAW)
if err != nil {
return nil, 0, err
return "", 0, err
}
return input.NullifierHash, val, nil
......@@ -82,7 +80,7 @@ func (a *action) withdrawVerify(proof *mixTy.ZkProofInfo) ([]byte, uint64, error
3. set nullifier exist
*/
func (a *action) Withdraw(withdraw *mixTy.MixWithdrawAction) (*types.Receipt, error) {
var nulliferSet [][]byte
var nulliferSet []string
var sumValue uint64
for _, k := range withdraw.SpendCommits {
nulfier, v, err := a.withdrawVerify(k)
......
......@@ -102,39 +102,39 @@ message MixAction {
message DepositPublicInput {
bytes nodeHash = 1;
string nodeHash = 1;
string amount = 2;
}
message WithdrawPublicInput {
bytes treeRootHash = 1;
bytes nullifierHash = 2;
bytes authorizeHash = 3;
string treeRootHash = 1;
string nullifierHash = 2;
string authorizeSpendHash = 3;
string amount = 4;
}
message TransferInputPublicInput {
bytes treeRootHash = 1;
string treeRootHash = 1;
string commitValueX = 2;
string commitValueY = 3;
bytes authorizeHash = 4;
bytes nullifierHash = 5;
string authorizeSpendHash = 4;
string nullifierHash = 5;
}
message TransferOutputPublicInput {
bytes nodeHash = 1;
string nodeHash = 1;
string commitValueX = 2;
string commitValueY = 3;
}
message AuthorizePublicInput {
bytes treeRootHash = 1;
string treeRootHash = 1;
string authorizePubKey = 2;
bytes authorizeHash = 3;
bytes authorizeSpendHash = 4;
string authorizeHash = 3;
string authorizeSpendHash = 4;
}
......@@ -156,9 +156,13 @@ message CommitTreeProve {
repeated string proofSet = 2;
uint32 proofIndex = 3;
uint32 numLeaves = 4;
string helpers = 5;
}
message TreePathReq{
string rootHash = 1;
string leafHash = 2;
}
......
This diff is collapsed.
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