mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 17:31:39 +00:00
@@ -0,0 +1,18 @@
|
||||
[tool.commitizen]
|
||||
name = "cz_customize"
|
||||
tag_format = "vault/v$version"
|
||||
ignored_tag_formats = ["*/v${version}", "v${version}"]
|
||||
version_scheme = "semver"
|
||||
version_provider = "scm"
|
||||
update_changelog_on_bump = true
|
||||
changelog_file = "CHANGELOG.md"
|
||||
major_version_zero = true
|
||||
annotated_tag = true
|
||||
pre_bump_hooks = ["bash scripts/hook-bump-pre.sh"]
|
||||
post_bump_hooks = ["goreleaser release --clean -f cmd/vault/.goreleaser.yml"]
|
||||
|
||||
[tool.commitizen.customize]
|
||||
bump_pattern = "^(feat|fix|refactor|perf|BREAKING CHANGE)"
|
||||
bump_map = { "BREAKING CHANGE" = "MAJOR", "feat" = "MINOR", "fix" = "PATCH", "refactor" = "PATCH", "perf" = "PATCH" }
|
||||
default_bump = "PATCH"
|
||||
changelog_pattern = "^(feat|fix|refactor|docs|build)\\(vault\\)(!)?:"
|
||||
@@ -0,0 +1,71 @@
|
||||
# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json
|
||||
---
|
||||
version: 2
|
||||
dist: dist/vault
|
||||
monorepo:
|
||||
tag_prefix: vault/
|
||||
dir: cmd/vault
|
||||
|
||||
project_name: vault
|
||||
before:
|
||||
hooks:
|
||||
- go mod download
|
||||
|
||||
builds:
|
||||
- id: vault
|
||||
main: main.go
|
||||
binary: vault
|
||||
no_unique_dist_dir: true
|
||||
hooks:
|
||||
post:
|
||||
- cp dist/vault/vault.wasm x/dwn/client/plugin/vault.wasm
|
||||
- cp dist/vault/vault.wasm packages/es/src/plugin/plugin.wasm
|
||||
mod_timestamp: "{{ .CommitTimestamp }}"
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- wasip1
|
||||
goarch:
|
||||
- wasm
|
||||
flags:
|
||||
- -mod=readonly
|
||||
- -trimpath
|
||||
ldflags:
|
||||
- -s -w
|
||||
- -X main.version={{.Version}}
|
||||
- -X main.commit={{.Commit}}
|
||||
- -X main.date={{.Date}}
|
||||
|
||||
archives:
|
||||
- id: vault-wasm-archive
|
||||
name_template: "vault_wasm_{{ .Version }}"
|
||||
formats: ["binary"]
|
||||
wrap_in_directory: true
|
||||
|
||||
blobs:
|
||||
- provider: s3
|
||||
endpoint: https://eb37925850388bca807b7fab964c12bb.r2.cloudflarestorage.com
|
||||
bucket: releases
|
||||
region: auto
|
||||
directory: "vault/{{ .Tag }}"
|
||||
|
||||
release:
|
||||
disable: false
|
||||
github:
|
||||
owner: sonr-io
|
||||
name: sonr
|
||||
name_template: "{{.ProjectName}}/{{ .Tag }}"
|
||||
draft: false
|
||||
replace_existing_draft: false # Don't replace drafts
|
||||
replace_existing_artifacts: false # Append, don't replace
|
||||
mode: append # Explicitly set to append mode
|
||||
|
||||
checksum:
|
||||
name_template: "vault_checksums.txt"
|
||||
|
||||
snapshot:
|
||||
version_template: "{{ incpatch .Version }}-dev"
|
||||
|
||||
# Changelog configuration
|
||||
changelog:
|
||||
sort: asc
|
||||
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
# Output configuration - dual output for both plugin and ES package
|
||||
GIT_ROOT := $(shell git rev-parse --show-toplevel)
|
||||
PLUGIN_DIR := $(GIT_ROOT)/x/dwn/client/plugin
|
||||
ES_PACKAGE_DIR := $(GIT_ROOT)/packages/es/src/plugin
|
||||
OUTPUT_FILE := plugin.wasm
|
||||
PLUGIN_PATH := $(PLUGIN_DIR)/vault.wasm
|
||||
ES_PATH := $(ES_PACKAGE_DIR)/$(OUTPUT_FILE)
|
||||
|
||||
# Build configuration for WASM
|
||||
GOOS := wasip1
|
||||
GOARCH := wasm
|
||||
|
||||
# Version information
|
||||
VERSION := $(shell echo $(shell git describe --tags 2>/dev/null || echo "dev") | sed 's/^v//')
|
||||
COMMIT := $(shell git log -1 --format='%H')
|
||||
|
||||
.PHONY: all build clean install test version help
|
||||
|
||||
all: build
|
||||
|
||||
build:
|
||||
@echo "Building vault WASM module..."
|
||||
@echo "Targets: Plugin and ES package"
|
||||
@mkdir -p $(PLUGIN_DIR)
|
||||
@mkdir -p $(ES_PACKAGE_DIR)
|
||||
@GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o $(PLUGIN_PATH) main.go
|
||||
@cp $(PLUGIN_PATH) $(ES_PATH)
|
||||
@echo "✅ Vault WASM module built successfully"
|
||||
@echo "Plugin output: $(PLUGIN_PATH)"
|
||||
@echo "ES package output: $(ES_PATH)"
|
||||
@ls -lh $(PLUGIN_PATH) | awk '{print "Plugin size: " $$5}'
|
||||
@ls -lh $(ES_PATH) | awk '{print "ES package size: " $$5}'
|
||||
|
||||
tidy:
|
||||
@echo "Tidying vault build artifacts..."
|
||||
@go mod tidy
|
||||
@echo "✅ Tidy complete"
|
||||
|
||||
test:
|
||||
@echo "Running vault tests..."
|
||||
@go test -v ./...
|
||||
@cd $(GIT_ROOT) && go test -C . -mod=readonly -v github.com/sonr-io/sonr/x/dwn/client/plugin/...
|
||||
|
||||
clean:
|
||||
@echo "Cleaning vault build artifacts..."
|
||||
@rm -f $(PLUGIN_PATH)
|
||||
@rm -f $(ES_PATH)
|
||||
@echo "✅ Clean complete"
|
||||
|
||||
release:
|
||||
@echo "Creating vault release..."
|
||||
@cd $(GIT_ROOT) && cz --config cmd/vault/.cz.toml --no-raise 6,21 bump --yes --increment PATCH
|
||||
|
||||
snapshot:
|
||||
@echo "Dry-Run Bumping Vault version..."
|
||||
@cd $(GIT_ROOT) && cz --config cmd/vault/.cz.toml bump --yes --dry-run --no-verify --increment PATCH
|
||||
@echo "Creating vault snapshots for all platforms..."
|
||||
@cd $(GIT_ROOT) && goreleaser release --snapshot --clean -f cmd/vault/.goreleaser.yml
|
||||
|
||||
version:
|
||||
@echo "Vault WASM Module"
|
||||
@echo "================="
|
||||
@echo "Version: $(VERSION)"
|
||||
@echo "Commit: $(COMMIT)"
|
||||
@echo "Target OS: $(GOOS)"
|
||||
@echo "Target Arch: $(GOARCH)"
|
||||
@echo "Plugin output: $(PLUGIN_PATH)"
|
||||
@echo "ES output: $(ES_PATH)"
|
||||
|
||||
verify: build
|
||||
@echo "Verifying WASM modules..."
|
||||
@if [ -f "$(PLUGIN_PATH)" ]; then \
|
||||
file "$(PLUGIN_PATH)"; \
|
||||
echo "✅ Plugin WASM file exists"; \
|
||||
else \
|
||||
echo "❌ Plugin WASM file not found"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@if [ -f "$(ES_PATH)" ]; then \
|
||||
file "$(ES_PATH)"; \
|
||||
echo "✅ ES package WASM file exists"; \
|
||||
else \
|
||||
echo "❌ ES package WASM file not found"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "Plugin size: $$(du -h $(PLUGIN_PATH) | cut -f1)"
|
||||
@echo "ES size: $$(du -h $(ES_PATH) | cut -f1)"
|
||||
@echo "✅ Verification complete"
|
||||
|
||||
help:
|
||||
@echo "Vault WASM Module Makefile"
|
||||
@echo "=========================="
|
||||
@echo ""
|
||||
@echo "This Makefile builds the vault WebAssembly module for both the"
|
||||
@echo "Sonr blockchain plugin system and the @sonr.io/es package."
|
||||
@echo ""
|
||||
@echo "Available targets:"
|
||||
@echo " build - Build vault WASM module (default)"
|
||||
@echo " clean - Remove built WASM artifacts"
|
||||
@echo " test - Run vault tests"
|
||||
@echo " tidy - Tidy Go module dependencies"
|
||||
@echo " version - Display version information"
|
||||
@echo " verify - Build and verify the WASM modules"
|
||||
@echo " help - Show this help message"
|
||||
@echo ""
|
||||
@echo "Output locations:"
|
||||
@echo " Plugin: $(PLUGIN_PATH)"
|
||||
@echo " ES Package: $(ES_PATH)"
|
||||
@echo ""
|
||||
@echo "Integration:"
|
||||
@echo " The WASM module is built for two purposes:"
|
||||
@echo " 1. Plugin system in x/dwn/client/plugin"
|
||||
@echo " 2. ES package for browser distribution via jsDelivr"
|
||||
@echo ""
|
||||
@echo "Examples:"
|
||||
@echo " make build # Build WASM module to both locations"
|
||||
@echo " make verify # Build and verify both outputs"
|
||||
@echo " make clean # Remove all artifacts"
|
||||
@@ -0,0 +1,477 @@
|
||||
# Vault - WebAssembly Vault Plugin
|
||||
|
||||
Vault is a WebAssembly-based vault system for the Sonr blockchain that provides secure, isolated execution of cryptographic operations. Built using the Extism framework, Vault enables secure multi-party computation (MPC) and vault management within a sandboxed WebAssembly environment.
|
||||
|
||||
## Overview
|
||||
|
||||
Vault serves as a cryptographic vault system that:
|
||||
|
||||
- Provides secure enclave-based key generation and management
|
||||
- Supports multi-chain transaction signing (Cosmos, EVM)
|
||||
- Implements WebAuthn-based authentication
|
||||
- Offers secure import/export functionality via IPFS
|
||||
- Enables isolated execution through WebAssembly
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Components
|
||||
|
||||
- **MPC Enclave**: Multi-party computation system for secure key operations
|
||||
- **Vault Management**: Create, unlock, and manage cryptographic vaults
|
||||
- **IPFS Integration**: Secure backup and restore of encrypted vault data
|
||||
- **WebAuthn Support**: Passwordless authentication for vault operations
|
||||
- **Multi-Chain Support**: Transaction signing for different blockchain networks
|
||||
|
||||
### Build Configuration
|
||||
|
||||
Vault is built specifically for WebAssembly:
|
||||
|
||||
```go
|
||||
//go:build js && wasm
|
||||
// +build js,wasm
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Core Enclave Operations
|
||||
|
||||
#### `generate`
|
||||
|
||||
```go
|
||||
//go:wasmexport generate
|
||||
func generate() int32
|
||||
```
|
||||
|
||||
Creates a new MPC enclave and returns the enclave data and public key.
|
||||
|
||||
**Input**: `GenerateRequest`
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "string"
|
||||
}
|
||||
```
|
||||
|
||||
**Output**: `GenerateResponse`
|
||||
|
||||
```json
|
||||
{
|
||||
"data": "EnclaveData",
|
||||
"public_key": "[]byte"
|
||||
}
|
||||
```
|
||||
|
||||
#### `refresh`
|
||||
|
||||
```go
|
||||
//go:wasmexport refresh
|
||||
func refresh() int32
|
||||
```
|
||||
|
||||
Refreshes an existing enclave with new cryptographic material.
|
||||
|
||||
**Input**: `RefreshRequest`
|
||||
|
||||
```json
|
||||
{
|
||||
"enclave": "EnclaveData"
|
||||
}
|
||||
```
|
||||
|
||||
**Output**: `RefreshResponse`
|
||||
|
||||
```json
|
||||
{
|
||||
"okay": "bool",
|
||||
"data": "EnclaveData"
|
||||
}
|
||||
```
|
||||
|
||||
#### `sign`
|
||||
|
||||
```go
|
||||
//go:wasmexport sign
|
||||
func sign() int32
|
||||
```
|
||||
|
||||
Signs a message using the enclave's private key.
|
||||
|
||||
**Input**: `SignRequest`
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "[]byte",
|
||||
"enclave": "EnclaveData"
|
||||
}
|
||||
```
|
||||
|
||||
**Output**: `SignResponse`
|
||||
|
||||
```json
|
||||
{
|
||||
"signature": "[]byte"
|
||||
}
|
||||
```
|
||||
|
||||
#### `verify`
|
||||
|
||||
```go
|
||||
//go:wasmexport verify
|
||||
func verify() int32
|
||||
```
|
||||
|
||||
Verifies a signature against a message and public key.
|
||||
|
||||
**Input**: `VerifyRequest`
|
||||
|
||||
```json
|
||||
{
|
||||
"public_key": "[]byte",
|
||||
"message": "[]byte",
|
||||
"signature": "[]byte"
|
||||
}
|
||||
```
|
||||
|
||||
**Output**: `VerifyResponse`
|
||||
|
||||
```json
|
||||
{
|
||||
"valid": "bool"
|
||||
}
|
||||
```
|
||||
|
||||
### Vault Import/Export Operations
|
||||
|
||||
#### `export`
|
||||
|
||||
```go
|
||||
//go:wasmexport export
|
||||
func export() int32
|
||||
```
|
||||
|
||||
Encrypts and exports vault data to IPFS, returning a Content ID (CID).
|
||||
|
||||
**Input**: `ExportRequest`
|
||||
|
||||
```json
|
||||
{
|
||||
"enclave": "EnclaveData",
|
||||
"password": "[]byte"
|
||||
}
|
||||
```
|
||||
|
||||
**Output**: `ExportResponse`
|
||||
|
||||
```json
|
||||
{
|
||||
"cid": "string",
|
||||
"success": "bool"
|
||||
}
|
||||
```
|
||||
|
||||
#### `import`
|
||||
|
||||
```go
|
||||
//go:wasmexport import
|
||||
func importVault() int32
|
||||
```
|
||||
|
||||
Retrieves and decrypts vault data from IPFS using a CID and password.
|
||||
|
||||
**Input**: `ImportRequest`
|
||||
|
||||
```json
|
||||
{
|
||||
"cid": "string",
|
||||
"password": "[]byte"
|
||||
}
|
||||
```
|
||||
|
||||
**Output**: `ImportResponse`
|
||||
|
||||
```json
|
||||
{
|
||||
"enclave": "EnclaveData",
|
||||
"success": "bool"
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced Vault Operations
|
||||
|
||||
#### `create_vault_enclave`
|
||||
|
||||
```go
|
||||
//go:wasmexport create_vault_enclave
|
||||
func createVaultEnclave() int32
|
||||
```
|
||||
|
||||
Creates a new vault enclave with advanced configuration options.
|
||||
|
||||
**Input**: `EnclaveConfig`
|
||||
|
||||
```json
|
||||
{
|
||||
"vault_id": "string",
|
||||
"key_derivation_method": "string",
|
||||
"encryption_algorithm": "string",
|
||||
"signing_algorithm": "string",
|
||||
"webauthn_enabled": "bool",
|
||||
"auto_lock_timeout": "int64",
|
||||
"key_rotation_interval": "int64",
|
||||
"supported_chains": ["string"],
|
||||
"max_concurrent_ops": "int",
|
||||
"memory_limit": "uint64"
|
||||
}
|
||||
```
|
||||
|
||||
#### `unlock_vault_enclave`
|
||||
|
||||
```go
|
||||
//go:wasmexport unlock_vault_enclave
|
||||
func unlockVaultEnclave() int32
|
||||
```
|
||||
|
||||
Unlocks a vault enclave, optionally using WebAuthn authentication.
|
||||
|
||||
#### `lock_vault_enclave`
|
||||
|
||||
```go
|
||||
//go:wasmexport lock_vault_enclave
|
||||
func lockVaultEnclave() int32
|
||||
```
|
||||
|
||||
Locks a vault enclave to prevent unauthorized access.
|
||||
|
||||
#### `rotate_vault_key`
|
||||
|
||||
```go
|
||||
//go:wasmexport rotate_vault_key
|
||||
func rotateVaultKey() int32
|
||||
```
|
||||
|
||||
Rotates the cryptographic keys within a vault enclave.
|
||||
|
||||
### Multi-Chain Transaction Signing
|
||||
|
||||
#### `sign_cosmos_transaction`
|
||||
|
||||
```go
|
||||
//go:wasmexport sign_cosmos_transaction
|
||||
func signCosmosTransaction() int32
|
||||
```
|
||||
|
||||
Signs transactions for Cosmos SDK-based blockchains.
|
||||
|
||||
#### `sign_evm_transaction`
|
||||
|
||||
```go
|
||||
//go:wasmexport sign_evm_transaction
|
||||
func signEvmTransaction() int32
|
||||
```
|
||||
|
||||
Signs transactions for Ethereum Virtual Machine compatible chains.
|
||||
|
||||
#### `sign_message`
|
||||
|
||||
```go
|
||||
//go:wasmexport sign_message
|
||||
func signMessage() int32
|
||||
```
|
||||
|
||||
Signs arbitrary messages using the vault's private key.
|
||||
|
||||
### Health and Monitoring
|
||||
|
||||
#### `get_vault_health`
|
||||
|
||||
```go
|
||||
//go:wasmexport get_vault_health
|
||||
func getVaultHealth() int32
|
||||
```
|
||||
|
||||
Returns the health status of a vault enclave.
|
||||
|
||||
**Output**: `EnclaveHealth`
|
||||
|
||||
```json
|
||||
{
|
||||
"vault_id": "string",
|
||||
"status": "string",
|
||||
"last_activity": "int64",
|
||||
"key_rotation_due": "bool",
|
||||
"attestation_valid": "bool"
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Motor supports configuration through Extism variables:
|
||||
|
||||
- `chain_id`: Blockchain network identifier (default: "sonr-testnet-1")
|
||||
- `password`: Default password for enclave operations (default: "password")
|
||||
- `gateway`: IPFS gateway URL (default: "https://ipfs.did.run/ipfs/")
|
||||
|
||||
Access these via helper functions:
|
||||
|
||||
```go
|
||||
func GetChainID() string
|
||||
func GetPassword() []byte
|
||||
func GetGateway() string
|
||||
```
|
||||
|
||||
### IPFS Integration
|
||||
|
||||
Motor integrates with IPFS for secure vault backup and restore:
|
||||
|
||||
- **Storage Endpoint**: `http://127.0.0.1:5001/api/v0/add`
|
||||
- **Retrieval Endpoint**: `http://127.0.0.1:5001/api/v0/cat`
|
||||
- **Data Format**: Encrypted vault data stored as content-addressed objects
|
||||
- **Security**: All vault data is encrypted before IPFS storage
|
||||
|
||||
## Security Features
|
||||
|
||||
### Enclave Isolation
|
||||
|
||||
- WebAssembly sandbox provides memory isolation
|
||||
- Secure execution environment prevents side-channel attacks
|
||||
- Attestation mechanisms ensure enclave integrity
|
||||
|
||||
### Authentication
|
||||
|
||||
- WebAuthn support for passwordless authentication
|
||||
- Challenge-response authentication flows
|
||||
- Automatic vault locking with configurable timeouts
|
||||
|
||||
### Key Management
|
||||
|
||||
- Multi-party computation for enhanced security
|
||||
- Automatic key rotation with configurable intervals
|
||||
- Secure key derivation and storage
|
||||
|
||||
### Data Protection
|
||||
|
||||
- AES encryption for sensitive data
|
||||
- Password-based encryption for import/export
|
||||
- Secure memory handling within WASM environment
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Basic Enclave Operations
|
||||
|
||||
```javascript
|
||||
// Generate new enclave
|
||||
const generateReq = { id: "my-vault" };
|
||||
const result = call_wasm_function("generate", generateReq);
|
||||
|
||||
// Sign a message
|
||||
const signReq = {
|
||||
message: new Uint8Array([1, 2, 3, 4]),
|
||||
enclave: result.data,
|
||||
};
|
||||
const signature = call_wasm_function("sign", signReq);
|
||||
```
|
||||
|
||||
### Vault Management
|
||||
|
||||
```javascript
|
||||
// Create vault with configuration
|
||||
const config = {
|
||||
vault_id: "user-vault-001",
|
||||
webauthn_enabled: true,
|
||||
auto_lock_timeout: 300,
|
||||
supported_chains: ["cosmos", "ethereum"],
|
||||
};
|
||||
const vault = call_wasm_function("create_vault_enclave", config);
|
||||
|
||||
// Sign Cosmos transaction
|
||||
const cosmosReq = {
|
||||
vault_id: "user-vault-001",
|
||||
chain_type: "cosmos",
|
||||
chain_id: "cosmoshub-4",
|
||||
message: transactionBytes,
|
||||
};
|
||||
const cosmosResult = call_wasm_function("sign_cosmos_transaction", cosmosReq);
|
||||
```
|
||||
|
||||
### Import/Export Operations
|
||||
|
||||
```javascript
|
||||
// Export vault to IPFS
|
||||
const exportReq = {
|
||||
enclave: vaultData,
|
||||
password: new Uint8Array([
|
||||
/* password bytes */
|
||||
]),
|
||||
};
|
||||
const exportResult = call_wasm_function("export", exportReq);
|
||||
console.log("Vault exported to CID:", exportResult.cid);
|
||||
|
||||
// Import vault from IPFS
|
||||
const importReq = {
|
||||
cid: "QmXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx",
|
||||
password: new Uint8Array([
|
||||
/* password bytes */
|
||||
]),
|
||||
};
|
||||
const importResult = call_wasm_function("import", importReq);
|
||||
```
|
||||
|
||||
## Building and Deployment
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Go 1.24.4+
|
||||
- Extism runtime
|
||||
- IPFS node (for import/export functionality)
|
||||
|
||||
### Build Commands
|
||||
|
||||
```bash
|
||||
# Build WebAssembly module
|
||||
GOOS=js GOARCH=wasm go build -o motr.wasm main.go
|
||||
|
||||
# Build via Makefile
|
||||
make motr
|
||||
```
|
||||
|
||||
### Integration
|
||||
|
||||
Motor is designed to be integrated with:
|
||||
|
||||
- **Highway Service**: PostgreSQL-backed HTTP API
|
||||
- **Sonr Blockchain**: Cosmos SDK-based blockchain node
|
||||
- **IPFS Network**: Decentralized storage system
|
||||
- **WebAuthn Infrastructure**: Passwordless authentication
|
||||
|
||||
## Error Handling
|
||||
|
||||
All functions return `int32` status codes:
|
||||
|
||||
- `0`: Success
|
||||
- `1`: Error (details available via `pdk.SetError`)
|
||||
|
||||
Error information is logged using Extism's logging system:
|
||||
|
||||
```go
|
||||
pdk.Log(pdk.LogError, "Error message")
|
||||
pdk.Log(pdk.LogInfo, "Info message")
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Core Dependencies
|
||||
|
||||
- `github.com/extism/go-pdk`: WebAssembly plugin development kit
|
||||
- `github.com/sonr-io/sonr/crypto/mpc`: Multi-party computation library
|
||||
|
||||
### Cryptographic Libraries
|
||||
|
||||
- `filippo.io/edwards25519`: Edwards25519 elliptic curve
|
||||
- `github.com/btcsuite/btcd/btcec/v2`: Bitcoin cryptography
|
||||
- `github.com/consensys/gnark-crypto`: Zero-knowledge proof cryptography
|
||||
|
||||
## License
|
||||
|
||||
Motor is part of the Sonr blockchain project. See the project's main license for terms and conditions.
|
||||
@@ -0,0 +1,26 @@
|
||||
module vault
|
||||
|
||||
go 1.24.7
|
||||
|
||||
replace github.com/sonr-io/sonr/crypto => ../../crypto/
|
||||
|
||||
require (
|
||||
github.com/extism/go-pdk v1.1.3
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||
github.com/sonr-io/sonr/crypto v0.0.0-00010101000000-000000000000
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.24.0 // indirect
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
|
||||
github.com/bwesterb/go-ristretto v1.2.3 // indirect
|
||||
github.com/consensys/gnark-crypto v0.19.0 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
||||
github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564 // indirect
|
||||
github.com/gtank/merlin v0.1.1 // indirect
|
||||
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
golang.org/x/crypto v0.42.0 // indirect
|
||||
golang.org/x/sys v0.36.0 // indirect
|
||||
)
|
||||
@@ -0,0 +1,38 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/bits-and-blooms/bitset v1.24.0 h1:H4x4TuulnokZKvHLfzVRTHJfFfnHEeSYJizujEZvmAM=
|
||||
github.com/bits-and-blooms/bitset v1.24.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
|
||||
github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/consensys/gnark-crypto v0.19.0 h1:zXCqeY2txSaMl6G5wFpZzMWJU9HPNh8qxPnYJ1BL9vA=
|
||||
github.com/consensys/gnark-crypto v0.19.0/go.mod h1:rT23F0XSZqE0mUA0+pRtnL56IbPxs6gp4CeRsBk4XS0=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
|
||||
github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564 h1:I6KUy4CI6hHjqnyJLNCEi7YHVMkwwtfSr2k9splgdSM=
|
||||
github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564/go.mod h1:yekO+3ZShy19S+bsmnERmznGy9Rfg6dWWWpiGJjNAz8=
|
||||
github.com/extism/go-pdk v1.1.3 h1:hfViMPWrqjN6u67cIYRALZTZLk/enSPpNKa+rZ9X2SQ=
|
||||
github.com/extism/go-pdk v1.1.3/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is=
|
||||
github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s=
|
||||
github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4=
|
||||
github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c=
|
||||
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0=
|
||||
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -0,0 +1,483 @@
|
||||
//go:build js && wasm
|
||||
// +build js,wasm
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/extism/go-pdk"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/sonr-io/sonr/crypto/mpc"
|
||||
)
|
||||
|
||||
const (
|
||||
KeyChainID = "chain_id"
|
||||
KeyEnclave = "enclave"
|
||||
KeyVaultConfig = "vault_config"
|
||||
)
|
||||
|
||||
// GetChainID returns the chain ID to use for unlocking the enclave
|
||||
func GetChainID() string {
|
||||
v := pdk.GetVar(KeyChainID)
|
||||
if v == nil {
|
||||
return "sonr-testnet-1"
|
||||
}
|
||||
return string(v)
|
||||
}
|
||||
|
||||
// GetEnclaveData loads MPC enclave data from PDK environment
|
||||
func GetEnclaveData() (*mpc.EnclaveData, error) {
|
||||
v := pdk.GetVar(KeyEnclave)
|
||||
if v == nil {
|
||||
return nil, fmt.Errorf("enclave data not provided in environment")
|
||||
}
|
||||
|
||||
var data mpc.EnclaveData
|
||||
if err := json.Unmarshal(v, &data); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal enclave data: %w", err)
|
||||
}
|
||||
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
// GetVaultConfig loads vault configuration from PDK environment
|
||||
func GetVaultConfig() map[string]any {
|
||||
v := pdk.GetVar(KeyVaultConfig)
|
||||
if v == nil {
|
||||
return make(map[string]any)
|
||||
}
|
||||
|
||||
var config map[string]any
|
||||
if err := json.Unmarshal(v, &config); err != nil {
|
||||
pdk.Log(pdk.LogWarn, fmt.Sprintf("Failed to parse vault config: %v", err))
|
||||
return make(map[string]any)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// UCAN Token Request/Response types
|
||||
type NewOriginTokenRequest struct {
|
||||
AudienceDID string `json:"audience_did"`
|
||||
Attenuations []map[string]any `json:"attenuations,omitempty"`
|
||||
Facts []string `json:"facts,omitempty"`
|
||||
NotBefore int64 `json:"not_before,omitempty"`
|
||||
ExpiresAt int64 `json:"expires_at,omitempty"`
|
||||
}
|
||||
|
||||
type NewAttenuatedTokenRequest struct {
|
||||
ParentToken string `json:"parent_token"`
|
||||
AudienceDID string `json:"audience_did"`
|
||||
Attenuations []map[string]any `json:"attenuations,omitempty"`
|
||||
Facts []string `json:"facts,omitempty"`
|
||||
NotBefore int64 `json:"not_before,omitempty"`
|
||||
ExpiresAt int64 `json:"expires_at,omitempty"`
|
||||
}
|
||||
|
||||
type UCANTokenResponse struct {
|
||||
Token string `json:"token"`
|
||||
Issuer string `json:"issuer"`
|
||||
Address string `json:"address"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type SignDataRequest struct {
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
|
||||
type SignDataResponse struct {
|
||||
Signature []byte `json:"signature"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type VerifyDataRequest struct {
|
||||
Data []byte `json:"data"`
|
||||
Signature []byte `json:"signature"`
|
||||
}
|
||||
|
||||
type VerifyDataResponse struct {
|
||||
Valid bool `json:"valid"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type GetIssuerDIDResponse struct {
|
||||
IssuerDID string `json:"issuer_did"`
|
||||
Address string `json:"address"`
|
||||
ChainCode string `json:"chain_code"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
var (
|
||||
enclave mpc.Enclave
|
||||
issuerDID string
|
||||
address string
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Initialize MPC enclave from PDK environment
|
||||
if err := initializeEnclave(); err != nil {
|
||||
pdk.SetError(fmt.Errorf("failed to initialize enclave: %w", err))
|
||||
return
|
||||
}
|
||||
pdk.Log(pdk.LogInfo, "Motor plugin initialized as MPC-based UCAN source")
|
||||
}
|
||||
|
||||
// initializeEnclave initializes the MPC enclave from PDK environment
|
||||
func initializeEnclave() error {
|
||||
// Load enclave data from PDK environment
|
||||
enclaveData, err := GetEnclaveData()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get enclave data: %w", err)
|
||||
}
|
||||
|
||||
// Import MPC enclave from data
|
||||
enclave, err = mpc.ImportEnclave(mpc.WithEnclaveData(enclaveData))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to import enclave: %w", err)
|
||||
}
|
||||
|
||||
// Derive issuer DID and address from enclave public key
|
||||
pubKeyBytes := enclave.PubKeyBytes()
|
||||
issuerDID, address, err = deriveIssuerDIDFromBytes(pubKeyBytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to derive issuer DID: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//go:wasmexport new_origin_token
|
||||
func newOriginToken() int32 {
|
||||
if !enclave.IsValid() {
|
||||
pdk.SetError(fmt.Errorf("enclave not initialized"))
|
||||
return 1
|
||||
}
|
||||
|
||||
req := &NewOriginTokenRequest{}
|
||||
err := pdk.InputJSON(req)
|
||||
if err != nil {
|
||||
pdk.SetError(fmt.Errorf("failed to parse request: %w", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Convert timestamps
|
||||
var notBefore, expiresAt time.Time
|
||||
if req.NotBefore > 0 {
|
||||
notBefore = time.Unix(req.NotBefore, 0)
|
||||
}
|
||||
if req.ExpiresAt > 0 {
|
||||
expiresAt = time.Unix(req.ExpiresAt, 0)
|
||||
}
|
||||
|
||||
// Create origin token using MPC signing
|
||||
tokenString, err := createUCANToken(
|
||||
req.AudienceDID,
|
||||
nil,
|
||||
req.Attenuations,
|
||||
req.Facts,
|
||||
notBefore,
|
||||
expiresAt,
|
||||
)
|
||||
if err != nil {
|
||||
resp := &UCANTokenResponse{Error: err.Error()}
|
||||
pdk.OutputJSON(resp)
|
||||
return 1
|
||||
}
|
||||
|
||||
resp := &UCANTokenResponse{
|
||||
Token: tokenString,
|
||||
Issuer: issuerDID,
|
||||
Address: address,
|
||||
}
|
||||
pdk.OutputJSON(resp)
|
||||
return 0
|
||||
}
|
||||
|
||||
//go:wasmexport new_attenuated_token
|
||||
func newAttenuatedToken() int32 {
|
||||
if !enclave.IsValid() {
|
||||
pdk.SetError(fmt.Errorf("enclave not initialized"))
|
||||
return 1
|
||||
}
|
||||
|
||||
req := &NewAttenuatedTokenRequest{}
|
||||
err := pdk.InputJSON(req)
|
||||
if err != nil {
|
||||
pdk.SetError(fmt.Errorf("failed to parse request: %w", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Convert timestamps
|
||||
var notBefore, expiresAt time.Time
|
||||
if req.NotBefore > 0 {
|
||||
notBefore = time.Unix(req.NotBefore, 0)
|
||||
}
|
||||
if req.ExpiresAt > 0 {
|
||||
expiresAt = time.Unix(req.ExpiresAt, 0)
|
||||
}
|
||||
|
||||
// Create proofs from parent token
|
||||
proofs := []string{req.ParentToken}
|
||||
|
||||
// Create attenuated token using MPC signing
|
||||
tokenString, err := createUCANToken(
|
||||
req.AudienceDID,
|
||||
proofs,
|
||||
req.Attenuations,
|
||||
req.Facts,
|
||||
notBefore,
|
||||
expiresAt,
|
||||
)
|
||||
if err != nil {
|
||||
resp := &UCANTokenResponse{Error: err.Error()}
|
||||
pdk.OutputJSON(resp)
|
||||
return 1
|
||||
}
|
||||
|
||||
resp := &UCANTokenResponse{
|
||||
Token: tokenString,
|
||||
Issuer: issuerDID,
|
||||
Address: address,
|
||||
}
|
||||
pdk.OutputJSON(resp)
|
||||
return 0
|
||||
}
|
||||
|
||||
//go:wasmexport sign_data
|
||||
func signData() int32 {
|
||||
if !enclave.IsValid() {
|
||||
pdk.SetError(fmt.Errorf("enclave not initialized"))
|
||||
return 1
|
||||
}
|
||||
|
||||
req := &SignDataRequest{}
|
||||
err := pdk.InputJSON(req)
|
||||
if err != nil {
|
||||
pdk.SetError(fmt.Errorf("failed to parse request: %w", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Sign data using MPC enclave
|
||||
signature, err := enclave.Sign(req.Data)
|
||||
if err != nil {
|
||||
resp := &SignDataResponse{Error: err.Error()}
|
||||
pdk.OutputJSON(resp)
|
||||
return 1
|
||||
}
|
||||
|
||||
resp := &SignDataResponse{Signature: signature}
|
||||
pdk.OutputJSON(resp)
|
||||
return 0
|
||||
}
|
||||
|
||||
//go:wasmexport verify_data
|
||||
func verifyData() int32 {
|
||||
if !enclave.IsValid() {
|
||||
pdk.SetError(fmt.Errorf("enclave not initialized"))
|
||||
return 1
|
||||
}
|
||||
|
||||
req := &VerifyDataRequest{}
|
||||
err := pdk.InputJSON(req)
|
||||
if err != nil {
|
||||
pdk.SetError(fmt.Errorf("failed to parse request: %w", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Verify data using MPC enclave
|
||||
valid, err := enclave.Verify(req.Data, req.Signature)
|
||||
if err != nil {
|
||||
resp := &VerifyDataResponse{Error: err.Error()}
|
||||
pdk.OutputJSON(resp)
|
||||
return 1
|
||||
}
|
||||
|
||||
resp := &VerifyDataResponse{Valid: valid}
|
||||
pdk.OutputJSON(resp)
|
||||
return 0
|
||||
}
|
||||
|
||||
//go:wasmexport get_issuer_did
|
||||
func getIssuerDID() int32 {
|
||||
if !enclave.IsValid() {
|
||||
pdk.SetError(fmt.Errorf("enclave not initialized"))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Get chain code for deterministic derivation
|
||||
chainCode, err := getChainCode()
|
||||
if err != nil {
|
||||
resp := &GetIssuerDIDResponse{Error: err.Error()}
|
||||
pdk.OutputJSON(resp)
|
||||
return 1
|
||||
}
|
||||
|
||||
resp := &GetIssuerDIDResponse{
|
||||
IssuerDID: issuerDID,
|
||||
Address: address,
|
||||
ChainCode: fmt.Sprintf("%x", chainCode),
|
||||
}
|
||||
pdk.OutputJSON(resp)
|
||||
return 0
|
||||
}
|
||||
|
||||
// UCAN token creation and MPC signing implementation
|
||||
|
||||
// MPCSigningMethod implements JWT signing using MPC enclaves
|
||||
type MPCSigningMethod struct {
|
||||
Name string
|
||||
enclave mpc.Enclave
|
||||
}
|
||||
|
||||
// Alg returns the signing method algorithm name
|
||||
func (m *MPCSigningMethod) Alg() string {
|
||||
return m.Name
|
||||
}
|
||||
|
||||
// Sign signs a JWT string using the MPC enclave
|
||||
func (m *MPCSigningMethod) Sign(signingString string, key any) ([]byte, error) {
|
||||
// Hash the signing string
|
||||
hasher := sha256.New()
|
||||
hasher.Write([]byte(signingString))
|
||||
digest := hasher.Sum(nil)
|
||||
|
||||
// Use MPC enclave to sign the digest
|
||||
sig, err := m.enclave.Sign(digest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to sign with MPC: %w", err)
|
||||
}
|
||||
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
// Verify verifies a JWT signature using the MPC enclave
|
||||
func (m *MPCSigningMethod) Verify(signingString string, sig []byte, key any) error {
|
||||
// Hash the signing string
|
||||
hasher := sha256.New()
|
||||
hasher.Write([]byte(signingString))
|
||||
digest := hasher.Sum(nil)
|
||||
|
||||
// Use MPC enclave to verify signature
|
||||
valid, err := m.enclave.Verify(digest, sig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to verify signature: %w", err)
|
||||
}
|
||||
|
||||
if !valid {
|
||||
return fmt.Errorf("signature verification failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createUCANToken creates a UCAN token using MPC signing
|
||||
func createUCANToken(
|
||||
audienceDID string,
|
||||
proofs []string,
|
||||
attenuations []map[string]any,
|
||||
facts []string,
|
||||
notBefore, expiresAt time.Time,
|
||||
) (string, error) {
|
||||
// Validate audience DID
|
||||
if audienceDID == "" {
|
||||
return "", fmt.Errorf("audience DID is required")
|
||||
}
|
||||
|
||||
// Create MPC signing method
|
||||
signingMethod := &MPCSigningMethod{
|
||||
Name: "MPC256",
|
||||
enclave: enclave,
|
||||
}
|
||||
|
||||
// Create JWT token
|
||||
token := jwt.New(signingMethod)
|
||||
|
||||
// Set UCAN version in header
|
||||
token.Header["ucv"] = "0.9.0"
|
||||
|
||||
// Prepare time claims
|
||||
var nbfUnix, expUnix int64
|
||||
if !notBefore.IsZero() {
|
||||
nbfUnix = notBefore.Unix()
|
||||
}
|
||||
if !expiresAt.IsZero() {
|
||||
expUnix = expiresAt.Unix()
|
||||
}
|
||||
|
||||
// Set claims
|
||||
claims := jwt.MapClaims{
|
||||
"iss": issuerDID,
|
||||
"aud": audienceDID,
|
||||
}
|
||||
|
||||
// Add attenuations if provided
|
||||
if len(attenuations) > 0 {
|
||||
claims["att"] = attenuations
|
||||
}
|
||||
|
||||
// Add proofs if provided
|
||||
if len(proofs) > 0 {
|
||||
claims["prf"] = proofs
|
||||
}
|
||||
|
||||
// Add facts if provided
|
||||
if len(facts) > 0 {
|
||||
claims["fct"] = facts
|
||||
}
|
||||
|
||||
// Add time claims
|
||||
if nbfUnix > 0 {
|
||||
claims["nbf"] = nbfUnix
|
||||
}
|
||||
if expUnix > 0 {
|
||||
claims["exp"] = expUnix
|
||||
}
|
||||
|
||||
token.Claims = claims
|
||||
|
||||
// Sign the token using MPC enclave (key parameter is ignored for MPC signing)
|
||||
tokenString, err := token.SignedString(nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to sign token with MPC: %w", err)
|
||||
}
|
||||
|
||||
return tokenString, nil
|
||||
}
|
||||
|
||||
// deriveIssuerDIDFromBytes creates issuer DID and address from public key bytes
|
||||
func deriveIssuerDIDFromBytes(pubKeyBytes []byte) (string, string, error) {
|
||||
if len(pubKeyBytes) == 0 {
|
||||
return "", "", fmt.Errorf("empty public key bytes")
|
||||
}
|
||||
|
||||
// Generate address from public key (simplified implementation)
|
||||
address := fmt.Sprintf("sonr1%x", pubKeyBytes[:20])
|
||||
|
||||
// Create DID from address (simplified implementation)
|
||||
issuerDID := fmt.Sprintf("did:sonr:%s", address)
|
||||
|
||||
return issuerDID, address, nil
|
||||
}
|
||||
|
||||
// getChainCode derives a deterministic chain code from the enclave
|
||||
func getChainCode() ([]byte, error) {
|
||||
if !enclave.IsValid() {
|
||||
return nil, fmt.Errorf("enclave is not valid")
|
||||
}
|
||||
|
||||
// Sign the address to create a deterministic chain code
|
||||
sig, err := enclave.Sign([]byte(address))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to sign address for chain code: %w", err)
|
||||
}
|
||||
|
||||
// Hash the signature to create a 32-byte chain code
|
||||
hasher := sha256.New()
|
||||
hasher.Write(sig)
|
||||
hash := hasher.Sum(nil)
|
||||
|
||||
return hash[:32], nil
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package main
|
||||
|
||||
// Version is set by commitizen during release process
|
||||
var Version = "dev"
|
||||
Reference in New Issue
Block a user