Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bjj signature fix #393

Merged
merged 14 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The Hypersign Identity Network is a permissionless blockchain network to manage
- Stake `$HID` tokens
- Submit Governance Proposals
- Transfer `$HID` tokens within and across different Tendermint-based blockchains using IBC
- Deploy CosmWasm Smart Contracts (Governance Based)
- Deploy CosmWasm Smart Contracts

## Prerequisite

Expand Down
2 changes: 1 addition & 1 deletion cmd/hid-noded/cmd/debug_extensions_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func getDocumentSignature(doc types.SsiMsg, docProof *types.DocumentProof, priva
}
case types.BJJSignature2021:
var docBytes []byte
docBytes, err := ldcontext.BJJSignature2021Normalize(doc)
docBytes, err := ldcontext.BJJSignature2021Normalize(doc, docProof)
if err != nil {
return "", err
}
Expand Down
117 changes: 117 additions & 0 deletions x/ssi/ld-context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const X25519KeyAgreementKeyEIP5630Context string = "https://raw.githubuserconten
const CredentialStatusContext string = "https://raw.githubusercontent.com/hypersign-protocol/hypersign-contexts/main/CredentialStatus.jsonld"
const CredentialSchemaContext string = "https://raw.githubusercontent.com/hypersign-protocol/hypersign-contexts/main/CredentialSchema.jsonld"
const BabyJubJubKey2021Context string = "https://raw.githubusercontent.com/hypersign-protocol/hypersign-contexts/main/BabyJubJubKey2021.jsonld"
const BJJSignature2021Context string = "https://raw.githubusercontent.com/hypersign-protocol/hypersign-contexts/main/BJJSignature2021.jsonld"
const LinkedDomainsContext string = "https://raw.githubusercontent.com/hypersign-protocol/hypersign-contexts/main/LinkedDomains.jsonld"

// As hid-node is not supposed to perform any GET request, the complete Context body of their
// respective Context urls has been maintained below.
Expand Down Expand Up @@ -745,4 +747,119 @@ var ContextUrlMap map[string]contextObject = map[string]contextObject{
},
},
},

