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