synor/sdk/go/crypto/client.go
Gulshan Yadav 08a55aa80e feat(sdk): Add Crypto SDK for all 12 languages
Implements quantum-resistant cryptographic primitives across all SDK languages:
- Hybrid Ed25519 + Dilithium3 signatures (classical + post-quantum)
- BIP-39 mnemonic support (12, 15, 18, 21, 24 words)
- BIP-44 hierarchical key derivation (coin type 0x5359)
- Post-quantum algorithms: Falcon (FIPS 206), SPHINCS+ (FIPS 205)
- Key derivation: HKDF-SHA3-256, PBKDF2
- Hash functions: SHA3-256, BLAKE3, Keccak-256

Languages: JavaScript/TypeScript, Python, Go, Rust, Flutter/Dart, Java,
Kotlin, Swift, C, C++, C#/.NET, Ruby
2026-01-28 13:47:55 +05:30

691 lines
20 KiB
Go

// Package crypto provides quantum-resistant cryptographic primitives for the Synor blockchain.
package crypto
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
// SynorCrypto is the main client for the Crypto SDK
type SynorCrypto struct {
config Config
client *http.Client
closed bool
Mnemonic *MnemonicClient
Keypairs *KeypairClient
Signing *SigningClient
Falcon *FalconClient
Sphincs *SphincsClient
KDF *KDFClient
Hash *HashClient
Negotiation *NegotiationClient
}
// New creates a new SynorCrypto client
func New(config Config) *SynorCrypto {
if config.Endpoint == "" {
config.Endpoint = DefaultEndpoint
}
if config.Timeout == 0 {
config.Timeout = 30000
}
if config.Retries == 0 {
config.Retries = 3
}
if config.DefaultNetwork == "" {
config.DefaultNetwork = NetworkMainnet
}
c := &SynorCrypto{
config: config,
client: &http.Client{
Timeout: time.Duration(config.Timeout) * time.Millisecond,
},
}
c.Mnemonic = &MnemonicClient{crypto: c}
c.Keypairs = &KeypairClient{crypto: c}
c.Signing = &SigningClient{crypto: c}
c.Falcon = &FalconClient{crypto: c}
c.Sphincs = &SphincsClient{crypto: c}
c.KDF = &KDFClient{crypto: c}
c.Hash = &HashClient{crypto: c}
c.Negotiation = &NegotiationClient{crypto: c}
return c
}
// DefaultNetwork returns the default network
func (c *SynorCrypto) DefaultNetwork() Network {
return c.config.DefaultNetwork
}
// HealthCheck checks if the service is healthy
func (c *SynorCrypto) HealthCheck(ctx context.Context) (bool, error) {
var result map[string]interface{}
if err := c.get(ctx, "/health", &result); err != nil {
return false, nil
}
status, _ := result["status"].(string)
return status == "healthy", nil
}
// GetInfo returns service information
func (c *SynorCrypto) GetInfo(ctx context.Context) (map[string]interface{}, error) {
var result map[string]interface{}
err := c.get(ctx, "/info", &result)
return result, err
}
// Close closes the client
func (c *SynorCrypto) Close() {
c.closed = true
}
// IsClosed returns true if the client is closed
func (c *SynorCrypto) IsClosed() bool {
return c.closed
}
func (c *SynorCrypto) get(ctx context.Context, path string, result interface{}) error {
if c.closed {
return NewCryptoError("Client has been closed", "CLIENT_CLOSED")
}
req, err := http.NewRequestWithContext(ctx, "GET", c.config.Endpoint+path, nil)
if err != nil {
return err
}
c.setHeaders(req)
resp, err := c.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
return c.handleResponse(resp, result)
}
func (c *SynorCrypto) post(ctx context.Context, path string, body interface{}, result interface{}) error {
if c.closed {
return NewCryptoError("Client has been closed", "CLIENT_CLOSED")
}
var reqBody io.Reader
if body != nil {
jsonBody, err := json.Marshal(body)
if err != nil {
return err
}
reqBody = bytes.NewBuffer(jsonBody)
}
req, err := http.NewRequestWithContext(ctx, "POST", c.config.Endpoint+path, reqBody)
if err != nil {
return err
}
c.setHeaders(req)
resp, err := c.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
return c.handleResponse(resp, result)
}
func (c *SynorCrypto) setHeaders(req *http.Request) {
req.Header.Set("Authorization", "Bearer "+c.config.APIKey)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-SDK-Version", "go/0.1.0")
}
func (c *SynorCrypto) handleResponse(resp *http.Response, result interface{}) error {
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
if resp.StatusCode >= 400 {
var errResp map[string]interface{}
json.Unmarshal(body, &errResp)
msg := fmt.Sprintf("HTTP %d", resp.StatusCode)
code := ""
if m, ok := errResp["message"].(string); ok {
msg = m
}
if c, ok := errResp["code"].(string); ok {
code = c
}
return NewCryptoError(msg, code)
}
return json.Unmarshal(body, result)
}
// ============================================================================
// Mnemonic Client
// ============================================================================
// MnemonicClient handles mnemonic operations
type MnemonicClient struct {
crypto *SynorCrypto
}
// Generate creates a new random mnemonic
func (c *MnemonicClient) Generate(ctx context.Context, wordCount int) (*Mnemonic, error) {
var result mnemonicResponse
err := c.crypto.post(ctx, "/mnemonic/generate", map[string]int{"word_count": wordCount}, &result)
if err != nil {
return nil, err
}
return result.toMnemonic()
}
// FromPhrase creates a mnemonic from a phrase
func (c *MnemonicClient) FromPhrase(ctx context.Context, phrase string) (*Mnemonic, error) {
var result mnemonicResponse
err := c.crypto.post(ctx, "/mnemonic/from-phrase", map[string]string{"phrase": phrase}, &result)
if err != nil {
return nil, err
}
return result.toMnemonic()
}
// FromEntropy creates a mnemonic from entropy
func (c *MnemonicClient) FromEntropy(ctx context.Context, entropy []byte) (*Mnemonic, error) {
var result mnemonicResponse
err := c.crypto.post(ctx, "/mnemonic/from-entropy", map[string]string{
"entropy": EncodeBase64(entropy),
}, &result)
if err != nil {
return nil, err
}
return result.toMnemonic()
}
// Validate checks if a phrase is valid
func (c *MnemonicClient) Validate(ctx context.Context, phrase string) (*MnemonicValidation, error) {
var result MnemonicValidation
err := c.crypto.post(ctx, "/mnemonic/validate", map[string]string{"phrase": phrase}, &result)
return &result, err
}
// ToSeed derives a seed from a mnemonic
func (c *MnemonicClient) ToSeed(ctx context.Context, phrase string, passphrase string) ([]byte, error) {
var result struct {
Seed string `json:"seed"`
}
err := c.crypto.post(ctx, "/mnemonic/to-seed", map[string]string{
"phrase": phrase,
"passphrase": passphrase,
}, &result)
if err != nil {
return nil, err
}
return DecodeBase64(result.Seed)
}
// SuggestWords suggests completions for a partial word
func (c *MnemonicClient) SuggestWords(ctx context.Context, partial string, limit int) ([]string, error) {
var result struct {
Suggestions []string `json:"suggestions"`
}
err := c.crypto.post(ctx, "/mnemonic/suggest", map[string]interface{}{
"partial": partial,
"limit": limit,
}, &result)
return result.Suggestions, err
}
type mnemonicResponse struct {
Phrase string `json:"phrase"`
Words []string `json:"words"`
WordCount int `json:"word_count"`
Entropy string `json:"entropy"`
}
func (r *mnemonicResponse) toMnemonic() (*Mnemonic, error) {
entropy, _ := DecodeBase64(r.Entropy)
return &Mnemonic{
Phrase: r.Phrase,
Words: r.Words,
WordCount: r.WordCount,
Entropy: entropy,
}, nil
}
// ============================================================================
// Keypair Client
// ============================================================================
// KeypairClient handles keypair operations
type KeypairClient struct {
crypto *SynorCrypto
}
// Generate creates a new random keypair
func (c *KeypairClient) Generate(ctx context.Context) (*HybridKeypair, error) {
var result keypairResponse
err := c.crypto.post(ctx, "/keypair/generate", nil, &result)
if err != nil {
return nil, err
}
return result.toKeypair()
}
// FromMnemonic creates a keypair from a mnemonic
func (c *KeypairClient) FromMnemonic(ctx context.Context, phrase string, passphrase string) (*HybridKeypair, error) {
var result keypairResponse
err := c.crypto.post(ctx, "/keypair/from-mnemonic", map[string]string{
"phrase": phrase,
"passphrase": passphrase,
}, &result)
if err != nil {
return nil, err
}
return result.toKeypair()
}
// FromSeed creates a keypair from a seed
func (c *KeypairClient) FromSeed(ctx context.Context, seed []byte) (*HybridKeypair, error) {
var result keypairResponse
err := c.crypto.post(ctx, "/keypair/from-seed", map[string]string{
"seed": EncodeBase64(seed),
}, &result)
if err != nil {
return nil, err
}
return result.toKeypair()
}
// GetAddress gets the address for a public key
func (c *KeypairClient) GetAddress(ctx context.Context, pk *HybridPublicKey, network Network) (*Address, error) {
var result Address
err := c.crypto.post(ctx, "/keypair/address", map[string]interface{}{
"public_key": map[string]string{
"ed25519": EncodeBase64(pk.Ed25519),
"dilithium": EncodeBase64(pk.Dilithium),
},
"network": network,
}, &result)
return &result, err
}
type keypairResponse struct {
PublicKey struct {
Ed25519 string `json:"ed25519"`
Dilithium string `json:"dilithium"`
} `json:"public_key"`
SecretKey struct {
Ed25519Seed string `json:"ed25519_seed"`
MasterSeed string `json:"master_seed"`
} `json:"secret_key"`
Addresses map[string]string `json:"addresses"`
}
func (r *keypairResponse) toKeypair() (*HybridKeypair, error) {
ed25519, _ := DecodeBase64(r.PublicKey.Ed25519)
dilithium, _ := DecodeBase64(r.PublicKey.Dilithium)
ed25519Seed, _ := DecodeBase64(r.SecretKey.Ed25519Seed)
masterSeed, _ := DecodeBase64(r.SecretKey.MasterSeed)
addresses := make(map[Network]string)
for k, v := range r.Addresses {
addresses[Network(k)] = v
}
return &HybridKeypair{
PublicKey: &HybridPublicKey{
Ed25519: ed25519,
Dilithium: dilithium,
},
SecretKey: &SecretKey{
Ed25519Seed: ed25519Seed,
MasterSeed: masterSeed,
},
addresses: addresses,
}, nil
}
// ============================================================================
// Signing Client
// ============================================================================
// SigningClient handles signing operations
type SigningClient struct {
crypto *SynorCrypto
}
// Sign signs a message with a hybrid keypair
func (c *SigningClient) Sign(ctx context.Context, kp *HybridKeypair, message []byte) (*HybridSignature, error) {
var result struct {
Ed25519 string `json:"ed25519"`
Dilithium string `json:"dilithium"`
}
err := c.crypto.post(ctx, "/sign/hybrid", map[string]interface{}{
"secret_key": map[string]string{
"ed25519_seed": EncodeBase64(kp.SecretKey.Ed25519Seed),
"master_seed": EncodeBase64(kp.SecretKey.MasterSeed),
},
"message": EncodeBase64(message),
}, &result)
if err != nil {
return nil, err
}
ed25519, _ := DecodeBase64(result.Ed25519)
dilithium, _ := DecodeBase64(result.Dilithium)
return &HybridSignature{
Ed25519: ed25519,
Dilithium: dilithium,
}, nil
}
// Verify verifies a hybrid signature
func (c *SigningClient) Verify(ctx context.Context, pk *HybridPublicKey, message []byte, sig *HybridSignature) (bool, error) {
var result struct {
Valid bool `json:"valid"`
}
err := c.crypto.post(ctx, "/sign/verify", map[string]interface{}{
"public_key": map[string]string{
"ed25519": EncodeBase64(pk.Ed25519),
"dilithium": EncodeBase64(pk.Dilithium),
},
"message": EncodeBase64(message),
"signature": map[string]string{
"ed25519": EncodeBase64(sig.Ed25519),
"dilithium": EncodeBase64(sig.Dilithium),
},
}, &result)
return result.Valid, err
}
// SignEd25519 signs with Ed25519 only
func (c *SigningClient) SignEd25519(ctx context.Context, secretKey []byte, message []byte) ([]byte, error) {
var result struct {
Signature string `json:"signature"`
}
err := c.crypto.post(ctx, "/sign/ed25519", map[string]string{
"secret_key": EncodeBase64(secretKey),
"message": EncodeBase64(message),
}, &result)
if err != nil {
return nil, err
}
return DecodeBase64(result.Signature)
}
// ============================================================================
// Falcon Client
// ============================================================================
// FalconClient handles Falcon operations
type FalconClient struct {
crypto *SynorCrypto
}
// Generate creates a Falcon keypair
func (c *FalconClient) Generate(ctx context.Context, variant FalconVariant) (*FalconKeypair, error) {
var result map[string]interface{}
err := c.crypto.post(ctx, "/falcon/generate", map[string]string{"variant": string(variant)}, &result)
if err != nil {
return nil, err
}
// Parse response into FalconKeypair
return parseFalconKeypair(result, variant)
}
// Sign signs with Falcon
func (c *FalconClient) Sign(ctx context.Context, kp *FalconKeypair, message []byte) (*FalconSignature, error) {
var result struct {
Signature string `json:"signature"`
Variant string `json:"variant"`
}
err := c.crypto.post(ctx, "/falcon/sign", map[string]string{
"variant": string(kp.Variant),
"secret_key": EncodeBase64(kp.SecretKey.Bytes),
"message": EncodeBase64(message),
}, &result)
if err != nil {
return nil, err
}
sigBytes, _ := DecodeBase64(result.Signature)
return &FalconSignature{
Variant: FalconVariant(result.Variant),
Bytes: sigBytes,
}, nil
}
// Verify verifies a Falcon signature
func (c *FalconClient) Verify(ctx context.Context, publicKey []byte, message []byte, sig *FalconSignature) (bool, error) {
var result struct {
Valid bool `json:"valid"`
}
err := c.crypto.post(ctx, "/falcon/verify", map[string]interface{}{
"variant": sig.Variant,
"public_key": EncodeBase64(publicKey),
"message": EncodeBase64(message),
"signature": EncodeBase64(sig.Bytes),
}, &result)
return result.Valid, err
}
func parseFalconKeypair(data map[string]interface{}, variant FalconVariant) (*FalconKeypair, error) {
pk := data["public_key"].(map[string]interface{})
sk := data["secret_key"].(map[string]interface{})
pkBytes, _ := DecodeBase64(pk["bytes"].(string))
skBytes, _ := DecodeBase64(sk["bytes"].(string))
return &FalconKeypair{
Variant: variant,
PublicKey: &FalconPublicKey{Variant: variant, Bytes: pkBytes},
SecretKey: &FalconSecretKey{Variant: variant, Bytes: skBytes},
}, nil
}
// ============================================================================
// SPHINCS+ Client
// ============================================================================
// SphincsClient handles SPHINCS+ operations
type SphincsClient struct {
crypto *SynorCrypto
}
// Generate creates a SPHINCS+ keypair
func (c *SphincsClient) Generate(ctx context.Context, variant SphincsVariant) (*SphincsKeypair, error) {
var result map[string]interface{}
err := c.crypto.post(ctx, "/sphincs/generate", map[string]string{"variant": string(variant)}, &result)
if err != nil {
return nil, err
}
return parseSphincsKeypair(result, variant)
}
// Sign signs with SPHINCS+
func (c *SphincsClient) Sign(ctx context.Context, kp *SphincsKeypair, message []byte) (*SphincsSignature, error) {
var result struct {
Signature string `json:"signature"`
Variant string `json:"variant"`
}
err := c.crypto.post(ctx, "/sphincs/sign", map[string]string{
"variant": string(kp.Variant),
"secret_key": EncodeBase64(kp.SecretKey.Bytes),
"message": EncodeBase64(message),
}, &result)
if err != nil {
return nil, err
}
sigBytes, _ := DecodeBase64(result.Signature)
return &SphincsSignature{
Variant: SphincsVariant(result.Variant),
Bytes: sigBytes,
}, nil
}
// Verify verifies a SPHINCS+ signature
func (c *SphincsClient) Verify(ctx context.Context, publicKey []byte, message []byte, sig *SphincsSignature) (bool, error) {
var result struct {
Valid bool `json:"valid"`
}
err := c.crypto.post(ctx, "/sphincs/verify", map[string]interface{}{
"variant": sig.Variant,
"public_key": EncodeBase64(publicKey),
"message": EncodeBase64(message),
"signature": EncodeBase64(sig.Bytes),
}, &result)
return result.Valid, err
}
func parseSphincsKeypair(data map[string]interface{}, variant SphincsVariant) (*SphincsKeypair, error) {
pk := data["public_key"].(map[string]interface{})
sk := data["secret_key"].(map[string]interface{})
pkBytes, _ := DecodeBase64(pk["bytes"].(string))
skBytes, _ := DecodeBase64(sk["bytes"].(string))
return &SphincsKeypair{
Variant: variant,
PublicKey: &SphincsPublicKey{Variant: variant, Bytes: pkBytes},
SecretKey: &SphincsSecretKey{Variant: variant, Bytes: skBytes},
}, nil
}
// ============================================================================
// KDF Client
// ============================================================================
// KDFClient handles key derivation
type KDFClient struct {
crypto *SynorCrypto
}
// DeriveKey derives a key using HKDF
func (c *KDFClient) DeriveKey(ctx context.Context, seed []byte, config *DerivationConfig) ([]byte, error) {
body := map[string]interface{}{
"seed": EncodeBase64(seed),
"output_length": config.OutputLength,
}
if config.Salt != nil {
body["salt"] = EncodeBase64(config.Salt)
}
if config.Info != nil {
body["info"] = EncodeBase64(config.Info)
}
var result struct {
Key string `json:"key"`
}
err := c.crypto.post(ctx, "/kdf/hkdf", body, &result)
if err != nil {
return nil, err
}
return DecodeBase64(result.Key)
}
// DeriveFromPassword derives a key from a password
func (c *KDFClient) DeriveFromPassword(ctx context.Context, password []byte, config *PasswordDerivationConfig) ([]byte, error) {
var result struct {
Key string `json:"key"`
}
err := c.crypto.post(ctx, "/kdf/pbkdf2", map[string]interface{}{
"password": EncodeBase64(password),
"salt": EncodeBase64(config.Salt),
"iterations": config.Iterations,
"output_length": config.OutputLength,
}, &result)
if err != nil {
return nil, err
}
return DecodeBase64(result.Key)
}
// DeriveChildKey derives a child key
func (c *KDFClient) DeriveChildKey(ctx context.Context, parentKey, chainCode []byte, index int) ([]byte, []byte, error) {
var result struct {
Key string `json:"key"`
ChainCode string `json:"chain_code"`
}
err := c.crypto.post(ctx, "/kdf/child", map[string]interface{}{
"parent_key": EncodeBase64(parentKey),
"chain_code": EncodeBase64(chainCode),
"index": index,
}, &result)
if err != nil {
return nil, nil, err
}
key, _ := DecodeBase64(result.Key)
cc, _ := DecodeBase64(result.ChainCode)
return key, cc, nil
}
// ============================================================================
// Hash Client
// ============================================================================
// HashClient handles hashing operations
type HashClient struct {
crypto *SynorCrypto
}
// SHA3_256 computes SHA3-256 hash
func (c *HashClient) SHA3_256(ctx context.Context, data []byte) (*Hash256, error) {
var result struct {
Hash string `json:"hash"`
}
err := c.crypto.post(ctx, "/hash/sha3-256", map[string]string{
"data": EncodeBase64(data),
}, &result)
if err != nil {
return nil, err
}
hashBytes, _ := DecodeBase64(result.Hash)
return &Hash256{Bytes: hashBytes, Hex: result.Hash}, nil
}
// Blake3 computes BLAKE3 hash
func (c *HashClient) Blake3(ctx context.Context, data []byte) (*Hash256, error) {
var result struct {
Hash string `json:"hash"`
}
err := c.crypto.post(ctx, "/hash/blake3", map[string]string{
"data": EncodeBase64(data),
}, &result)
if err != nil {
return nil, err
}
hashBytes, _ := DecodeBase64(result.Hash)
return &Hash256{Bytes: hashBytes, Hex: result.Hash}, nil
}
// ============================================================================
// Negotiation Client
// ============================================================================
// NegotiationClient handles algorithm negotiation
type NegotiationClient struct {
crypto *SynorCrypto
}
// GetCapabilities returns local capabilities
func (c *NegotiationClient) GetCapabilities(ctx context.Context) (*AlgorithmCapabilities, error) {
var result AlgorithmCapabilities
err := c.crypto.get(ctx, "/negotiation/capabilities", &result)
return &result, err
}
// Negotiate negotiates with a peer
func (c *NegotiationClient) Negotiate(ctx context.Context, peerCaps *AlgorithmCapabilities, policy *NegotiationPolicy) (*NegotiationResult, error) {
var result NegotiationResult
err := c.crypto.post(ctx, "/negotiation/negotiate", map[string]interface{}{
"peer_capabilities": peerCaps,
"policy": policy,
}, &result)
return &result, err
}