Skip to content

Commit 41f6e6e

Browse files
committed
feat: add data integrity proof
Signed-off-by: Misha Sizov <[email protected]>
1 parent 6f83cdc commit 41f6e6e

File tree

8 files changed

+303
-63
lines changed

8 files changed

+303
-63
lines changed

doc/did/doc.go

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"github.com/xeipuuv/gojsonschema"
2626

2727
"github.com/trustbloc/did-go/doc/did/endpoint"
28-
"github.com/trustbloc/did-go/doc/ld/processor"
2928
sigproof "github.com/trustbloc/did-go/doc/ld/proof"
3029
"github.com/trustbloc/did-go/doc/signature/api"
3130
"github.com/trustbloc/did-go/doc/signature/verifier"
@@ -48,13 +47,16 @@ const (
4847
jsonldController = "controller"
4948
jsonldOwner = "owner"
5049

51-
jsonldCreator = "creator"
52-
jsonldCreated = "created"
53-
jsonldProofValue = "proofValue"
54-
jsonldSignatureValue = "signatureValue"
55-
jsonldDomain = "domain"
56-
jsonldNonce = "nonce"
57-
jsonldProofPurpose = "proofPurpose"
50+
jsonldCreator = "creator"
51+
jsonldCreated = "created"
52+
jsonldProofValue = "proofValue"
53+
jsonldSignatureValue = "signatureValue"
54+
jsonldDomain = "domain"
55+
jsonldNonce = "nonce"
56+
jsonldProofPurpose = "proofPurpose"
57+
jsonldChallenge = "challenge"
58+
jsonldCryptoSuite = "cryptosuite"
59+
jsonldVerificationMethod = "verificationMethod"
5860

5961
// various public key encodings.
6062
jsonldPublicKeyBase58 = "publicKeyBase58"
@@ -487,14 +489,17 @@ func (r *rawDoc) UnmarshalJSON(data []byte) error {
487489

488490
// Proof is cryptographic proof of the integrity of the DID Document.
489491
type Proof struct {
490-
Type string
491-
Created *time.Time
492-
Creator string
493-
ProofValue []byte
494-
Domain string
495-
Nonce []byte
496-
ProofPurpose string
497-
relativeURL bool
492+
Type string
493+
Created *time.Time
494+
Creator string
495+
ProofValue []byte
496+
Domain string
497+
Nonce []byte
498+
ProofPurpose string
499+
CryptoSuite string
500+
Challenge string
501+
VerificationMethod string
502+
relativeURL bool
498503
}
499504

500505
// UnmarshalJSON unmarshals a DID Document.
@@ -659,13 +664,16 @@ func populateProofs(context, didID, baseURI string, rawProofs []interface{}) ([]
659664
}
660665

661666
proof := Proof{
662-
Type: stringEntry(emap[jsonldType]),
663-
Creator: creator,
664-
ProofValue: proofValue,
665-
ProofPurpose: stringEntry(emap[jsonldProofPurpose]),
666-
Domain: stringEntry(emap[jsonldDomain]),
667-
Nonce: nonce,
668-
relativeURL: isRelative,
667+
Type: stringEntry(emap[jsonldType]),
668+
Creator: creator,
669+
ProofValue: proofValue,
670+
ProofPurpose: stringEntry(emap[jsonldProofPurpose]),
671+
Domain: stringEntry(emap[jsonldDomain]),
672+
VerificationMethod: stringEntry(emap[jsonldVerificationMethod]),
673+
CryptoSuite: stringEntry(emap[jsonldCryptoSuite]),
674+
Challenge: stringEntry(emap[jsonldChallenge]),
675+
Nonce: nonce,
676+
relativeURL: isRelative,
669677
}
670678

671679
created := stringEntry(emap[jsonldCreated])
@@ -1246,7 +1254,7 @@ func (doc *Doc) MarshalJSON() ([]byte, error) {
12461254
}
12471255

12481256
// VerifyProof verifies document proofs.
1249-
func (doc *Doc) VerifyProof(suites []api.VerifierSuite, jsonldOpts ...processor.Opts) error {
1257+
func (doc *Doc) VerifyProof(suites []api.VerifierSuite, opts ...verifier.Opts) error {
12501258
if len(doc.Proof) == 0 {
12511259
return ErrProofNotFound
12521260
}
@@ -1261,7 +1269,7 @@ func (doc *Doc) VerifyProof(suites []api.VerifierSuite, jsonldOpts ...processor.
12611269
return fmt.Errorf("create verifier: %w", err)
12621270
}
12631271

1264-
return v.Verify(docBytes, jsonldOpts...)
1272+
return v.Verify(docBytes, opts...)
12651273
}
12661274

12671275
// VerificationMethods returns verification methods of DID Doc of certain relationship.
@@ -1565,13 +1573,16 @@ func populateRawProofs(context, didID, baseURI string, proofs []Proof) []interfa
15651573
}
15661574

15671575
rawProofs = append(rawProofs, map[string]interface{}{
1568-
jsonldType: p.Type,
1569-
jsonldCreated: p.Created,
1570-
jsonldCreator: creator,
1571-
k: sigproof.EncodeProofValue(p.ProofValue, p.Type),
1572-
jsonldDomain: p.Domain,
1573-
jsonldNonce: base64.RawURLEncoding.EncodeToString(p.Nonce),
1574-
jsonldProofPurpose: p.ProofPurpose,
1576+
jsonldType: p.Type,
1577+
jsonldCreated: p.Created,
1578+
jsonldCreator: creator,
1579+
k: sigproof.EncodeProofValue(p.ProofValue, p.Type),
1580+
jsonldDomain: p.Domain,
1581+
jsonldNonce: base64.RawURLEncoding.EncodeToString(p.Nonce),
1582+
jsonldProofPurpose: p.ProofPurpose,
1583+
jsonldVerificationMethod: p.VerificationMethod,
1584+
jsonldCryptoSuite: p.CryptoSuite,
1585+
jsonldChallenge: p.Challenge,
15751586
})
15761587
}
15771588

doc/did/doc_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"encoding/pem"
1717
"errors"
1818
"fmt"
19+
"github.com/trustbloc/did-go/doc/signature/verifier"
1920
"testing"
2021
"time"
2122

@@ -1388,12 +1389,12 @@ func TestVerifyProof(t *testing.T) {
13881389
require.NotNil(t, doc)
13891390
err = doc.VerifyProof(
13901391
[]api.VerifierSuite{&signature.MockVerifierSuite{MockSuite: signature.MockSuite{AcceptVal: true}}},
1391-
testutil.WithDocumentLoader(t),
1392+
verifier.WithProcessorOpts(testutil.WithDocumentLoader(t)),
13921393
)
13931394
require.NoError(t, err)
13941395

13951396
// error - no suites are passed, verifier is not created
1396-
err = doc.VerifyProof([]api.VerifierSuite{}, testutil.WithDocumentLoader(t))
1397+
err = doc.VerifyProof([]api.VerifierSuite{}, verifier.WithProcessorOpts(testutil.WithDocumentLoader(t)))
13971398
require.Error(t, err)
13981399
require.Contains(t, err.Error(), "create verifier")
13991400

@@ -1404,7 +1405,7 @@ func TestVerifyProof(t *testing.T) {
14041405
MockSuite: signature.MockSuite{AcceptVal: true},
14051406
VerifyErr: errors.New("ed25519: invalid signature"),
14061407
}},
1407-
testutil.WithDocumentLoader(t),
1408+
verifier.WithProcessorOpts(testutil.WithDocumentLoader(t)),
14081409
)
14091410
require.NotNil(t, err)
14101411
require.Contains(t, err.Error(), "ed25519: invalid signature")
@@ -1415,7 +1416,7 @@ func TestVerifyProof(t *testing.T) {
14151416
require.NotNil(t, doc)
14161417
err = doc.VerifyProof(
14171418
[]api.VerifierSuite{&signature.MockVerifierSuite{MockSuite: signature.MockSuite{AcceptVal: true}}},
1418-
testutil.WithDocumentLoader(t),
1419+
verifier.WithProcessorOpts(testutil.WithDocumentLoader(t)),
14191420
)
14201421
require.Equal(t, ErrProofNotFound, err)
14211422
require.Contains(t, err.Error(), "proof not found")

doc/ld/proof/proof.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ const (
3939
jsonldChallenge = "challenge"
4040
// jsonldCapabilityChain is a key for capabilityChain.
4141
jsonldCapabilityChain = "capabilityChain"
42+
// jsonldCryptoSuite is a key for cryptosuite.
43+
jsonldCryptoSuite = "cryptosuite"
4244

4345
ed25519Signature2020 = "Ed25519Signature2020"
4446
)
@@ -58,6 +60,9 @@ type Proof struct {
5860
SignatureRepresentation SignatureRepresentation
5961
// CapabilityChain must be an array. Each element is either a string or an object.
6062
CapabilityChain []interface{}
63+
CryptoSuite string // Data integrity proof model field.
64+
//ID string // Data integrity proof model field. Not in use.
65+
//PreviousProof string // Data integrity proof model field. Not in use.
6166
}
6267

6368
// NewProof creates new proof.
@@ -113,6 +118,7 @@ func NewProof(emap map[string]interface{}) (*Proof, error) {
113118
Domain: stringEntry(emap[jsonldDomain]),
114119
Nonce: nonce,
115120
Challenge: stringEntry(emap[jsonldChallenge]),
121+
CryptoSuite: stringEntry(emap[jsonldCryptoSuite]),
116122
CapabilityChain: capabilityChain,
117123
}, nil
118124
}
@@ -227,6 +233,10 @@ func (p *Proof) JSONLdObject() map[string]interface{} { // nolint:gocyclo
227233
emap[jsonldCapabilityChain] = p.CapabilityChain
228234
}
229235

