1 changed files with 142 additions and 0 deletions
@ -0,0 +1,142 @@ |
|||||
|
import json |
||||
|
import time |
||||
|
from mnemonic import Mnemonic |
||||
|
from eth_account import Account |
||||
|
import jwt |
||||
|
import requests |
||||
|
from typing import Tuple, Dict, Any |
||||
|
|
||||
|
# Constants |
||||
|
DEFAULT_ROOT_DERIVATION_PATH = "m/84737769'/0'/0'/0'" |
||||
|
API_SERVER = "https://test-api.endorser.ch" # Replace with your endorser API URL |
||||
|
|
||||
|
# Step 1: Generate a mnemonic seed phrase |
||||
|
def generate_mnemonic() -> str: |
||||
|
mnemo = Mnemonic("english") |
||||
|
return mnemo.generate(strength=256) # 24-word mnemonic |
||||
|
|
||||
|
# Step 2: Derive Ethereum address and keys from mnemonic |
||||
|
def derive_address(mnemonic: str, derivation_path: str = DEFAULT_ROOT_DERIVATION_PATH) -> Tuple[str, str, str, str]: |
||||
|
mnemonic = mnemonic.strip().lower() |
||||
|
seed = Mnemonic("english").to_seed(mnemonic) |
||||
|
|
||||
|
# Derive the account using eth-account (simplified, assumes single derivation) |
||||
|
account = Account.from_mnemonic(mnemonic, account_path=derivation_path) |
||||
|
address = account.address |
||||
|
private_hex = account.privateKey.hex()[2:] # Remove '0x' |
||||
|
public_hex = account.key.public_key.to_hex()[2:] # Remove '0x' |
||||
|
|
||||
|
return address, private_hex, public_hex, derivation_path |
||||
|
|
||||
|
# Step 3: Create a DID identifier |
||||
|
def new_identifier(address: str, public_key_hex: str, private_key_hex: str, derivation_path: str) -> Dict[str, Any]: |
||||
|
did = f"did:ethr:{address}" |
||||
|
key_id = f"{did}#keys-1" |
||||
|
|
||||
|
identifier = { |
||||
|
"did": did, |
||||
|
"keys": [{ |
||||
|
"id": key_id, |
||||
|
"type": "Secp256k1VerificationKey2018", |
||||
|
"controller": did, |
||||
|
"ethereumAddress": address, |
||||
|
"publicKeyHex": public_key_hex, |
||||
|
"privateKeyHex": private_key_hex |
||||
|
}], |
||||
|
"services": [] |
||||
|
} |
||||
|
return identifier |
||||
|
|
||||
|
# Step 4: Initialize a new account (DID creation) |
||||
|
def initialize_account() -> Dict[str, Any]: |
||||
|
# Generate mnemonic |
||||
|
mnemonic = generate_mnemonic() |
||||
|
|
||||
|
# Derive keys and address |
||||
|
address, private_hex, public_hex, derivation_path = derive_address(mnemonic) |
||||
|
|
||||
|
# Create DID identifier |
||||
|
identity = new_identifier(address, public_hex, private_hex, derivation_path) |
||||
|
|
||||
|
# Simulate storing (in a real app, save to a database) |
||||
|
account_data = { |
||||
|
"did": identity["did"], |
||||
|
"identity": json.dumps(identity), |
||||
|
"mnemonic": mnemonic, |
||||
|
"derivation_path": derivation_path |
||||
|
} |
||||
|
print("Account initialized:", account_data) |
||||
|
return identity |
||||
|
|
||||
|
# Step 5: Create a Verifiable Credential JWT |
||||
|
def create_endorser_jwt(did: str, private_key_hex: str, payload: Dict[str, Any], expires_in: int = 3600) -> str: |
||||
|
# Prepare JWT headers and payload |
||||
|
headers = {"typ": "JWT", "alg": "ES256K"} |
||||
|
current_time = int(time.time()) |
||||
|
jwt_payload = { |
||||
|
"iat": current_time, |
||||
|
"exp": current_time + expires_in, |
||||
|
"iss": did, |
||||
|
**payload |
||||
|
} |
||||
|
|
||||
|
# Sign the JWT using the private key |
||||
|
private_key_bytes = bytes.fromhex(private_key_hex) |
||||
|
jwt_token = jwt.encode( |
||||
|
jwt_payload, |
||||
|
private_key_bytes, |
||||
|
algorithm="ES256K", |
||||
|
headers=headers |
||||
|
) |
||||
|
return jwt_token |
||||
|
|
||||
|
# Step 6: Create and submit a registration claim |
||||
|
def register(active_did: str, private_key_hex: str, api_server: str = API_SERVER) -> Dict[str, Any]: |
||||
|
# Create a simple VC payload (replace with your specific claim) |
||||
|
vc_payload = { |
||||
|
"vc": { |
||||
|
"@context": ["https://www.w3.org/2018/credentials/v1"], |
||||
|
"type": ["VerifiableCredential"], |
||||
|
"credentialSubject": { |
||||
|
"id": active_did, |
||||
|
"status": "registered" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
# Sign the VC as a JWT |
||||
|
jwt_token = create_endorser_jwt(active_did, private_key_hex, vc_payload) |
||||
|
|
||||
|
# Submit to the API |
||||
|
url = f"{api_server}/api/v2/claim" |
||||
|
payload = {"jwtEncoded": jwt_token} |
||||
|
|
||||
|
try: |
||||
|
response = requests.post( |
||||
|
url, |
||||
|
json=payload, |
||||
|
headers={"Content-Type": "application/json"} |
||||
|
) |
||||
|
response_data = response.json() |
||||
|
|
||||
|
if response.status_code == 200 and response_data.get("success"): |
||||
|
return {"success": True} |
||||
|
else: |
||||
|
return {"error": "Registration failed", "details": response_data} |
||||
|
|
||||
|
except requests.RequestException as e: |
||||
|
return {"error": f"Error submitting claim: {str(e)}"} |
||||
|
|
||||
|
# Main execution |
||||
|
def main(): |
||||
|
# Step 1: Create a new DID |
||||
|
identity = initialize_account() |
||||
|
active_did = identity["did"] |
||||
|
private_key_hex = identity["keys"][0]["privateKeyHex"] |
||||
|
|
||||
|
# Step 2: Register the DID |
||||
|
result = register(active_did, private_key_hex) |
||||
|
print("Registration result:", result) |
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
main() |
Loading…
Reference in new issue