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 }