236+
if p.CryptoSuite != "" {
237+
emap[jsonldCryptoSuite] = p.CryptoSuite
238+
}
239+
230240
return emap
231241
}
232242

doc/ld/proof/proof_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func TestProof(t *testing.T) {
3030
"domain": "abc.com",
3131
"nonce": "",
3232
"proofValue": proofValueBase64,
33+
"cryptosuite": "ecdsa-rdfc-2019",
3334
})
3435
require.NoError(t, err)
3536

@@ -47,6 +48,7 @@ func TestProof(t *testing.T) {
4748
require.Equal(t, "abc.com", p.Domain)
4849
require.Equal(t, []byte(""), p.Nonce)
4950
require.Equal(t, proofValueBytes, p.ProofValue)
51+
require.Equal(t, "ecdsa-rdfc-2019", p.CryptoSuite)
5052

5153
// test proof with multibase encoding
5254
p, err = NewProof(map[string]interface{}{
@@ -57,6 +59,7 @@ func TestProof(t *testing.T) {
5759
"domain": "abc.com",
5860
"nonce": "",
5961
"proofValue": proofValueMultibase,
62+
"cryptosuite": "eddsa-rdfc-2022",
6063
})
6164
require.NoError(t, err)
6265

@@ -74,6 +77,7 @@ func TestProof(t *testing.T) {
7477
require.Equal(t, "abc.com", p.Domain)
7578
require.Equal(t, []byte(""), p.Nonce)
7679
require.Equal(t, proofValueBytes, p.ProofValue)
80+
require.Equal(t, "eddsa-rdfc-2022", p.CryptoSuite)
7781

7882
// test created time with milliseconds section
7983
p, err = NewProof(map[string]interface{}{
@@ -391,6 +395,7 @@ func TestProof_JSONLdObject(t *testing.T) {
391395
Domain: "internal",
392396
Nonce: nonceBase64,
393397
Challenge: "sample-challenge-xyz",
398+
CryptoSuite: "eddsa-rdfc-2022",
394399
}
395400

396401
pJSONLd := p.JSONLdObject()
@@ -403,6 +408,7 @@ func TestProof_JSONLdObject(t *testing.T) {
403408
r.Equal("internal", pJSONLd["domain"])
404409
r.Equal("abc", pJSONLd["nonce"])
405410
r.Equal("sample-challenge-xyz", pJSONLd["challenge"])
411+
r.Equal("eddsa-rdfc-2022", pJSONLd["cryptosuite"])
406412

407413
// test created time with milliseconds section
408414
created, err = time.Parse(time.RFC3339Nano, "2018-03-15T00:00:00.972Z")

doc/signature/api/api.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/trustbloc/kms-go/doc/jose/jwk"
1414

1515
"github.com/trustbloc/did-go/doc/ld/processor"
16+
"github.com/trustbloc/did-go/doc/signature/verifier"
1617
)
1718

1819
// Context holds signing options and private key.
@@ -38,9 +39,9 @@ type Signer interface {
3839
// Verifier wraps a set of VerifierSuite instances and verifies proofs on json LD documents.
3940
type Verifier interface {
4041
// Verify verifies a json LD proof on a document.
41-
Verify(jsonLdDoc []byte, opts ...processor.Opts) error
42+
Verify(jsonLdDoc []byte, opts ...verifier.Opts) error
4243
// VerifyObject verifies a json LD proof on a document unmarshalled following json.Unmarshal conventions.
43-
VerifyObject(jsonLdObject map[string]interface{}, opts ...processor.Opts) error
44+
VerifyObject(jsonLdObject map[string]interface{}, opts ...verifier.Opts) error
4445
}
4546

4647
// SignatureSuite provides common methods for signature suites.

doc/signature/signer/dataintegrity.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
Copyright SecureKey Technologies Inc. All Rights Reserved.
3+
SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package signer
7+
8+
//
9+
//import (
10+
// "encoding/json"
11+
// "fmt"
12+
// "time"
13+
//
14+
// "github.com/trustbloc/vc-go/dataintegrity"
15+
// "github.com/trustbloc/vc-go/dataintegrity/models"
16+
//
17+
// "github.com/trustbloc/did-go/doc/ld/proof"
18+
//)
19+
//
20+
//// DataIntegrityProofContext holds parameters for creating a Data Integrity Proof.
21+
//type DataIntegrityProofContext struct {
22+
// SigningKeyID string // eg did:foo:bar#key-1
23+
// ProofPurpose string // assertionMethod
24+
// CryptoSuite string // ecdsa-2019
25+
// Created *time.Time //
26+
// Domain string //
27+
// Challenge string //
28+
//}
29+
//
30+
//// AddDataIntegrityProof adds a Data Integrity Proof to the document.
31+
//func (signer *DocumentSigner) AddDataIntegrityProof(
32+
// doc []byte,
33+
// context *DataIntegrityProofContext,
34+
// diSigner *dataintegrity.Signer,
35+
//) ([]byte, error) {
36+
// var jsonLdObject map[string]interface{}
37+
//
38+
// err := json.Unmarshal(doc, &jsonLdObject)
39+
// if err != nil {
40+
// return nil, fmt.Errorf("failed to unmarshal json ld document: %w", err)
41+
// }
42+
//
43+
// // TODO: rewrite to use json object instead bytes presentation
44+
// diProof, err := createDataIntegrityProof(context, doc, diSigner)
45+
// if err != nil {
46+
// return nil, fmt.Errorf("create data integrity proof: %w", err)
47+
// }
48+
//
49+
// if err = proof.AddProof(jsonLdObject, diProof); err != nil {
50+
// return nil, fmt.Errorf("add data integrity proof: %w", err)
51+
// }
52+
//
53+
// signedDoc, err := json.Marshal(jsonLdObject)
54+
// if err != nil {
55+
// return nil, err
56+
// }
57+
//
58+
// return signedDoc, nil
59+
//}
60+
//
61+
//func createDataIntegrityProof(
62+
// context *DataIntegrityProofContext,
63+
// ldBytes []byte,
64+
// signer *dataintegrity.Signer,
65+
//) (*proof.Proof, error) {
66+
// var createdTime time.Time
67+
// if context.Created == nil {
68+
// createdTime = time.Now()
69+
// } else {
70+
// createdTime = *context.Created
71+
// }
72+
//
73+
// if context.ProofPurpose == "" {
74+
// context.ProofPurpose = defaultProofPurpose
75+
// }
76+
//
77+
// signed, err := signer.AddProof(ldBytes, &models.ProofOptions{
78+
// Purpose: context.ProofPurpose,
79+
// VerificationMethodID: context.SigningKeyID,
80+
// ProofType: models.DataIntegrityProof,
81+
// SuiteType: context.CryptoSuite,
82+
// Domain: context.Domain,
83+
// Challenge: context.Challenge,
84+
// Created: createdTime,
85+
// })
86+
// if err != nil {
87+
// return nil, fmt.Errorf("add proof: %w", err)
88+
// }
89+
//
90+
// type rawProof struct {
91+
// Proof map[string]interface{} `json:"proof,omitempty"`
92+
// }
93+
//
94+
// // Get a proof from json-ld document.
95+
// var rProof rawProof
96+
//
97+
// err = json.Unmarshal(signed, &rProof)
98+
// if err != nil {
99+
// return nil, err
100+
// }
101+
//
102+
// diProof, err := proof.NewProof(rProof.Proof)
103+
// if err != nil {
104+
// return nil, fmt.Errorf("new proof: %w", err)
105+
// }
106+
//
107+
// return diProof, nil
108+
//}

0 commit comments

Comments
 (0)