Fabric 1.3中的新增的idemixer(Identity Mixer)以前不大懂zero-knowledge proof(零知识证明),原本觉得PKI基础的MSP是比较常用和稳健的方式,新加个验证方式是不是有点增加复杂性。

最近有时间整理下,才发现零知识证明也真是个黑科技。

1. 零知识证明入门

1.1 零知识证明例子

网上这篇文章写得蛮好的http://www.elecfans.com/blockchain/1015964.html

这里以Fabric给出的例子: 假设Alice需要向Bob(门店职员)证明她DMV(车管所)颁发的合法驾照。这个场景,Alice就是下图的user/用户, DMV车管所则是issuer/证书颁发者,Bob则是verifier验证者。 idemix-overview.png

Alice为了证明自己是合法的司机,大多时候她会把自己的驾照交给Bob检查和验证,但这样做Bob就可以知道Alice的很多额外的隐私信息,例如名字,地址,年龄等。

如果使用idemixer和零正式证明的方式, 我们只允许Bob知道当前这个女用户是个合法的司机,其它信息都保密。 即使下次Alice再来门店,Alice应该提供给Bob不同的证明,保证Bob不会知道这个证明是同一个用户。

即零知识证明可提供匿名性和无关联性。

1.2 零知识证明用处

elecfans的文章总结得很好了,常见的是以下两点。

  • 数据隐私保护和身份验证,如Alice和Bob的例子所示,
  • 减少计算和扩容,同样的多次计算可以使用零知识证明压缩和减少,最新的以太坊可是大力推崇

2. 如果使用Fabric的idemixer

2.1 测试开发环境使用idemixgen命令行

具体参看https://hyperledger-fabric.readthedocs.io/en/latest/idemixgen.html

2.2 生产环境使用Fabric CA 1.3以上版本

(1) Fabric CA配置 fabric-ca-server init会生成IssuerPublicKey和IssuerRevocationPublicKey两个文件

(2) MSP初始化配置 configtx.yaml定义Org1Idemix和Org2Idemix两个组织, 注意msptype类型为idemix, mspdir对应文件应使用Fabric CA生成的IssuerPublicKey和IssuerRevocationPublicKey构成。

Organizations:
   - &Org1Idemix
        # defaultorg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        name: idemixMSP1

        # id to load the msp definition as
        id: idemixMSPID1

        msptype: idemix
        mspdir: crypto-config/peerOrganizations/org3.example.com


    - &Org2Idemix
        # defaultorg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        name: idemixMSP2

        # id to load the msp definition as
        id: idemixMSPID2

        msptype: idemix
        mspdir: crypto-config/peerOrganizations/org4.example.com

profiles:
    TwoOrgsOrdererGenesis_v13:
        Capabilities:
            <<: *ChannelCapabilities
        Orderer:
            <<: *OrdererDefaults
            Organizations:
                - *OrdererOrg
            Capabilities:
                <<: *OrdererCapabilities
        Consortiums:
            SampleConsortium:
                Organizations:
                    - *Org1
                    - *Org2
                    - *Org1Idemix
                    - *Org2Idemix
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *OrdererOrg
            Capabilities:
                <<: *ApplicationCapabilities1_3

    TwoOrgsChannel_v13:
        Consortium: SampleConsortium
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *Org1
                - *Org2
                - *Org1Idemix
                - *Org2Idemix
            Capabilities:
                <<: *ApplicationCapabilities1_3

(3) CA客户端生成用户

IdemixEnrollment idemixEnrollment = hfcaClient.idemixEnroll(x509enrollment, "idemixMSPID1");

(4) 验证者链码如何获取idemixer信息 暂时go的链码的cid(Client Identity)库才支持获取idemixer证书信息。

func GetAttributeValue(stub ChaincodeStubInterface, attrName string) (value string, found bool, err error)

type ChaincodeStubInterface interface {
    // GetCreator returns `SignatureHeader.Creator` (e.g. an identity)
    // of the `SignedProposal`. This is the identity of the agent (or user)
    // submitting the transaction.
    GetCreator() ([]byte, error)
}

type ClientIdentity interface {

    // GetID returns the ID associated with the invoking identity.  This ID
    // is guaranteed to be unique within the MSP.
    GetID() (string, error)

    // Return the MSP ID of the client
    GetMSPID() (string, error)

    // GetAttributeValue returns the value of the client's attribute named `attrName`.
    // If the client possesses the attribute, `found` is true and `value` equals the
    // value of the attribute.
    // If the client does not possess the attribute, `found` is false and `value`
    // equals "".
    GetAttributeValue(attrName string) (value string, found bool, err error)

    // AssertAttributeValue verifies that the client has the attribute named `attrName`
    // with a value of `attrValue`; otherwise, an error is returned.
    AssertAttributeValue(attrName, attrValue string) error

    // GetX509Certificate returns the X509 certificate associated with the client,
    // or nil if it was not identified by an X509 certificate.
    GetX509Certificate() (*x509.Certificate, error)
}

暂时idemixer的GetAttributeValue只支持ou和role

  • ou 是identity’s affiliation (e.g. “org1.department1”)
  • role 是‘member’ 或 ‘admin’.

具体调用的go链码

package main

import (
	"fmt"
	"log"
    "os"
	"strconv"
	"strings"

	"github.com/hyperledger/fabric-chaincode-go/pkg/cid"
	"github.com/hyperledger/fabric-chaincode-go/shim"
	pb "github.com/hyperledger/fabric-protos-go/peer"
)
// Invoke makes payment of X units from A to B
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	Info.Println("########### example_cc Invoke ###########")

	function, args := stub.GetFunctionAndParameters()

	// Getting attributes from an idemix credential
	ou, found, err := cid.GetAttributeValue(stub, "ou");
	if err != nil {
		return shim.Error("Failed to get attribute 'ou'")
	}
	if !found {
		return shim.Error("attribute 'ou' not found")
	}
	if !strings.HasSuffix(ou, "department1") {
		return shim.Error(fmt.Sprintf("Incorrect 'ou' returned, got '%s' expecting to end with 'department1'", ou))
	}
	role, found, err := cid.GetAttributeValue(stub, "role");
	if err != nil {
		return shim.Error("Failed to get attribute 'role'")
	}
	if !found {
		return shim.Error("attribute 'role' not found")
	}
	if role != "member" {
		return shim.Error(fmt.Sprintf("Incorrect 'role' returned, got '%s' expecting 'member'", role))
	}

	if function == "delete" {
		// Deletes an entity from its state
		return t.delete(stub, args)
	}

	if function == "query" {
		// queries an entity state
		return t.query(stub, args)
	}

	if function == "move" {
		// Deletes an entity from its state
		return t.move(stub, args)
	}

	Error.Printf("Unknown action, check the first argument, must be one of 'delete', 'query', or 'move'. But got: %v", args[0])
	return shim.Error(fmt.Sprintf("Unknown action, check the first argument, must be one of 'delete', 'query', or 'move'. But got: %v", args[0]))
}

2.3 idemixer的限制

还不大完善,基本现阶段还是推荐用传统的MSP方式,具体参考https://hyperledger-fabric.readthedocs.io/en/latest/idemix.html#current-limitations

零知识证明在以太坊是推崇的,它的应用场景实际蛮广的,fabric尚需努力,不过貌似2.0那么久还没release或者是推广得不好。不过区块链的前途是光明的,道路是曲折的,多了解下这些基础不是坏事。