BJJSignature2021Context: {
"@version": 1.1,
"id": "@id",
"type": "@type",
"proof": map[string]interface{}{
"@id": "https://w3id.org/security#proof",
"@type": "@id",
"@container": "@graph",
},
"BJJSignature2021": map[string]interface{}{
"@id": "https://w3id.org/security#BJJSignature2021",
"@context": map[string]interface{}{
"@version": 1.1,
"@protected": true,
"id": "@id",
"type": "@type",
"challenge": "https://w3id.org/security#challenge",
"created": map[string]interface{}{
"@id": "http://purl.org/dc/terms/created",
"@type": "http://www.w3.org/2001/XMLSchema#dateTime",
},
"domain": "https://w3id.org/security#domain",
"proofValue": "https://w3id.org/security#proofValue",
"credentialRoot": "https://w3id.org/security#credentialRoot",
"nonce": "https://w3id.org/security#nonce",
"proofPurpose": map[string]interface{}{
"@id": "https://w3id.org/security#proofPurpose",
"@type": "@vocab",
"@context": map[string]interface{}{
"@version": 1.1,
"@protected": true,
"id": "@id",
"type": "@type",
"assertionMethod": map[string]interface{}{
"@id": "https://w3id.org/security#assertionMethod",
"@type": "@id",
"@container": "@set",
},
"authentication": map[string]interface{}{
"@id": "https://w3id.org/security#authenticationMethod",
"@type": "@id",
"@container": "@set",
},
},
},
"verificationMethod": map[string]interface{}{
"@id": "https://w3id.org/security#verificationMethod",
"@type": "@id",
},
},
},
"BabyJubJubSignatureProof2021": map[string]interface{}{
"@id": "https://w3id.org/security#BabyJubJubSignatureProof2021",
"@context": map[string]interface{}{
"@version": 1.1,
"@protected": true,
"id": "@id",
"type": "@type",
"challenge": "https://w3id.org/security#challenge",
"created": map[string]interface{}{
"@id": "http://purl.org/dc/terms/created",
"@type": "http://www.w3.org/2001/XMLSchema#dateTime",
},
"domain": "https://w3id.org/security#domain",
"nonce": "https://w3id.org/security#nonce",
"proofPurpose": map[string]interface{}{
"@id": "https://w3id.org/security#proofPurpose",
"@type": "@vocab",
"@context": map[string]interface{}{
"@version": 1.1,
"@protected": true,
"id": "@id",
"type": "@type",
"sec": "https://w3id.org/security#",
"assertionMethod": map[string]interface{}{
"@id": "https://w3id.org/security#assertionMethod",
"@type": "@id",
"@container": "@set",
},
"authentication": map[string]interface{}{
"@id": "https://w3id.org/security#authenticationMethod",
"@type": "@id",
"@container": "@set",
},
},
},
"proofValue": "https://w3id.org/security#proofValue",
"credentialRoot": "https://w3id.org/security#credentialRoot",
"verificationMethod": map[string]interface{}{
"@id": "https://w3id.org/security#verificationMethod",
"@type": "@id",
},
},
},
},
LinkedDomainsContext: {

"@protected": true,
"id": "@id",
"type": "@type",
"LinkedDomains": map[string]interface{}{
"@id": "https://www.w3.org/ns/did#LinkedDomains",
"@type": "@id",
"@context": map[string]interface{}{
"@protected": true,
"id": "@id",
"type": "@type",
"serviceEndpoint": map[string]interface{}{
"@id": "https://www.w3.org/ns/did#serviceEndpoint",
"@type": "@id",
},
},
},
},
}
10 changes: 6 additions & 4 deletions x/ssi/ld-context/cryptosuite.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,23 +129,25 @@ func EcdsaSecp256k1Signature2019Normalize(ssiMsg types.SsiMsg, docProof *types.D

// BJJSignature2021Normalize performs canonization of SSI documents
// based on the spec: https://iden3-communication.io/BJJSignature2021/
func BJJSignature2021Normalize(ssiMsg types.SsiMsg) ([]byte, error) {
func BJJSignature2021Normalize(ssiMsg types.SsiMsg, docProof *types.DocumentProof) ([]byte, error) {
var jsonLDString string
switch doc := ssiMsg.(type) {
case *types.DidDocument:
jsonLDBytes, err := json.Marshal(NewJsonLdDidDocumentWithoutVM(doc))
jsonLDBytes, err := json.Marshal(NewJsonLdDidDocumentWithoutVM(doc, docProof))
if err != nil {
return nil, err
}
jsonLDString = string(jsonLDBytes)
case *types.CredentialSchemaDocument:
jsonLDBytes, err := json.Marshal(NewJsonLdCredentialSchema(doc))
credentialSchemaDocument := NewJsonLdCredentialSchemaBJJ(doc, docProof)
jsonLDBytes, err := json.Marshal(credentialSchemaDocument)
if err != nil {
return nil, err
}
jsonLDString = string(jsonLDBytes)
case *types.CredentialStatusDocument:
jsonLDBytes, err := json.Marshal(NewJsonLdCredentialStatus(doc))
credentialStatusDocument := NewJsonLdCredentialStatusBJJ(doc, docProof)
jsonLDBytes, err := json.Marshal(credentialStatusDocument)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion x/ssi/ld-context/normalize.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func NormalizeByProofType(ssiMsg types.SsiMsg, didDocumentProof *types.DocumentP
}
return msgBytes, nil
case types.BJJSignature2021:
msgBytes, err := BJJSignature2021Normalize(ssiMsg)
msgBytes, err := BJJSignature2021Normalize(ssiMsg, didDocumentProof)
if err != nil {
return nil, err
}
Expand Down
138 changes: 129 additions & 9 deletions x/ssi/ld-context/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,22 @@ func (doc *JsonLdCredentialStatus) GetContext() []contextObject {
return doc.Context
}

type JsonLdCredentialStatusBJJ struct {
Context []contextObject `json:"@context,omitempty"`
Id string `json:"id,omitempty"`
Revoked bool `json:"revoked,omitempty"`
Suspended bool `json:"suspended,omitempty"`
Remarks string `json:"remarks,omitempty"`
Issuer string `json:"issuer,omitempty"`
IssuanceDate string `json:"issuanceDate,omitempty"`
CredentialMerkleRootHash string `json:"credentialMerkleRootHash,omitempty"`
Proof JsonLdDocumentProof `json:"proof,omitempty"`
}

func (doc *JsonLdCredentialStatusBJJ) GetContext() []contextObject {
return doc.Context
}

// NewJsonLdCredentialStatus returns a new JsonLdCredentialStatus struct from input Credential Status
func NewJsonLdCredentialStatus(credStatusDoc *types.CredentialStatusDocument) *JsonLdCredentialStatus {
if len(credStatusDoc.Context) == 0 {
Expand Down Expand Up @@ -108,6 +124,37 @@ func NewJsonLdCredentialStatus(credStatusDoc *types.CredentialStatusDocument) *J
return jsonLdCredentialStatus
}

func NewJsonLdCredentialStatusBJJ(credStatusDoc *types.CredentialStatusDocument, docProof *types.DocumentProof) *JsonLdCredentialStatusBJJ {
if len(credStatusDoc.Context) == 0 {
panic("atleast one context url must be provided in the Credential Status Document for Canonization")
}

var jsonLdCredentialStatus *JsonLdCredentialStatusBJJ = &JsonLdCredentialStatusBJJ{}

for _, url := range credStatusDoc.Context {
contextObj, ok := ContextUrlMap[url]
if !ok {
panic(fmt.Sprintf("invalid or unsupported context url: %v", url))
}
jsonLdCredentialStatus.Context = append(jsonLdCredentialStatus.Context, contextObj)
}

jsonLdCredentialStatus.Id = credStatusDoc.Id
jsonLdCredentialStatus.Revoked = credStatusDoc.Revoked
jsonLdCredentialStatus.Remarks = credStatusDoc.Remarks
jsonLdCredentialStatus.Suspended = credStatusDoc.Suspended
jsonLdCredentialStatus.Issuer = credStatusDoc.Issuer
jsonLdCredentialStatus.IssuanceDate = credStatusDoc.IssuanceDate
jsonLdCredentialStatus.CredentialMerkleRootHash = credStatusDoc.CredentialMerkleRootHash

jsonLdCredentialStatus.Proof.Type = docProof.Type
jsonLdCredentialStatus.Proof.Created = docProof.Created
jsonLdCredentialStatus.Proof.ProofPurpose = docProof.ProofPurpose
jsonLdCredentialStatus.Proof.VerificationMethod = docProof.VerificationMethod

return jsonLdCredentialStatus
}

// Document Proof

type JsonLdDocumentProof struct {
Expand Down Expand Up @@ -163,6 +210,22 @@ func (doc *JsonLdCredentialSchema) GetContext() []contextObject {
return doc.Context
}

type JsonLdCredentialSchemaBJJ struct {
Context []contextObject `json:"@context,omitempty"`
Type string `json:"type,omitempty"`
ModelVersion string `json:"modelVersion,omitempty"`
Id string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Author string `json:"author,omitempty"`
Authored string `json:"authored,omitempty"`
Schema *types.CredentialSchemaProperty `json:"schema,omitempty"`
Proof JsonLdDocumentProof `json:"proof,omitempty"`
}

func (doc *JsonLdCredentialSchemaBJJ) GetContext() []contextObject {
return doc.Context
}

func NewJsonLdCredentialSchema(credSchema *types.CredentialSchemaDocument) *JsonLdCredentialSchema {
if len(credSchema.Context) == 0 {
panic("atleast one context url must be provided for DID Document for Canonization")
Expand All @@ -189,24 +252,60 @@ func NewJsonLdCredentialSchema(credSchema *types.CredentialSchemaDocument) *Json
return jsonLdDoc
}

func NewJsonLdCredentialSchemaBJJ(credSchema *types.CredentialSchemaDocument, docProof *types.DocumentProof) *JsonLdCredentialSchemaBJJ {
if len(credSchema.Context) == 0 {
panic("atleast one context url must be provided for DID Document for Canonization")
}

var jsonLdDoc *JsonLdCredentialSchemaBJJ = &JsonLdCredentialSchemaBJJ{}

for _, url := range credSchema.Context {
contextObj, ok := ContextUrlMap[url]
if !ok {
panic(fmt.Sprintf("invalid or unsupported context url: %v", url))
}
jsonLdDoc.Context = append(jsonLdDoc.Context, contextObj)
}

jsonLdDoc.Type = credSchema.Type
jsonLdDoc.ModelVersion = credSchema.ModelVersion
jsonLdDoc.Id = credSchema.Id
jsonLdDoc.Name = credSchema.Name
jsonLdDoc.Author = credSchema.Author
jsonLdDoc.Authored = credSchema.Authored
jsonLdDoc.Schema = credSchema.Schema

jsonLdDoc.Proof.Type = docProof.Type
jsonLdDoc.Proof.Created = docProof.Created
jsonLdDoc.Proof.ProofPurpose = docProof.ProofPurpose
jsonLdDoc.Proof.VerificationMethod = docProof.VerificationMethod

return jsonLdDoc
}

// It is a similar to `Did` struct, with the exception that the `context` attribute is of type
// `contextObject` instead of `[]string`, which is meant for accomodating Context JSON body
// having arbritrary attributes. It should be used for performing Canonization.
type JsonLdDidDocumentWithoutVM struct {
Context []contextObject `json:"@context,omitempty"`
Id string `json:"id,omitempty"`
Controller []string `json:"controller,omitempty"`
AlsoKnownAs []string `json:"alsoKnownAs,omitempty"`
Authentication []verificationMethodWithoutController `json:"authentication,omitempty"`
AssertionMethod []verificationMethodWithoutController `json:"assertionMethod,omitempty"`
Context []contextObject `json:"@context,omitempty"`
Id string `json:"id,omitempty"`
Controller []string `json:"controller,omitempty"`
// AlsoKnownAs []string `json:"alsoKnownAs,omitempty"`
Authentication []verificationMethodWithoutController `json:"authentication,omitempty"`
AssertionMethod []verificationMethodWithoutController `json:"assertionMethod,omitempty"`
CapabilityDelegation []verificationMethodWithoutController `json:"capabilityDelegation,omitempty"`
CapabilityInvocation []verificationMethodWithoutController `json:"capabilityInvocation,omitempty"`
KeyAgreement []verificationMethodWithoutController `json:"keyAgreement,omitempty"`
Proof JsonLdDocumentProof `json:"proof,omitempty"`
Service []*types.Service `protobuf:"bytes,11,rep,name=service,proto3" json:"service,omitempty"`
}

func (doc *JsonLdDidDocumentWithoutVM) GetContext() []contextObject {
return doc.Context
}

// NewJsonLdDidDocument returns a new JsonLdDid struct from input Did
func NewJsonLdDidDocumentWithoutVM(didDoc *types.DidDocument) *JsonLdDidDocumentWithoutVM {
func NewJsonLdDidDocumentWithoutVM(didDoc *types.DidDocument, docProof *types.DocumentProof) *JsonLdDidDocumentWithoutVM {
if len(didDoc.Context) == 0 {
panic("atleast one context url must be provided for DID Document for Canonization")
}
Expand All @@ -223,8 +322,6 @@ func NewJsonLdDidDocumentWithoutVM(didDoc *types.DidDocument) *JsonLdDidDocument

jsonLdDoc.Id = didDoc.Id
jsonLdDoc.Controller = didDoc.Controller
jsonLdDoc.AlsoKnownAs = didDoc.AlsoKnownAs

// Replace verification method ids with their corresponding Verification Method object
var vmMap map[string]verificationMethodWithoutController = map[string]verificationMethodWithoutController{}

Expand All @@ -250,8 +347,31 @@ func NewJsonLdDidDocumentWithoutVM(didDoc *types.DidDocument) *JsonLdDidDocument
jsonLdDoc.AssertionMethod = append(jsonLdDoc.AssertionMethod, vmObj)
jsonLdDoc.AssertionMethod[len(jsonLdDoc.AssertionMethod)-1].Id = jsonLdDoc.AssertionMethod[len(jsonLdDoc.AssertionMethod)-1].Id + "assertionMethod"
}

for _, vmId := range didDoc.CapabilityDelegation {
vmObj := vmMap[vmId]
jsonLdDoc.CapabilityDelegation = append(jsonLdDoc.CapabilityDelegation, vmObj)
jsonLdDoc.CapabilityDelegation[len(jsonLdDoc.CapabilityDelegation)-1].Id = jsonLdDoc.CapabilityDelegation[len(jsonLdDoc.CapabilityDelegation)-1].Id + "capabilityDelegation"
}

for _, vmId := range didDoc.CapabilityInvocation {
vmObj := vmMap[vmId]
jsonLdDoc.CapabilityInvocation = append(jsonLdDoc.CapabilityInvocation, vmObj)
jsonLdDoc.CapabilityInvocation[len(jsonLdDoc.CapabilityInvocation)-1].Id = jsonLdDoc.CapabilityInvocation[len(jsonLdDoc.CapabilityInvocation)-1].Id + "capabilityInvocation"
}

for _, vmId := range didDoc.KeyAgreement {
vmObj := vmMap[vmId]
jsonLdDoc.KeyAgreement = append(jsonLdDoc.KeyAgreement, vmObj)
jsonLdDoc.KeyAgreement[len(jsonLdDoc.KeyAgreement)-1].Id = jsonLdDoc.KeyAgreement[len(jsonLdDoc.KeyAgreement)-1].Id + "keyAgreement"
}
}

jsonLdDoc.Proof.Type = docProof.Type
jsonLdDoc.Proof.Created = docProof.Created
jsonLdDoc.Proof.ProofPurpose = docProof.ProofPurpose
jsonLdDoc.Proof.VerificationMethod = docProof.VerificationMethod + docProof.ProofPurpose
jsonLdDoc.Service = didDoc.Service
return jsonLdDoc
}

Expand Down
4 changes: 2 additions & 2 deletions x/ssi/tests/crypto/signature.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package crypto

import (
ldcontext "github.com/hypersign-protocol/hid-node/x/ssi/ld-context"
cli "github.com/hypersign-protocol/hid-node/x/ssi/client/cli"
ldcontext "github.com/hypersign-protocol/hid-node/x/ssi/ld-context"
"github.com/hypersign-protocol/hid-node/x/ssi/types"
)

Expand Down Expand Up @@ -70,7 +70,7 @@ func GetDocumentSignature(doc types.SsiMsg, docProof *types.DocumentProof, priva
}
case types.BJJSignature2021:
var docBytes []byte
docBytes, err := ldcontext.BJJSignature2021Normalize(doc)
docBytes, err := ldcontext.BJJSignature2021Normalize(doc, docProof)
if err != nil {
return "", err
}
Expand Down
Loading
Loading