github.com/hyperledger/aries-framework-go@v0.3.2/test/bbs/src/main.go (about)

     1  // +build js,wasm
     2  
     3  /*
     4  Copyright SecureKey Technologies Inc. All Rights Reserved.
     5  
     6  SPDX-License-Identifier: Apache-2.0
     7  */
     8  
     9  package main
    10  
    11  //nolint:gci
    12  import (
    13  	_ "embed"
    14  	"encoding/base64"
    15  	"encoding/json"
    16  	"errors"
    17  	"fmt"
    18  	"syscall/js"
    19  
    20  	"github.com/btcsuite/btcutil/base58"
    21  	jsonld "github.com/piprate/json-gold/ld"
    22  
    23  	"github.com/hyperledger/aries-framework-go/component/storageutil/mem"
    24  	bbs "github.com/hyperledger/aries-framework-go/pkg/crypto/primitive/bbs12381g2pub"
    25  	"github.com/hyperledger/aries-framework-go/pkg/doc/ld"
    26  	"github.com/hyperledger/aries-framework-go/pkg/doc/ldcontext"
    27  	jsonldsig "github.com/hyperledger/aries-framework-go/pkg/doc/signature/jsonld"
    28  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite"
    29  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/bbsblssignature2020"
    30  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/bbsblssignatureproof2020"
    31  	"github.com/hyperledger/aries-framework-go/pkg/doc/verifiable"
    32  	ldstore "github.com/hyperledger/aries-framework-go/pkg/store/ld"
    33  )
    34  
    35  func main() {
    36  	js.Global().Set("signVCAsync", js.FuncOf(signVCJS))
    37  	js.Global().Set("verifyVCAsync", js.FuncOf(verifyVCJS))
    38  	js.Global().Set("deriveVCProofAsync", js.FuncOf(deriveVCProofJS))
    39  	js.Global().Set("verifyProofVCAsync", js.FuncOf(verifyProofVCJS))
    40  
    41  	select {}
    42  }
    43  
    44  func signVCJS(_ js.Value, args []js.Value) interface{} {
    45  	privKeyObj, vcObj, verificationMethodObj, callback := args[0], args[1], args[2], args[3]
    46  
    47  	go func(privKeyB64, vcJSON, verificationMethod string, callback js.Value) {
    48  		vcSigned, err := signVC(privKeyB64, vcJSON, verificationMethod)
    49  		if err != nil {
    50  			callback.Invoke(err.Error(), js.Null())
    51  		} else {
    52  			callback.Invoke(js.Null(), string(vcSigned))
    53  		}
    54  	}(privKeyObj.String(), vcObj.String(), verificationMethodObj.String(), callback)
    55  
    56  	return nil
    57  }
    58  
    59  func verifyVCJS(_ js.Value, args []js.Value) interface{} {
    60  	pubKeyObj, vcObj, callback := args[0], args[1], args[2]
    61  
    62  	go func(pubKeyB64, vcJSON string, callback js.Value) {
    63  		err := verifyVC(pubKeyB64, vcJSON)
    64  		if err != nil {
    65  			callback.Invoke(err.Error())
    66  		} else {
    67  			callback.Invoke(js.Null())
    68  		}
    69  	}(pubKeyObj.String(), vcObj.String(), callback)
    70  
    71  	return nil
    72  }
    73  
    74  func deriveVCProofJS(_ js.Value, args []js.Value) interface{} {
    75  	pubKeyObj, vcObj, revealJSON, nonce, callback := args[0], args[1], args[2], args[3], args[4]
    76  
    77  	go func(pubKeyB64, vcJSON, revealJSON, nonce string, callback js.Value) {
    78  		vcSigned, err := deriveProofVC(pubKeyB64, vcJSON, revealJSON, nonce)
    79  		if err != nil {
    80  			callback.Invoke(err.Error(), js.Null())
    81  		} else {
    82  			callback.Invoke(js.Null(), string(vcSigned))
    83  		}
    84  	}(pubKeyObj.String(), vcObj.String(), revealJSON.String(), nonce.String(), callback)
    85  
    86  	return nil
    87  }
    88  
    89  func verifyProofVCJS(_ js.Value, args []js.Value) interface{} {
    90  	pubKeyObj, vcObj, callback := args[0], args[1], args[2]
    91  
    92  	go func(pubKeyB64, vcJSON string, callback js.Value) {
    93  		err := verifyProofVC(pubKeyB64, vcJSON)
    94  		if err != nil {
    95  			callback.Invoke(err.Error())
    96  		} else {
    97  			callback.Invoke(js.Null())
    98  		}
    99  	}(pubKeyObj.String(), vcObj.String(), callback)
   100  
   101  	return nil
   102  }
   103  
   104  func signVC(privKeyB64, vcJSON, verificationMethod string) ([]byte, error) {
   105  	privKeyBytes := base58.Decode(privKeyB64)
   106  
   107  	privKey, err := bbs.UnmarshalPrivateKey(privKeyBytes)
   108  	if err != nil {
   109  		return nil, errors.New("invalid private key")
   110  	}
   111  
   112  	signer, err := newBBSSigner(privKey)
   113  	if err != nil {
   114  		return nil, fmt.Errorf("create BBS signer: %w", err)
   115  	}
   116  
   117  	sigSuite := bbsblssignature2020.New(suite.WithSigner(signer))
   118  
   119  	ldpContext := &verifiable.LinkedDataProofContext{
   120  		SignatureType:           "BbsBlsSignature2020",
   121  		SignatureRepresentation: verifiable.SignatureProofValue,
   122  		Suite:                   sigSuite,
   123  		VerificationMethod:      verificationMethod,
   124  	}
   125  
   126  	jsonldDocLoader, err := createJSONLDDocumentLoader()
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  
   131  	vc, err := verifiable.ParseCredential([]byte(vcJSON), verifiable.WithJSONLDDocumentLoader(jsonldDocLoader),
   132  		verifiable.WithDisabledProofCheck())
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	err = vc.AddLinkedDataProof(ldpContext, jsonldsig.WithDocumentLoader(jsonldDocLoader))
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  
   142  	vcWithProof, err := json.Marshal(vc)
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  
   147  	return vcWithProof, nil
   148  }
   149  
   150  func verifyVC(pubKeyB64, vcJSON string) error {
   151  	pubKeyBytes := base58.Decode(pubKeyB64)
   152  
   153  	sigSuite := bbsblssignature2020.New(
   154  		suite.WithVerifier(bbsblssignature2020.NewG2PublicKeyVerifier()))
   155  
   156  	documentLoader, err := createJSONLDDocumentLoader()
   157  	if err != nil {
   158  		return err
   159  	}
   160  
   161  	_, err = verifiable.ParseCredential([]byte(vcJSON),
   162  		verifiable.WithJSONLDDocumentLoader(documentLoader),
   163  		verifiable.WithEmbeddedSignatureSuites(sigSuite),
   164  		verifiable.WithPublicKeyFetcher(verifiable.SingleKey(pubKeyBytes, "Bls12381G2Key2020")),
   165  	)
   166  
   167  	return err
   168  }
   169  
   170  func verifyProofVC(pubKeyB64, vcJSON string) error {
   171  	pubKeyBytes := base58.Decode(pubKeyB64)
   172  
   173  	var vcDoc map[string]interface{}
   174  
   175  	err := json.Unmarshal([]byte(vcJSON), &vcDoc)
   176  	if err != nil {
   177  		return fmt.Errorf("parse VC doc: %w", err)
   178  	}
   179  
   180  	proof, ok := vcDoc["proof"].(map[string]interface{})
   181  	if !ok {
   182  		return fmt.Errorf("unexpected \"proof\" format: %w", err)
   183  	}
   184  
   185  	nonce, ok := proof["nonce"].(string)
   186  	if !ok {
   187  		return fmt.Errorf("unexpected \"nonce\" format: %w", err)
   188  	}
   189  
   190  	nonceBytes, err := base64.StdEncoding.DecodeString(nonce)
   191  	if err != nil {
   192  		return fmt.Errorf("nonce base64 format: %w", err)
   193  	}
   194  
   195  	sigSuite := bbsblssignatureproof2020.New(
   196  		suite.WithCompactProof(),
   197  		suite.WithVerifier(bbsblssignatureproof2020.NewG2PublicKeyVerifier(nonceBytes)))
   198  
   199  	jsonldDocLoader, err := createJSONLDDocumentLoader()
   200  	if err != nil {
   201  		return err
   202  	}
   203  
   204  	_, err = verifiable.ParseCredential([]byte(vcJSON),
   205  		verifiable.WithJSONLDDocumentLoader(jsonldDocLoader),
   206  		verifiable.WithEmbeddedSignatureSuites(sigSuite),
   207  		verifiable.WithPublicKeyFetcher(verifiable.SingleKey(pubKeyBytes, "Bls12381G2Key2020")),
   208  	)
   209  
   210  	return err
   211  }
   212  
   213  func deriveProofVC(pubKeyB64, vcJSON, revealJSON, nonce string) ([]byte, error) {
   214  	pubKeyBytes := base58.Decode(pubKeyB64)
   215  
   216  	nonceBytes, err := base64.StdEncoding.DecodeString(nonce)
   217  	if err != nil {
   218  		return nil, err
   219  	}
   220  
   221  	jsonldLoader, err := createJSONLDDocumentLoader()
   222  	if err != nil {
   223  		return nil, err
   224  	}
   225  
   226  	vc, err := verifiable.ParseCredential([]byte(vcJSON), verifiable.WithJSONLDDocumentLoader(jsonldLoader),
   227  		verifiable.WithDisabledProofCheck())
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  
   232  	var revealDoc map[string]interface{}
   233  
   234  	err = json.Unmarshal([]byte(revealJSON), &revealDoc)
   235  	if err != nil {
   236  		return nil, fmt.Errorf("unmarshal reveal doc: %w", err)
   237  	}
   238  
   239  	vcSD, err := vc.GenerateBBSSelectiveDisclosure(revealDoc, nonceBytes,
   240  		verifiable.WithJSONLDDocumentLoader(jsonldLoader),
   241  		verifiable.WithPublicKeyFetcher(verifiable.SingleKey(pubKeyBytes, "Bls12381G2Key2020")))
   242  	if err != nil {
   243  		return nil, fmt.Errorf("create selective disclosure: %w", err)
   244  	}
   245  
   246  	vcSDBytes, err := json.Marshal(vcSD)
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  
   251  	return vcSDBytes, nil
   252  }
   253  
   254  // nolint:gochecknoglobals // embedded custom context
   255  var (
   256  	//go:embed contexts/citizenship_v1.jsonld
   257  	citizenshipVocab []byte
   258  	//go:embed contexts/credentials-examples_v1.jsonld
   259  	credentialExamplesVocab []byte
   260  	//go:embed contexts/odrl.jsonld
   261  	odrlVocab []byte
   262  )
   263  
   264  type provider struct {
   265  	ContextStore        ldstore.ContextStore
   266  	RemoteProviderStore ldstore.RemoteProviderStore
   267  }
   268  
   269  func (p *provider) JSONLDContextStore() ldstore.ContextStore {
   270  	return p.ContextStore
   271  }
   272  
   273  func (p *provider) JSONLDRemoteProviderStore() ldstore.RemoteProviderStore {
   274  	return p.RemoteProviderStore
   275  }
   276  
   277  func createJSONLDDocumentLoader() (jsonld.DocumentLoader, error) {
   278  	contextStore, err := ldstore.NewContextStore(mem.NewProvider())
   279  	if err != nil {
   280  		return nil, fmt.Errorf("create JSON-LD context store: %w", err)
   281  	}
   282  
   283  	remoteProviderStore, err := ldstore.NewRemoteProviderStore(mem.NewProvider())
   284  	if err != nil {
   285  		return nil, fmt.Errorf("create remote provider store: %w", err)
   286  	}
   287  
   288  	p := &provider{
   289  		ContextStore:        contextStore,
   290  		RemoteProviderStore: remoteProviderStore,
   291  	}
   292  
   293  	loader, err := ld.NewDocumentLoader(p,
   294  		ld.WithExtraContexts(
   295  			ldcontext.Document{
   296  				URL:         "https://w3id.org/citizenship/v1",
   297  				DocumentURL: "https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v1.jsonld",
   298  				Content:     citizenshipVocab,
   299  			},
   300  			ldcontext.Document{
   301  				URL:     "https://www.w3.org/2018/credentials/examples/v1",
   302  				Content: credentialExamplesVocab,
   303  			},
   304  			ldcontext.Document{
   305  				URL:     "https://www.w3.org/ns/odrl.jsonld",
   306  				Content: odrlVocab,
   307  			},
   308  		),
   309  	)
   310  	if err != nil {
   311  		return nil, fmt.Errorf("create document loader: %w", err)
   312  	}
   313  
   314  	return loader, nil
   315  }