github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/signature/suite/bbsblssignatureproof2020/signer_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package bbsblssignatureproof2020_test
     8  
     9  import (
    10  	_ "embed"
    11  	"encoding/base64"
    12  	"encoding/json"
    13  	"errors"
    14  	"testing"
    15  
    16  	"github.com/btcsuite/btcutil/base58"
    17  	"github.com/stretchr/testify/require"
    18  
    19  	"github.com/hyperledger/aries-framework-go/component/models/ld/testutil"
    20  	"github.com/hyperledger/aries-framework-go/component/models/signature/suite/bbsblssignatureproof2020"
    21  	"github.com/hyperledger/aries-framework-go/component/models/signature/verifier"
    22  
    23  	"github.com/hyperledger/aries-framework-go/pkg/doc/verifiable"
    24  )
    25  
    26  //nolint:gochecknoglobals
    27  var (
    28  	//go:embed testdata/case16_vc.jsonld
    29  	case16VC string // Case 16 (https://github.com/w3c-ccg/vc-http-api/pull/128)
    30  	//go:embed testdata/case16_reveal_doc.jsonld
    31  	case16RevealDoc string
    32  	//go:embed testdata/case18_vc.jsonld
    33  	case18VC string // Case 18 (https://github.com/w3c-ccg/vc-http-api/pull/128)
    34  	//go:embed testdata/case18_reveal_doc.jsonld
    35  	case18RevealDoc string
    36  	//go:embed testdata/doc_with_many_proofs.jsonld
    37  	docWithManyProofsJSON string //nolint:unused // re-enable test that uses this var (#2562)
    38  )
    39  
    40  // nolint
    41  func TestSuite_SelectiveDisclosure(t *testing.T) {
    42  	// pkBase58 from did:key:zUC724vuGvHpnCGFG1qqpXb81SiBLu3KLSqVzenwEZNPoY35i2Bscb8DLaVwHvRFs6F2NkNNXRcPWvqnPDUd9ukdjLkjZd3u9zzL4wDZDUpkPAatLDGLEYVo8kkAzuAKJQMr7N2
    43  	pkBase58 := "nEP2DEdbRaQ2r5Azeatui9MG6cj7JUHa8GD7khub4egHJREEuvj4Y8YG8w51LnhPEXxVV1ka93HpSLkVzeQuuPE1mH9oCMrqoHXAKGBsuDT1yJvj9cKgxxLCXiRRirCycki"
    44  	pubKeyBytes := base58.Decode(pkBase58)
    45  
    46  	nonce, err := base64.StdEncoding.DecodeString("G/hn9Ca9bIWZpJGlhnr/41r8RB0OO0TLChZASr3QJVztdri/JzS8Zf/xWJT5jW78zlM=")
    47  	require.NoError(t, err)
    48  
    49  	docMap := toMap(t, case16VC)
    50  	revealDocMap := toMap(t, case16RevealDoc)
    51  
    52  	s := bbsblssignatureproof2020.New()
    53  
    54  	const proofField = "proof"
    55  
    56  	pubKeyResolver := &testKeyResolver{
    57  		publicKey: &verifier.PublicKey{
    58  			Type:  "Bls12381G2Key2020",
    59  			Value: pubKeyBytes,
    60  		},
    61  	}
    62  
    63  	t.Run("single BBS+ signature", func(t *testing.T) {
    64  		docWithSelectiveDisclosure, err := s.SelectiveDisclosure(docMap, revealDocMap, nonce,
    65  			pubKeyResolver, testutil.WithDocumentLoader(t))
    66  		require.NoError(t, err)
    67  		require.NotEmpty(t, docWithSelectiveDisclosure)
    68  		require.Contains(t, docWithSelectiveDisclosure, proofField)
    69  
    70  		proofs, ok := docWithSelectiveDisclosure[proofField].([]map[string]interface{})
    71  		require.True(t, ok)
    72  
    73  		require.Len(t, proofs, 1)
    74  		require.Equal(t, "BbsBlsSignatureProof2020", proofs[0]["type"])
    75  		require.NotEmpty(t, proofs[0]["proofValue"])
    76  	})
    77  
    78  	t.Run("several proofs including BBS+ signature", func(t *testing.T) {
    79  		// TODO re-enable (#2562).
    80  		t.Skip()
    81  		docWithSeveralProofsMap := toMap(t, docWithManyProofsJSON)
    82  
    83  		pubKeyBytes2 := base58.Decode("tPTWWeUm8yT3aR9HtMvo2pLLvAdyV9Z4nJYZ2ZsyoLVpTupVb7NaRJ3tZePF6YsCN1nw7McqJ38tvpmQxKQxrTbyzjiewUDaj5jbD8gVfpfXJL2SfPBw4TGjYPA6zg6Jrxn")
    84  
    85  		compositeResolver := &testKeyResolver{
    86  			variants: map[string]*verifier.PublicKey{
    87  				"did:example:489398593#test": {
    88  					Type:  "Bls12381G2Key2020",
    89  					Value: pubKeyBytes},
    90  				"did:example:123456#key2": {
    91  					Type:  "Bls12381G2Key2020",
    92  					Value: pubKeyBytes2},
    93  			},
    94  		}
    95  
    96  		docWithSelectiveDisclosure, err := s.SelectiveDisclosure(docWithSeveralProofsMap, revealDocMap, nonce,
    97  			compositeResolver, testutil.WithDocumentLoader(t))
    98  		require.NoError(t, err)
    99  		require.NotEmpty(t, docWithSelectiveDisclosure)
   100  		require.Contains(t, docWithSelectiveDisclosure, proofField)
   101  
   102  		proofs, ok := docWithSelectiveDisclosure[proofField].([]map[string]interface{})
   103  		require.True(t, ok)
   104  
   105  		require.Len(t, proofs, 2)
   106  		require.Equal(t, "BbsBlsSignatureProof2020", proofs[0]["type"])
   107  		require.NotEmpty(t, proofs[0]["proofValue"])
   108  		require.Equal(t, "BbsBlsSignatureProof2020", proofs[1]["type"])
   109  		require.NotEmpty(t, proofs[1]["proofValue"])
   110  	})
   111  
   112  	t.Run("malformed input", func(t *testing.T) {
   113  		docMap := make(map[string]interface{})
   114  		docMap["@context"] = "http://localhost/nocontext"
   115  		docMap["bad"] = "example"
   116  		docMap["proof"] = "example"
   117  
   118  		_, err := s.SelectiveDisclosure(docMap, revealDocMap, nonce, pubKeyResolver, testutil.WithDocumentLoader(t))
   119  		require.Error(t, err)
   120  	})
   121  
   122  	t.Run("no proof", func(t *testing.T) {
   123  		docMapWithoutProof := make(map[string]interface{}, len(docMap)-1)
   124  
   125  		for k, v := range docMap {
   126  			if k != proofField {
   127  				docMapWithoutProof[k] = v
   128  			}
   129  		}
   130  
   131  		docWithSelectiveDisclosure, err := s.SelectiveDisclosure(docMapWithoutProof, revealDocMap, nonce,
   132  			pubKeyResolver, testutil.WithDocumentLoader(t))
   133  		require.Error(t, err)
   134  		require.Contains(t, err.Error(), "document does not have a proof")
   135  		require.Empty(t, docWithSelectiveDisclosure)
   136  	})
   137  
   138  	t.Run("invalid proof", func(t *testing.T) {
   139  		docMapWithInvalidProof := make(map[string]interface{}, len(docMap)-1)
   140  
   141  		for k, v := range docMap {
   142  			if k != proofField {
   143  				docMapWithInvalidProof[k] = v
   144  			} else {
   145  				docMapWithInvalidProof[k] = "invalid proof"
   146  			}
   147  		}
   148  
   149  		docWithSelectiveDisclosure, err := s.SelectiveDisclosure(docMapWithInvalidProof, revealDocMap, nonce,
   150  			pubKeyResolver, testutil.WithDocumentLoader(t))
   151  		require.Error(t, err)
   152  		require.EqualError(t, err, "get BLS proofs: read document proofs: proof is not map or array of maps")
   153  		require.Empty(t, docWithSelectiveDisclosure)
   154  	})
   155  
   156  	t.Run("invalid proof value", func(t *testing.T) {
   157  		docMapWithInvalidProofValue := make(map[string]interface{}, len(docMap))
   158  
   159  		for k, v := range docMap {
   160  			if k == proofField {
   161  				proofMap := make(map[string]interface{})
   162  
   163  				for k1, v1 := range v.(map[string]interface{}) {
   164  					if k1 == "proofValue" {
   165  						proofMap[k1] = "invalid"
   166  					} else {
   167  						proofMap[k1] = v1
   168  					}
   169  				}
   170  
   171  				docMapWithInvalidProofValue[proofField] = proofMap
   172  			} else {
   173  				docMapWithInvalidProofValue[k] = v
   174  			}
   175  		}
   176  
   177  		docWithSelectiveDisclosure, err := s.SelectiveDisclosure(docMapWithInvalidProofValue, revealDocMap, nonce,
   178  			pubKeyResolver, testutil.WithDocumentLoader(t))
   179  		require.Error(t, err)
   180  		require.EqualError(t, err, "generate signature proof: derive BBS+ proof: parse signature: invalid size of signature") //nolint:lll
   181  		require.Empty(t, docWithSelectiveDisclosure)
   182  	})
   183  
   184  	t.Run("invalid input BBS+ proof value", func(t *testing.T) {
   185  		docMapWithInvalidProofType := make(map[string]interface{}, len(docMap)-1)
   186  
   187  		for k, v := range docMap {
   188  			if k == proofField {
   189  				proofMap := make(map[string]interface{})
   190  
   191  				for k1, v1 := range v.(map[string]interface{}) {
   192  					if k1 == "type" {
   193  						proofMap[k1] = "invalid"
   194  					} else {
   195  						proofMap[k1] = v1
   196  					}
   197  				}
   198  
   199  				docMapWithInvalidProofType[proofField] = proofMap
   200  			} else {
   201  				docMapWithInvalidProofType[k] = v
   202  			}
   203  		}
   204  
   205  		docWithSelectiveDisclosure, err := s.SelectiveDisclosure(docMapWithInvalidProofType, revealDocMap, nonce,
   206  			pubKeyResolver, testutil.WithDocumentLoader(t))
   207  		require.Error(t, err)
   208  		require.EqualError(t, err, "no BbsBlsSignature2020 proof present")
   209  		require.Empty(t, docWithSelectiveDisclosure)
   210  	})
   211  
   212  	t.Run("failed to resolve public key", func(t *testing.T) {
   213  		failingPublicKeyResolver := &testKeyResolver{
   214  			err: errors.New("public key not found"),
   215  		}
   216  
   217  		docWithSelectiveDisclosure, err := s.SelectiveDisclosure(docMap, revealDocMap, nonce,
   218  			failingPublicKeyResolver, testutil.WithDocumentLoader(t))
   219  		require.Error(t, err)
   220  		require.EqualError(t, err, "generate signature proof: get public key and signature: resolve public key of BBS+ signature: public key not found") //nolint:lll
   221  		require.Empty(t, docWithSelectiveDisclosure)
   222  	})
   223  
   224  	t.Run("Case 18 derives into Case 19", func(t *testing.T) {
   225  		case18DocMap := toMap(t, case18VC)
   226  		case18RevealDocMap := toMap(t, case18RevealDoc)
   227  
   228  		case19Nonce, err := base64.StdEncoding.DecodeString("lEixQKDQvRecCifKl789TQj+Ii6YWDLSwn3AxR0VpPJ1QV5htod/0VCchVf1zVM0y2E=")
   229  		require.NoError(t, err)
   230  
   231  		docWithSelectiveDisclosure, err := s.SelectiveDisclosure(case18DocMap, case18RevealDocMap, case19Nonce,
   232  			pubKeyResolver, testutil.WithDocumentLoader(t))
   233  		require.NoError(t, err)
   234  		require.NotEmpty(t, docWithSelectiveDisclosure)
   235  		require.Contains(t, docWithSelectiveDisclosure, proofField)
   236  
   237  		proofs, ok := docWithSelectiveDisclosure[proofField].([]map[string]interface{})
   238  		require.True(t, ok)
   239  
   240  		require.Len(t, proofs, 1)
   241  		require.Equal(t, "BbsBlsSignatureProof2020", proofs[0]["type"])
   242  		require.NotEmpty(t, proofs[0]["proofValue"])
   243  
   244  		case18DerivationBytes, err := json.Marshal(docWithSelectiveDisclosure)
   245  
   246  		pubKeyFetcher := verifiable.SingleKey(pubKeyBytes, "Bls12381G2Key2020")
   247  
   248  		loader, err := testutil.DocumentLoader()
   249  		require.NoError(t, err)
   250  
   251  		_, err = verifiable.ParseCredential(case18DerivationBytes, verifiable.WithPublicKeyFetcher(pubKeyFetcher),
   252  			verifiable.WithJSONLDDocumentLoader(loader))
   253  		require.NoError(t, err)
   254  	})
   255  }
   256  
   257  func toMap(t *testing.T, doc string) map[string]interface{} {
   258  	var docMap map[string]interface{}
   259  	err := json.Unmarshal([]byte(doc), &docMap)
   260  	require.NoError(t, err)
   261  
   262  	return docMap
   263  }
   264  
   265  type testKeyResolver struct {
   266  	publicKey *verifier.PublicKey
   267  	variants  map[string]*verifier.PublicKey
   268  	err       error
   269  }
   270  
   271  func (r *testKeyResolver) Resolve(id string) (*verifier.PublicKey, error) {
   272  	if r.err != nil {
   273  		return nil, r.err
   274  	}
   275  
   276  	if len(r.variants) > 0 {
   277  		return r.variants[id], nil
   278  	}
   279  
   280  	return r.publicKey, r.err
   281  }