About Signature

Generation Process

1 Build signature content: Encrypt timestamp method requestPath and body using HMAC SHA256 with SecretKey then encode using Base64

2 Sorting rules:

  • Parameters in requestPath and content in body should follow the same sorting rule
  • Sorting order: intfloat/doublestringlist & object
  • Data of the same type are sorted lexicographically list and object are sorted based on their positions in the sequence
  • Consistent recursive sorting rule for nested structures
  • Empty values (such as null and '') as well as empty arrays [] and empty dictionaries {} are excluded from the signature

3 Example:

  • Input example: {{“x”: 1 “y”: 2} 1 3 2 -4 11 “xxxxx” “yyyy” “jscx” 0 “sss” {“z”: 2 “x”: 1 “a”: “”}}
  • After sorting: {-4 0 1 2 3 11 “jscx” “sss” “xxxxx” “yyyy” {“x”: 1 “y”: 2} {“x”: 1 “z”: 2}}

Important Notes

  • Ensure data sorting during transmission is independent of the content
  • If both path and body contain parameters sort them separately and concatenate as timestamp + method + requestPath + body

Example Signature

  • timestamp = 1538054050234
  • method = GET
  • requestPath = /api/v1/crypto/order?order_no=sdf23?token=ETH
  • body is empty
  • Signature content: 1538054050234 + GET + /api/v1/crypto/order?token=ETH?order_no=sdf23

Timestamp Format

  • timestamp uses ISO formatted Unix timestamp (milliseconds) eg 1538054050231

Other Instructions

  • method is the request method and must be uppercase
  • requestPath is case-sensitive if ending with / it should still be retained
  • body is the request body string it can be omitted if there is no body
  • Any empty parameters are filtered out and not included in the signature
  • Use HMAC SHA256 and SecretKey to sign the hash string finally encoded in Base64
```python
import base64
import hmac
import json
import requests
from datetime import datetime
from typing import Dict Any List Union Type

# Signature
class SignatureUtility:
    def generate_signature(self secret_key: str message: str) -> str:
        Generate the HMAC SHA256 signature for a given message
        signature = hmacnew(secret_keyencode() messageencode() digestmod=sha256)digest()
        return base64b64encode(signature)decode()

    def verify_signature(self secret_key: str message: str received_signature: str) -> bool:
        Verify the received signature against the computed one
        computed_signature = selfgenerate_signature(secret_key message)
        return hmaccompare_digest(computed_signature received_signature)

    def clean_and_sort_dict(self data: Union[Dict[Any Union[Dict Any]] List[Union[Dict Any]]]) -> Union[Dict[Any Union[Dict Any]] List[Union[Dict Any]]]:
        if isinstance(data dict):
            sorted_dict = {}
            for key value in sorted(dataitems()):
                if isinstance(value (dict list)):
                    value = selfclean_and_sort_dict(value)

                # Checking for non-empty values including non-empty lists and non-empty dictionaries
                if value or value == 0:
                    sorted_dict[key] = value
            return sorted_dict if sorted_dict else None  # Return None if the dictionary is empty
        elif isinstance(data list):
            int_list = sorted([item for item in data if isinstance(item int)])
            float_list = sorted([item for item in data if isinstance(item float)])
            str_list = sorted([item for item in data if isinstance(item str)])
            complex_data_types = [item for item in data if isinstance(item (dict list))]

            sorted_complex_data = [selfclean_and_sort_dict(item) for item in complex_data_types]
            sorted_complex_data = [item for item in sorted_complex_data if item]  # Filter out None values

            result = int_li