Skip to content

Commit

Permalink
Merge pull request #376 from hypersign-protocol/ld-json-fix
Browse files Browse the repository at this point in the history
fixed JSON-LD canonization; added `client` proto package to define governed constants for external clients
  • Loading branch information
arnabghose997 authored Nov 9, 2023
2 parents c0928a1 + ce0091b commit ad004f4
Show file tree
Hide file tree
Showing 36 changed files with 509 additions and 283 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ build: go-version-check

proto-gen-go:
@echo "Generating golang code from protobuf"
./scripts/protocgen.sh
./scripts/protocgen-go.sh

proto-gen-swagger:
@echo "Generating swagger docs"
Expand Down
61 changes: 44 additions & 17 deletions cmd/hid-noded/cmd/debug_extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,63 +305,90 @@ func signSSIDocCmd() *cobra.Command {

func signDidDocCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "did-doc [doc] [private-key] [signing-algo]",
Use: "did-doc [doc] [private-key] [proof-object-without-signature]",
Short: "Did Document signature",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
argDidDoc := args[0]
argPrivateKey := args[1]
argSigningAlgo := args[2]
argProofObjectWithoutSignature := args[2]

clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

// Unmarshal Schema Document
// Unmarshal DID Document
var didDoc types.DidDocument
err = clientCtx.Codec.UnmarshalJSON([]byte(argDidDoc), &didDoc)
if err != nil {
return err
}

// Sign Schema Document
// Unmarshal Proof Object
var didDocProof types.DocumentProof
err = clientCtx.Codec.UnmarshalJSON([]byte(argProofObjectWithoutSignature), &didDocProof)
if err != nil {
return err
}

// Sign DID Document
var signature string
switch argSigningAlgo {
switch didDocProof.Type {
case types.Ed25519Signature2020:
didDocBytes, err := ldcontext.EdDSACryptoSuite2020Canonize(&didDoc)
if err != nil {
return err
var didDocBytes []byte
if len(didDoc.Context) > 0 {
didDocBytes, err = ldcontext.Ed25519Signature2020Normalize(&didDoc, &didDocProof)
if err != nil {
return err
}
} else {
didDocBytes = didDoc.GetSignBytes()
}

signature, err = hidnodecli.GetEd25519Signature2020(argPrivateKey, didDocBytes[:])
if err != nil {
return err
}
case types.EcdsaSecp256k1Signature2019:
didDocBytes, err := ldcontext.EcdsaSecp256k1Signature2019Canonize(&didDoc)
if err != nil {
return err
var didDocBytes []byte
if len(didDoc.Context) > 0 {
didDocBytes, err = ldcontext.EcdsaSecp256k1Signature2019Normalize(&didDoc, &didDocProof)
if err != nil {
return err
}
} else {
didDocBytes = didDoc.GetSignBytes()
}

signature, err = hidnodecli.GetEcdsaSecp256k1Signature2019(argPrivateKey, didDocBytes[:])
if err != nil {
return err
}
case types.EcdsaSecp256k1RecoverySignature2020:
didDocBytes, err := ldcontext.EcdsaSecp256k1RecoverySignature2020Canonize(&didDoc)
if err != nil {
return err
var didDocBytes []byte
if len(didDoc.Context) > 0 {
didDocBytes, err = ldcontext.EcdsaSecp256k1RecoverySignature2020Normalize(&didDoc, &didDocProof)
if err != nil {
return err
}
} else {
didDocBytes = didDoc.GetSignBytes()
}

signature, err = hidnodecli.GetEcdsaSecp256k1RecoverySignature2020(argPrivateKey, didDocBytes[:])
if err != nil {
return err
}
case types.BbsBlsSignature2020:
didDocBytes, err := ldcontext.BbsBlsSignature2020Canonize(&didDoc)
if err != nil {
return err
var didDocBytes []byte
if len(didDoc.Context) > 0 {
didDocBytes, err = ldcontext.BbsBlsSignature2020Normalize(&didDoc, &didDocProof)
if err != nil {
return err
}
} else {
didDocBytes = didDoc.GetSignBytes()
}

signature, err = hidnodecli.GetBbsBlsSignature2020(argPrivateKey, didDocBytes[:])
Expand Down
8 changes: 5 additions & 3 deletions localnetsetup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ BINARY=hid-noded
# Check if the binary is installed
${BINARY} &> /dev/null

CHAINID=hidnode

RET_VAL=$?
if [ ${RET_VAL} -ne 0 ]; then
echo "hid-noded binary is not installed in your system."
Expand All @@ -19,7 +21,7 @@ rm -rf $HOME/.hid-node/
mkdir $HOME/.hid-node

# Init node
hid-noded init --chain-id=hidnode node1 --home=$HOME/.hid-node
hid-noded init --chain-id=$CHAINID node1 --home=$HOME/.hid-node

# Change hid-node config
hid-noded configure min-gas-prices 0uhid
Expand All @@ -38,14 +40,14 @@ cat $HOME/.hid-node/config/genesis.json | jq '.app_state["gov"]["deposit_params"
cat $HOME/.hid-node/config/genesis.json | jq '.app_state["gov"]["voting_params"]["voting_period"]="50s"' > $HOME/.hid-node/config/tmp_genesis.json && mv $HOME/.hid-node/config/tmp_genesis.json $HOME/.hid-node/config/genesis.json

# update ssi genesis
cat $HOME/.hid-node/config/genesis.json | jq '.app_state["ssi"]["chain_namespace"]="devnet"' > $HOME/.hid-node/config/tmp_genesis.json && mv $HOME/.hid-node/config/tmp_genesis.json $HOME/.hid-node/config/genesis.json
cat $HOME/.hid-node/config/genesis.json | jq '.app_state["ssi"]["chainNamespace"]="devnet"' > $HOME/.hid-node/config/tmp_genesis.json && mv $HOME/.hid-node/config/tmp_genesis.json $HOME/.hid-node/config/genesis.json

# update mint genesis
cat $HOME/.hid-node/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="uhid"' > $HOME/.hid-node/config/tmp_genesis.json && mv $HOME/.hid-node/config/tmp_genesis.json $HOME/.hid-node/config/genesis.json

# create validator node with tokens
hid-noded add-genesis-account $(hid-noded keys show node1 -a --keyring-backend=test --home=$HOME/.hid-node) 500000000000000000uhid --home=$HOME/.hid-node --keyring-backend test
hid-noded gentx node1 50000000000000000uhid --keyring-backend=test --home=$HOME/.hid-node --chain-id=hidnode
hid-noded gentx node1 50000000000000000uhid --keyring-backend=test --home=$HOME/.hid-node --chain-id=$CHAINID
hid-noded collect-gentxs --home=$HOME/.hid-node

# change app.toml values
Expand Down
1 change: 1 addition & 0 deletions proto/ssi/client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This client Proto package is only meant to be used by external clients apart from `hid-node` itself. These are supposed to be the de facto constants based on the Protocol.
31 changes: 31 additions & 0 deletions proto/ssi/client/enums.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// The messages defined here are meant only meant for TS client.
syntax = "proto3";
package hypersign.ssi.client;

option go_package = "github.com/hypersign-protocol/hid-node/x/ssi/types";

enum VerificationMethodRelationships {
authentication = 0;
assertionMethod = 1;
keyAgreement = 2;
capabilityInvocation = 3;
capabilityDelegation = 4;
}

enum VerificationMethodTypes {
Ed25519VerificationKey2020 = 0;
EcdsaSecp256k1VerificationKey2019 = 1;
EcdsaSecp256k1RecoveryMethod2020 = 2;
X25519KeyAgreementKey2020 = 3;
X25519KeyAgreementKeyEIP5630 = 4;
Bls12381G2Key2020 = 5;
BabyJubJubVerificationKey2023 = 6;
}

enum ProofTypes {
Ed25519Signature2020 = 0;
EcdsaSecp256k1Signature2019 = 1;
EcdsaSecp256k1RecoverySignature2020 = 2;
BabyJubJubSignature2023 = 3;
BbsBlsSignature2020 = 4;
}
1 change: 1 addition & 0 deletions proto/ssi/v1/client_spec.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ enum ClientSpecType {
CLIENT_SPEC_TYPE_COSMOS_ADR036 = 1;
CLIENT_SPEC_TYPE_ETH_PERSONAL_SIGN = 2;
}

2 changes: 1 addition & 1 deletion proto/ssi/v1/credential_status.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ message CredentialStatusDocument {
string remarks = 4;
string issuer = 5;
string issuanceDate = 6;
string merkleRootHash = 7;
string credentialMerkleRootHash = 7;
}

message CredentialStatusState {
Expand Down
2 changes: 2 additions & 0 deletions scripts/protocgen.sh → scripts/protocgen-go.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ set -eux pipefail
# Get the path of the cosmos-sdk repo from go/pkg/mod
cosmos_sdk_dir=$(go list -f '{{ .Dir }}' -m github.com/cosmos/cosmos-sdk)
proto_dirs=$(find ./proto -path -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq)
proto_dirs=${proto_dirs/\.\/proto\/ssi\/client} # exclude proto/ssi/client from generating Go files as they are meant for external clients

for dir in $proto_dirs; do
# generate protobuf bind
protoc \
Expand Down
2 changes: 2 additions & 0 deletions scripts/protocgen-ts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ for dir in $proto_dirs; do
--ts_proto_opt=unrecognizedEnum=false \
--ts_proto_opt=useJsonName=true \
--ts_proto_opt=esModuleInterop=true \
--ts_proto_opt=stringEnums=true \
--ts_proto_opt=outputExtensions=true \
-I "proto" \
-I "third_party/proto" \
-I "$cosmos_sdk_dir/third_party/proto" \
Expand Down
42 changes: 38 additions & 4 deletions tests/e2e/ssi_tests/e2e_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,22 @@ def credential_status_test():
cred_id = cred_doc["id"]
run_blockchain_command(register_cred_status_cmd, f"Registering Credential status with Id: {cred_id}")

print("3. PASS: Bob suspends the credential status using one of his VMs\n")
print("3. FAIL: Bob attempts to update credential status without any changes\n")
_, cred_proof = generate_cred_status_document(
kp_bob,
did_doc_bob,
did_doc_bob_vm["id"],
updated_credstatus_doc=cred_doc
)
register_cred_status_cmd = form_update_cred_status_tx(
cred_doc,
cred_proof,
DEFAULT_BLOCKCHAIN_ACCOUNT_NAME
)
cred_id = cred_doc["id"]
run_blockchain_command(register_cred_status_cmd, f"Updating Credential status with Id: {cred_id}", True)

print("4. PASS: Bob suspends the credential status using one of his VMs\n")
cred_doc["suspended"] = True

_, cred_proof = generate_cred_status_document(
Expand All @@ -917,7 +932,7 @@ def credential_status_test():
cred_id = cred_doc["id"]
run_blockchain_command(register_cred_status_cmd, f"Updating Credential status with Id: {cred_id}")

print("4. PASS: Bob un-suspends the credential status using one of his VMs\n")
print("5. PASS: Bob un-suspends the credential status using one of his VMs\n")
cred_doc["suspended"] = False

_, cred_proof = generate_cred_status_document(
Expand All @@ -934,7 +949,26 @@ def credential_status_test():
cred_id = cred_doc["id"]
run_blockchain_command(register_cred_status_cmd, f"Updating Credential status with Id: {cred_id}")

print("5. PASS: Bob revokes the credential status using one of his VMs\n")
print("6. FAIL: Bob attempts to update the VC status document by changing the Credential Merkle Root Hash\n")
valid_cred_merkle_root_hash = cred_doc["credentialMerkleRootHash"] # for later re-assignment in next test case
cred_doc["credentialMerkleRootHash"] = "9de17abaffe74f4675c738f5d69c28a329aff8721cb0ed4808d8616e26280ed9"

_, cred_proof = generate_cred_status_document(
kp_bob,
did_doc_bob,
did_doc_bob_vm["id"],
updated_credstatus_doc=cred_doc
)
register_cred_status_cmd = form_update_cred_status_tx(
cred_doc,
cred_proof,
DEFAULT_BLOCKCHAIN_ACCOUNT_NAME
)
cred_id = cred_doc["id"]
run_blockchain_command(register_cred_status_cmd, f"Updating Credential status with Id: {cred_id}", True)
cred_doc["credentialMerkleRootHash"] = valid_cred_merkle_root_hash

print("7. PASS: Bob revokes the credential status using one of his VMs\n")
cred_doc["revoked"] = True

_, cred_proof = generate_cred_status_document(
Expand All @@ -951,7 +985,7 @@ def credential_status_test():
cred_id = cred_doc["id"]
run_blockchain_command(register_cred_status_cmd, f"Updating Credential status with Id: {cred_id}")

print("6. FAIL: Bob attempts to un-revoke the credential status using one of his VMs\n")
print("8. FAIL: Bob attempts to un-revoke the credential status using one of his VMs\n")
cred_doc["revoked"] = False

_, cred_proof = generate_cred_status_document(
Expand Down
6 changes: 4 additions & 2 deletions tests/e2e/ssi_tests/generate_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
DID_CONTEXT = "https://www.w3.org/ns/did/v1"
SECP256K1_RECOVERY_CONTEXT = "https://ns.did.ai/suites/secp256k1-2020/v1"
SECP256K1_VER_KEY_2019_CONTEXT = "https://ns.did.ai/suites/secp256k1-2019/v1"
BBS_CONTEXT = "https://ns.did.ai/suites/bls12381-2020/v1"

def generate_did_document(key_pair, algo="Ed25519Signature2020", bech32prefix="hid", is_uuid=False):
base_document = {
Expand All @@ -27,7 +28,8 @@ def generate_did_document(key_pair, algo="Ed25519Signature2020", bech32prefix="h
base_document["context"].append(SECP256K1_RECOVERY_CONTEXT)
if algo == "EcdsaSecp256k1Signature2019":
base_document["context"].append(SECP256K1_VER_KEY_2019_CONTEXT)

if algo == "BbsBlsSignature2020":
base_document["context"].append(BBS_CONTEXT)
did_id = generate_document_id("did", key_pair, algo, is_uuid)

# Form the DID Document
Expand Down Expand Up @@ -152,7 +154,7 @@ def generate_cred_status_document(key_pair, cred_author, vm, signature=None, alg
"id": "",
"issuer": "did:hid:devnet:z3861habXtUFLNuu6J7m5p8VPsoBMduYbYeUxfx9CnWZR",
"issuanceDate": "2022-08-16T09:37:12Z",
"merkleRootHash": "f35c3a4e3f1b8ba54ee3cf59d3de91b8b357f707fdb72a46473b65b46f92f80b"
"credentialMerkleRootHash": "f35c3a4e3f1b8ba54ee3cf59d3de91b8b357f707fdb72a46473b65b46f92f80b"
}

proof_type = ""
Expand Down
6 changes: 3 additions & 3 deletions tests/e2e/ssi_tests/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def form_did_create_tx_multisig(diddoc, signPairs, blockchain_account):
"proofValue": "",
}

signature = get_document_signature(diddoc, "did", signPair["kp"], signAlgo)
signature = get_document_signature(diddoc, "did", signPair["kp"], signAlgo, base_diddoc_proof)
base_diddoc_proof["proofValue"] = signature
proofsStr += f"'{json.dumps(base_diddoc_proof)}' "

Expand All @@ -46,7 +46,7 @@ def form_did_update_tx_multisig(diddoc, signPairs, blockchain_account):
"proofValue": "",
}

signature = get_document_signature(diddoc, "did", signPair["kp"], signAlgo)
signature = get_document_signature(diddoc, "did", signPair["kp"], signAlgo, base_diddoc_proof)
base_diddoc_proof["proofValue"] = signature
proofsStr += f"'{json.dumps(base_diddoc_proof)}' "

Expand All @@ -72,7 +72,7 @@ def form_did_deactivate_tx_multisig(didId, signPairs, blockchain_account):
"proofValue": "",
}

signature = get_document_signature(diddoc, "did", signPair["kp"], signAlgo)
signature = get_document_signature(diddoc, "did", signPair["kp"], signAlgo, base_diddoc_proof)
base_diddoc_proof["proofValue"] = signature
proofsStr += f"'{json.dumps(base_diddoc_proof)}' "

Expand Down
8 changes: 6 additions & 2 deletions tests/e2e/ssi_tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def is_blockchain_active(rpc_port):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
assert s.connect_ex(('localhost', rpc_port)) == 0, f"hid-noded is not running"

def get_document_signature(doc: dict, doc_type: str, key_pair: dict, algo: str = "ed25519"):
def get_document_signature(doc: dict, doc_type: str, key_pair: dict, algo: str = "ed25519", proofObj = None):
if algo in ["EcdsaSecp256k1RecoverySignature2020", "BabyJubJubSignature2023"]:
private_key = key_pair["priv_key_hex"]
else:
Expand All @@ -123,7 +123,11 @@ def get_document_signature(doc: dict, doc_type: str, key_pair: dict, algo: str =
else:
raise Exception("Invalid value for doc_type param: " + doc_type)

cmd_string = f"hid-noded debug sign-ssi-doc {doc_cmd} '{json.dumps(doc)}' {private_key} {algo}"
if doc_type == "did":
print()
cmd_string = f"hid-noded debug sign-ssi-doc {doc_cmd} '{json.dumps(doc)}' {private_key} '{json.dumps(proofObj)}'"
else:
cmd_string = f"hid-noded debug sign-ssi-doc {doc_cmd} '{json.dumps(doc)}' {private_key} {algo}"
signature, _ = run_command(cmd_string)

if signature == "":
Expand Down
Loading

0 comments on commit ad004f4

Please sign in to comment.