Skip to content

Commit

Permalink
Add debug command to sign DID document command (#57)
Browse files Browse the repository at this point in the history
* chore: add sign did document

* chore: renaming

* chore: fix to compare with multibase address and loop all verification method

* chore: rename variable
  • Loading branch information
kenta92115 authored Dec 7, 2023
1 parent 775518d commit 8f3f791
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 13 deletions.
149 changes: 142 additions & 7 deletions cmd/swisstronikd/cmd/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,24 @@ import (
"crypto/rand"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"os"
"strings"

"encoding/hex"
didutil "swisstronik/testutil/did"
"swisstronik/x/did/types"
didcli "swisstronik/x/did/client/cli"
didtypes "swisstronik/x/did/types"

"github.com/cometbft/cometbft/libs/bytes"
"github.com/cosmos/cosmos-sdk/client"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
"github.com/ethereum/go-ethereum/common"
"github.com/google/uuid"
"github.com/spf13/cobra"
"github.com/cometbft/cometbft/libs/bytes"
)

type DIDDocument struct {
Expand Down Expand Up @@ -55,6 +57,11 @@ type Service struct {
ServiceEndpoint []string `json:"serviceEndpoint"`
}

type KeyPair struct {
PrivateKeyBase64 string `json:"private_key_base_64"`
PublicKeyBase64 string `json:"public_key_base_64"`
}

// Cmd creates a CLI main command
func DebugCmd() *cobra.Command {
cmd := &cobra.Command{
Expand All @@ -68,6 +75,7 @@ func DebugCmd() *cobra.Command {
cmd.AddCommand(ExtractPubkeyCmd())
cmd.AddCommand(ConvertAddressCmd())
cmd.AddCommand(SampleDIDResource())
cmd.AddCommand(SignDIDDocument())

return cmd
}
Expand Down Expand Up @@ -180,6 +188,133 @@ func SampleDIDDocument() *cobra.Command {
return cmd
}

func ReadKeyPairFromFile(file string) (KeyPair, error) {
bytes, err := os.ReadFile(file)
if err != nil {
return KeyPair{}, err
}

keyPair := KeyPair{}
err = json.Unmarshal(bytes, &keyPair)
if err != nil {
return KeyPair{}, err
}

return keyPair, nil
}

func SignDIDDocument() *cobra.Command {
cmd := &cobra.Command{
Use: "sign-did-document [did.json] [key.json]",
Short: "Generates signed DID document ready to be stored in DID registry",
Long: "Generates signed self-controlled DID document from the payload and key information provided, which is ready to be stored in DID registry.",
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 2 {
return errors.New("invalid input parameters")
}

signInputs := make([]didcli.SignInput, 0)

// Decode did.json to have payload
payloadJSON, err := didcli.ReadPayloadFromFile(args[0])
if err != nil {
// Decode did.json to have payload & sign inputs
payloadJSON, signInputs, err = didcli.ReadPayloadWithSignInputsFromFile(args[0])
}

if err != nil {
return errors.New("invalid payload")
}

// Decode key.json to have private and public key pair
keyPairFromFile, err := ReadKeyPairFromFile(args[1])
if err != nil {
return err
}

// Decode base64 based private key string to have byte[]
privateKeyBytesFromFile, err := base64.StdEncoding.DecodeString(keyPairFromFile.PrivateKeyBase64)
if err != nil {
return err
}

// Encode ed25519 based private key
privateKeyFromFile := ed25519.PrivateKey(privateKeyBytesFromFile)
// Encode ed25519 based public key
publicKeyFromFile := privateKeyFromFile.Public().(ed25519.PublicKey)
// Multibase public key
publicKeyMultibaseFromFile := didutil.GenerateEd25519VerificationKey2020VerificationMaterial(publicKeyFromFile)

// Unmarshal spec-compliant payload
var specPayload didcli.DIDDocument
err = json.Unmarshal([]byte(payloadJSON), &specPayload)
if err != nil {
return err
}

if len(specPayload.VerificationMethod) < 1 {
return errors.New("publicKeyMultibase is not specified")
}

validKey := false
keyId := ""
for _, v := range specPayload.VerificationMethod {
// Check if public key is addressed in verfication method
_, ok := v["publicKeyMultibase"]
if !ok {
continue
}

_, ok = v["id"]
if !ok {
continue
}

// Get multibase public key address
publicKeyMultibase := v["publicKeyMultibase"].(string)

// if there is matching verification method,
if publicKeyMultibase == publicKeyMultibaseFromFile {
keyId = v["id"].(string)
validKey = true
break
}
}

// if there is no matching verification method
if !validKey {
return errors.New("invalid key information")
}

// Construct sign inputs
if len(signInputs) < 1 {
signInputs = append(signInputs, didcli.SignInput{
VerificationMethodID: keyId,
PrivKey: privateKeyFromFile,
})
}

// Construct payload with sign inputs
result := didcli.PayloadWithSignInputs{
Payload: payloadJSON,
SignInputs: signInputs,
}

// Encode the structured result
encodedResult, err := json.Marshal(result)
if err != nil {
return err
}

// Print output.
_, err = fmt.Fprintln(cmd.OutOrStdout(), string(encodedResult))
return err
},
}

return cmd
}

func SampleDIDResource() *cobra.Command {
cmd := &cobra.Command{
Use: "sample-did-resource [existing-did] [base64-encoded-ed25519-private-key]",
Expand Down Expand Up @@ -210,7 +345,7 @@ func SampleDIDResource() *cobra.Command {
if !didtypes.IsValidDID(did, didtypes.DIDMethod) {
return fmt.Errorf("provided DID is invalid")
}

// Derive collection id from provided DID
_, collectionId, err := didtypes.TrySplitDID(did)
if err != nil {
Expand All @@ -220,12 +355,12 @@ func SampleDIDResource() *cobra.Command {
resource := didtypes.MsgCreateResourcePayload{
CollectionId: collectionId,
Id: uuid.NewString(),
Name: "sample-resource",
Version: "sample-version",
Name: "sample-resource",
Version: "sample-version",
ResourceType: "SampleResourceType",
AlsoKnownAs: []*types.AlternativeUri{
AlsoKnownAs: []*didtypes.AlternativeUri{
{
Uri: "http://example.com/example-did",
Uri: "http://example.com/example-did",
Description: "http-uri",
},
},
Expand Down
31 changes: 25 additions & 6 deletions x/did/client/cli/tx.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package cli

import (
"fmt"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"crypto/ed25519"
"encoding/json"
"fmt"
"os"


"github.com/cosmos/cosmos-sdk/client"
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

"swisstronik/x/did/types"
)

Expand Down Expand Up @@ -61,6 +62,10 @@ type Service struct {
ServiceEndpoint []string `json:"serviceEndpoint"`
}

type Payload struct {
Payload json.RawMessage
}

type PayloadWithSignInputs struct {
Payload json.RawMessage
SignInputs []SignInput
Expand Down Expand Up @@ -119,6 +124,21 @@ func AccAddrByKeyRef(keyring keyring.Keyring, keyRef string) (sdk.AccAddress, er
return sdk.AccAddressFromBech32(keyRef)
}

func ReadPayloadFromFile(filePath string) (json.RawMessage, error) {
bytes, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}

payload := &Payload{}
err = json.Unmarshal(bytes, payload)
if err != nil {
return nil, err
}

return payload.Payload, nil
}

func ReadPayloadWithSignInputsFromFile(filePath string) (json.RawMessage, []SignInput, error) {
bytes, err := os.ReadFile(filePath)
if err != nil {
Expand Down Expand Up @@ -202,4 +222,3 @@ func GetFromSpecCompliantPayload(specPayload DIDDocument) ([]*types.Verification

return verificationMethod, service, nil
}

0 comments on commit 8f3f791

Please sign in to comment.