Authentication and Cryptographic Signing
Comprehensive guide to authentication, request signing, and cryptographic security in the Fractal Engine system
The Fractal Engine implements a robust cryptographic authentication system based on Dogecoin's ECDSA signature scheme. All authenticated requests must be signed with valid Dogecoin private keys and verified using the corresponding public keys.
Security Model Overview
The authentication system is built on the following principles:
- Public Key Cryptography: Uses secp256k1 elliptic curve (same as Bitcoin/Dogecoin)
- Message Signing: All payloads are signed using ECDSA with SHA256 hashing
- Request Validation: Server validates signatures against public keys and message payloads
- Address Binding: Public keys must correspond to valid Dogecoin addresses
- Replay Protection: Each request includes unique payload data preventing replay attacks
Security Architecture
Cryptographic Components
Key Generation
The system uses secp256k1 elliptic curve cryptography for key generation:
// Generate a new Dogecoin keypair
privHex, pubHex, address, err := doge.GenerateDogecoinKeypair(prefix)
if err != nil {
return err
}
// prefix values:
// 0x1E - Mainnet
// 0x71 - Testnet
// 0x6f - RegtestMessage Signing Process
All request payloads are signed using the following process:
- Payload Serialization: Request payload is marshaled to JSON
- SHA256 Hashing: Payload bytes are hashed using SHA256
- ECDSA Signing: Hash is signed with private key using ECDSA
- DER Encoding: Signature is encoded in DER format
- Hex Encoding: DER signature is converted to hexadecimal string
func SignPayload(payload []byte, privHex string) (string, error) {
// Decode private key from hex
privBytes, err := hex.DecodeString(privHex)
if err != nil {
return "", err
}
privKey, _ := btcec.PrivKeyFromBytes(privBytes)
// Hash the payload using SHA256
hash := sha256.Sum256(payload)
// Sign the hash using ECDSA
signature := ecdsa.Sign(privKey, hash[:])
// Encode signature as DER, then to hex
sigDER := signature.Serialize()
sigHex := hex.EncodeToString(sigDER)
return sigHex, nil
}Signature Verification
The server validates signatures using the following process:
- Public Key Validation: Verify public key format (66-character compressed hex)
- Payload Hashing: Hash the request payload with SHA256
- Signature Decoding: Decode hex signature to DER format
- ECDSA Verification: Verify signature against hash and public key
- Address Validation: Ensure public key corresponds to a valid Dogecoin address
func ValidateSignature(payload []byte, publicKey string, signature string) error {
// Hash message with SHA256
hash := sha256.Sum256(payload)
// Decode and parse public key
pubKeyBytes, err := hex.DecodeString(publicKey)
if err != nil {
return errors.New("invalid public key format")
}
pubKey, err := btcec.ParsePubKey(pubKeyBytes)
if err != nil {
return errors.New("failed to parse public key")
}
// Decode and parse signature
sigBytes, err := hex.DecodeString(signature)
if err != nil {
return errors.New("invalid signature encoding")
}
sig, err := ecdsa.ParseDERSignature(sigBytes)
if err != nil {
return errors.New("failed to parse DER signature")
}
// Verify signature
if !sig.Verify(hash[:], pubKey) {
return errors.New("signature verification failed")
}
return nil
}Request Authentication Flow
Signed Request Structure
All authenticated requests follow this structure:
{
"public_key": "03a1b2c3d4e5f6789abcdef...", // 66-char compressed public key
"signature": "304402204a1b2c3d4e5f...", // DER-encoded ECDSA signature
"payload": {
// Request-specific data
}
}Authentication Process
Step 1: Prepare Payload
payload := CreateInvoiceRequestPayload{
PaymentAddress: "DPaymentAddress123",
BuyerAddress: "DBuyerAddress456",
MintHash: "abc123...",
Quantity: 100,
Price: 50000,
SellerAddress: "DSellerAddress789",
}Step 2: Serialize to JSON
payloadBytes, err := json.Marshal(payload)
if err != nil {
return err
}Step 3: Sign Payload
signature, err := doge.SignPayload(payloadBytes, privateKeyHex)
if err != nil {
return err
}Step 4: Create Signed Request
request := CreateInvoiceRequest{
SignedRequest: SignedRequest{
PublicKey: publicKeyHex,
Signature: signature,
},
Payload: payload,
}Step 1: Validate Public Key Format
if err := validation.ValidatePublicKey(req.PublicKey); err != nil {
return fmt.Errorf("invalid public_key: %w", err)
}Step 2: Serialize Payload for Verification
payloadBytes, err := json.Marshal(req.Payload)
if err != nil {
return fmt.Errorf("invalid payload: %w", err)
}Step 3: Validate Signature
if err := req.ValidateSignature(payloadBytes); err != nil {
return err
}Step 4: Process Authenticated Request
// Request is now authenticated and can be processedMessage Formatting Standards
Payload Serialization
All payloads must be serialized to JSON in a consistent manner:
- Deterministic Ordering: JSON fields should maintain consistent ordering
- No Pretty Printing: Compact JSON without extra whitespace
- UTF-8 Encoding: All strings must be valid UTF-8
- No Null Values: Omit fields rather than including null values
Signature Format
Signatures follow strict formatting requirements:
- Encoding: DER format encoded as hexadecimal
- Case: Lowercase hexadecimal characters
- Length: Variable length (typically 140-144 characters)
- Validation: Must parse as valid DER signature
Public Key Format
Public keys must conform to compressed format:
- Length: Exactly 66 characters
- Encoding: Hexadecimal (lowercase)
- Compression: Compressed secp256k1 public key
- Prefix: Starts with
02or03
Key Management Best Practices
Secure Storage
The CLI uses system keyring for secure private key storage:
// Store private key securely
store := keys.NewSecureStore()
store.Save(label+"_private_key", privHex)
store.Save(label+"_public_key", pubHex)
store.Save(label+"_address", address)Key Rotation
Regular key rotation is recommended:
- Generate New Keypair: Create new keys for sensitive operations
- Transfer Assets: Move tokens to new addresses
- Update Applications: Configure new keys in client applications
- Revoke Old Keys: Remove old keys from secure storage
Backup and Recovery
- Secure Backup: Store private keys in encrypted backups
- Multiple Locations: Use geographically distributed storage
- Test Recovery: Regularly test backup restoration procedures
- Access Control: Limit access to backup systems
Security Considerations
Threat Model
The authentication system protects against:
- Message Tampering: Signatures prevent payload modification
- Impersonation: Public key cryptography prevents identity spoofing
- Replay Attacks: Unique payload data prevents request reuse
- Man-in-the-Middle: HTTPS transport protects signature transmission
Attack Vectors
Be aware of potential security risks:
- Private Key Compromise: Secure key storage is critical
- Side-Channel Attacks: Use constant-time cryptographic operations
- Weak Random Numbers: Ensure proper entropy for key generation
- Implementation Bugs: Regular security audits recommended
Validation Layers
The system implements multiple validation layers:
- Format Validation: Public keys, addresses, and signatures format checks
- Cryptographic Validation: ECDSA signature mathematical verification
- Business Logic Validation: Request-specific validation rules
- Rate Limiting: Protection against abuse and DoS attacks
Code Examples
Go Client Implementation
package main
import (
"encoding/json"
"fmt"
"log"
"dogecoin.org/fractal-engine/pkg/doge"
"dogecoin.org/fractal-engine/pkg/rpc"
)
func signRequest() {
// Your private and public keys
privateKey := "your_private_key_hex"
publicKey := "your_public_key_hex"
// Create payload
payload := rpc.CreateInvoiceRequestPayload{
PaymentAddress: "DPaymentAddress123",
BuyerAddress: "DBuyerAddress456",
MintHash: "abc123def456...",
Quantity: 100,
Price: 50000,
SellerAddress: "DSellerAddress789",
}
// Serialize payload
payloadBytes, err := json.Marshal(payload)
if err != nil {
log.Fatal(err)
}
// Sign payload
signature, err := doge.SignPayload(payloadBytes, privateKey)
if err != nil {
log.Fatal(err)
}
// Create signed request
request := rpc.CreateInvoiceRequest{
SignedRequest: rpc.SignedRequest{
PublicKey: publicKey,
Signature: signature,
},
Payload: payload,
}
fmt.Printf("Signed request: %+v\n", request)
}package main
import (
"log"
"dogecoin.org/fractal-engine/pkg/client"
"dogecoin.org/fractal-engine/pkg/rpc"
)
func useClientLibrary() {
// Initialize client with your keys
client := client.NewTokenisationClient(
"https://api.fractalengine.com",
"your_private_key_hex",
"your_public_key_hex",
)
// Create invoice request
invoiceReq := &rpc.CreateInvoiceRequest{
Payload: rpc.CreateInvoiceRequestPayload{
PaymentAddress: "DPaymentAddress123",
BuyerAddress: "DBuyerAddress456",
MintHash: "abc123def456...",
Quantity: 100,
Price: 50000,
SellerAddress: "DSellerAddress789",
},
}
// Client automatically signs the request
response, err := client.CreateInvoice(invoiceReq)
if err != nil {
log.Fatal(err)
}
log.Printf("Invoice created: %s", response.Hash)
}package main
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"log"
"dogecoin.org/fractal-engine/pkg/doge"
"dogecoin.org/fractal-engine/pkg/validation"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
)
func advancedSigning() {
// Generate new keypair
privKey, err := btcec.NewPrivateKey()
if err != nil {
log.Fatal(err)
}
pubKey := privKey.PubKey()
pubKeyHex := hex.EncodeToString(pubKey.SerializeCompressed())
privKeyHex := hex.EncodeToString(privKey.Serialize())
// Validate public key format
if err := validation.ValidatePublicKey(pubKeyHex); err != nil {
log.Fatal(err)
}
// Create and sign payload
payload := map[string]interface{}{
"action": "custom_action",
"data": "some_data",
"nonce": "unique_nonce_123",
}
payloadBytes, err := json.Marshal(payload)
if err != nil {
log.Fatal(err)
}
// Manual signing process
hash := sha256.Sum256(payloadBytes)
signature := ecdsa.Sign(privKey, hash[:])
sigHex := hex.EncodeToString(signature.Serialize())
// Verify signature
err = doge.ValidateSignature(payloadBytes, pubKeyHex, sigHex)
if err != nil {
log.Fatal(err)
}
log.Println("Signature verified successfully")
}JavaScript/TypeScript Example
import * as secp256k1 from 'secp256k1';
import { createHash } from 'crypto';
interface SignedRequest {
public_key: string;
signature: string;
payload: any;
}
function signPayload(payload: any, privateKeyHex: string): string {
// Serialize payload to JSON
const payloadString = JSON.stringify(payload);
const payloadBytes = Buffer.from(payloadString, 'utf8');
// Hash payload with SHA256
const hash = createHash('sha256').update(payloadBytes).digest();
// Sign hash
const privateKey = Buffer.from(privateKeyHex, 'hex');
const signature = secp256k1.ecdsaSign(hash, privateKey);
// Return DER-encoded signature as hex
return signature.signature.toString('hex');
}
function createSignedRequest(
payload: any,
privateKeyHex: string,
publicKeyHex: string
): SignedRequest {
const signature = signPayload(payload, privateKeyHex);
return {
public_key: publicKeyHex,
signature: signature,
payload: payload
};
}Python Example
import hashlib
import json
from ecdsa import SigningKey, SECP256k1
from ecdsa.util import sigencode_der
def sign_payload(payload: dict, private_key_hex: str) -> str:
"""Sign a payload using ECDSA with SHA256."""
# Serialize payload to JSON
payload_json = json.dumps(payload, separators=(',', ':'), sort_keys=True)
payload_bytes = payload_json.encode('utf-8')
# Hash payload with SHA256
hash_obj = hashlib.sha256(payload_bytes)
message_hash = hash_obj.digest()
# Create signing key from hex
private_key_bytes = bytes.fromhex(private_key_hex)
signing_key = SigningKey.from_string(private_key_bytes, curve=SECP256k1)
# Sign hash and encode as DER
signature = signing_key.sign_digest(message_hash, sigencode=sigencode_der)
return signature.hex()
def create_signed_request(payload: dict, private_key_hex: str, public_key_hex: str) -> dict:
"""Create a signed request."""
signature = sign_payload(payload, private_key_hex)
return {
"public_key": public_key_hex,
"signature": signature,
"payload": payload
}Troubleshooting Authentication Issues
Common Error Messages
Invalid Public Key Format
Error: invalid public_key: public key must be exactly 66 characters (compressed format)Solution: Ensure public key is compressed format (66 hex characters starting with 02 or 03)
Signature Verification Failed
Error: signature verification failedCauses:
- Payload was modified after signing
- Wrong private key used for signing
- Public key doesn't match private key
- Invalid signature encoding
Solution: Re-sign with correct private key and ensure payload integrity
Invalid Address Format
Error: invalid address: invalid Dogecoin address formatSolution: Verify address corresponds to correct network (mainnet/testnet/regtest)
Debugging Steps
- Verify Key Pair: Ensure public key derives from private key
- Check Payload: Verify JSON serialization is identical
- Validate Encoding: Confirm hex encoding is lowercase
- Test Signature: Use reference implementation to verify
- Network Match: Ensure all addresses use same network prefix
Testing Authentication
func testAuthentication() {
// Generate test keypair
privHex, pubHex, address, err := doge.GenerateDogecoinKeypair(doge.PrefixRegtest)
if err != nil {
log.Fatal(err)
}
// Create test payload
payload := map[string]interface{}{
"test": "data",
"timestamp": time.Now().Unix(),
}
payloadBytes, _ := json.Marshal(payload)
// Sign payload
signature, err := doge.SignPayload(payloadBytes, privHex)
if err != nil {
log.Fatal(err)
}
// Verify signature
err = doge.ValidateSignature(payloadBytes, pubHex, signature)
if err != nil {
log.Fatal("Signature verification failed:", err)
}
log.Println("Authentication test passed")
log.Printf("Address: %s", address)
log.Printf("Public Key: %s", pubHex)
log.Printf("Signature: %s", signature)
}Integration Examples
Web Application Integration
For web applications, implement client-side signing:
// Import secp256k1 library
const secp256k1 = require('secp256k1');
class FractalEngineAuth {
constructor(privateKeyHex, publicKeyHex) {
this.privateKey = Buffer.from(privateKeyHex, 'hex');
this.publicKey = publicKeyHex;
}
async signRequest(payload) {
const payloadString = JSON.stringify(payload);
const hash = crypto.createHash('sha256')
.update(payloadString)
.digest();
const signature = secp256k1.ecdsaSign(hash, this.privateKey);
return {
public_key: this.publicKey,
signature: signature.signature.toString('hex'),
payload: payload
};
}
async makeAuthenticatedRequest(url, payload) {
const signedRequest = await this.signRequest(payload);
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(signedRequest)
});
return response.json();
}
}Mobile Application Integration
For mobile applications, use platform-specific crypto libraries:
// iOS Swift example using CommonCrypto
import CryptoKit
import secp256k1
class FractalEngineAuth {
private let privateKey: secp256k1.Signing.PrivateKey
private let publicKeyHex: String
init(privateKeyHex: String) throws {
let privateKeyData = Data(hex: privateKeyHex)
self.privateKey = try secp256k1.Signing.PrivateKey(dataRepresentation: privateKeyData)
self.publicKeyHex = privateKey.publicKey.dataRepresentation.hexString
}
func signPayload<T: Codable>(_ payload: T) throws -> SignedRequest<T> {
let jsonData = try JSONEncoder().encode(payload)
let hash = SHA256.hash(data: jsonData)
let signature = try privateKey.ecdsa.signature(for: Data(hash))
let signatureHex = signature.derRepresentation.hexString
return SignedRequest(
publicKey: publicKeyHex,
signature: signatureHex,
payload: payload
)
}
}The Fractal Engine's authentication system provides robust security through proven cryptographic methods. By following these guidelines and best practices, developers can implement secure, authenticated applications that integrate seamlessly with the platform.