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
This commit is contained in:
Gulshan Yadav 2026-01-28 13:47:55 +05:30
parent 2c534a18bb
commit 08a55aa80e
25 changed files with 11265 additions and 0 deletions

View file

@ -0,0 +1,799 @@
/**
* Synor Crypto SDK for C
*
* Quantum-resistant cryptographic primitives for the Synor blockchain.
*
* Example:
* ```c
* synor_crypto_config_t config = {
* .api_key = "your-api-key",
* .endpoint = "https://crypto.synor.io/v1",
* .timeout = 30000,
* .retries = 3
* };
*
* synor_crypto_t* crypto = synor_crypto_create(&config);
*
* // Generate a mnemonic
* synor_mnemonic_t mnemonic;
* synor_crypto_mnemonic_generate(crypto, 24, &mnemonic);
* printf("Backup words: %s\n", mnemonic.phrase);
*
* // Create keypair from mnemonic
* synor_hybrid_keypair_t keypair;
* synor_crypto_keypair_from_mnemonic(crypto, mnemonic.phrase, "", &keypair);
*
* synor_crypto_destroy(crypto);
* ```
*/
#ifndef SYNOR_CRYPTO_H
#define SYNOR_CRYPTO_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ============================================================================
* Constants
* ============================================================================ */
#define SYNOR_CRYPTO_ED25519_PUBLIC_KEY_SIZE 32
#define SYNOR_CRYPTO_ED25519_SECRET_KEY_SIZE 32
#define SYNOR_CRYPTO_ED25519_SIGNATURE_SIZE 64
#define SYNOR_CRYPTO_DILITHIUM3_PUBLIC_KEY_SIZE 1952
#define SYNOR_CRYPTO_DILITHIUM3_SIGNATURE_SIZE 3293
#define SYNOR_CRYPTO_HYBRID_SIGNATURE_SIZE (64 + 3293)
#define SYNOR_CRYPTO_COIN_TYPE 0x5359
#define SYNOR_CRYPTO_MIN_PBKDF2_ITERATIONS 10000
#define SYNOR_CRYPTO_MIN_SALT_LENGTH 8
#define SYNOR_CRYPTO_DEFAULT_ENDPOINT "https://crypto.synor.io/v1"
#define SYNOR_CRYPTO_MAX_PHRASE_LEN 1024
#define SYNOR_CRYPTO_MAX_ADDRESS_LEN 128
#define SYNOR_CRYPTO_MAX_HASH_LEN 64
#define SYNOR_CRYPTO_MAX_ERROR_LEN 256
/* ============================================================================
* Enumerations
* ============================================================================ */
typedef enum {
SYNOR_NETWORK_MAINNET = 0,
SYNOR_NETWORK_TESTNET = 1,
SYNOR_NETWORK_DEVNET = 2
} synor_network_t;
typedef enum {
SYNOR_FALCON_512 = 0,
SYNOR_FALCON_1024 = 1
} synor_falcon_variant_t;
typedef enum {
SYNOR_SPHINCS_SHAKE128S = 0,
SYNOR_SPHINCS_SHAKE192S = 1,
SYNOR_SPHINCS_SHAKE256S = 2
} synor_sphincs_variant_t;
typedef enum {
SYNOR_PQ_DILITHIUM3 = 0,
SYNOR_PQ_FALCON512 = 1,
SYNOR_PQ_FALCON1024 = 2,
SYNOR_PQ_SPHINCS128S = 3,
SYNOR_PQ_SPHINCS192S = 4,
SYNOR_PQ_SPHINCS256S = 5
} synor_pq_algorithm_t;
typedef enum {
SYNOR_ALGO_FAMILY_CLASSICAL = 0,
SYNOR_ALGO_FAMILY_LATTICE = 1,
SYNOR_ALGO_FAMILY_HASH_BASED = 2,
SYNOR_ALGO_FAMILY_HYBRID = 3
} synor_algorithm_family_t;
typedef enum {
SYNOR_OK = 0,
SYNOR_ERROR_INVALID_PARAMS = -1,
SYNOR_ERROR_NETWORK = -2,
SYNOR_ERROR_AUTH = -3,
SYNOR_ERROR_TIMEOUT = -4,
SYNOR_ERROR_API = -5,
SYNOR_ERROR_CLOSED = -6,
SYNOR_ERROR_MEMORY = -7,
SYNOR_ERROR_PARSE = -8
} synor_error_t;
/* ============================================================================
* Configuration Types
* ============================================================================ */
typedef struct {
const char* api_key;
const char* endpoint;
uint32_t timeout;
uint32_t retries;
bool debug;
synor_network_t default_network;
} synor_crypto_config_t;
typedef struct {
uint8_t* salt;
size_t salt_len;
uint8_t* info;
size_t info_len;
uint32_t output_length;
} synor_derivation_config_t;
typedef struct {
uint8_t* salt;
size_t salt_len;
uint32_t iterations;
uint32_t output_length;
} synor_password_derivation_config_t;
typedef struct {
uint32_t account;
uint32_t change;
uint32_t index;
} synor_derivation_path_t;
/* ============================================================================
* Key Types
* ============================================================================ */
typedef struct {
char ed25519[88]; /* Base64 encoded */
char dilithium[2608]; /* Base64 encoded */
} synor_hybrid_public_key_t;
typedef struct {
char ed25519_seed[88]; /* Base64 encoded */
char master_seed[88]; /* Base64 encoded */
} synor_secret_key_t;
typedef struct {
synor_falcon_variant_t variant;
uint8_t* bytes;
size_t bytes_len;
} synor_falcon_public_key_t;
typedef struct {
synor_falcon_variant_t variant;
uint8_t* bytes;
size_t bytes_len;
} synor_falcon_secret_key_t;
typedef struct {
synor_sphincs_variant_t variant;
uint8_t* bytes;
size_t bytes_len;
} synor_sphincs_public_key_t;
typedef struct {
synor_sphincs_variant_t variant;
uint8_t* bytes;
size_t bytes_len;
} synor_sphincs_secret_key_t;
/* ============================================================================
* Signature Types
* ============================================================================ */
typedef struct {
char ed25519[88]; /* Base64 encoded */
char dilithium[4392]; /* Base64 encoded */
} synor_hybrid_signature_t;
typedef struct {
synor_falcon_variant_t variant;
uint8_t* signature;
size_t signature_len;
} synor_falcon_signature_t;
typedef struct {
synor_sphincs_variant_t variant;
uint8_t* signature;
size_t signature_len;
} synor_sphincs_signature_t;
/* ============================================================================
* Keypair Types
* ============================================================================ */
typedef struct {
synor_hybrid_public_key_t public_key;
synor_secret_key_t secret_key;
char addresses[3][SYNOR_CRYPTO_MAX_ADDRESS_LEN]; /* mainnet, testnet, devnet */
} synor_hybrid_keypair_t;
typedef struct {
synor_falcon_variant_t variant;
synor_falcon_public_key_t public_key;
synor_falcon_secret_key_t secret_key;
} synor_falcon_keypair_t;
typedef struct {
synor_sphincs_variant_t variant;
synor_sphincs_public_key_t public_key;
synor_sphincs_secret_key_t secret_key;
} synor_sphincs_keypair_t;
/* ============================================================================
* Mnemonic Types
* ============================================================================ */
typedef struct {
char phrase[SYNOR_CRYPTO_MAX_PHRASE_LEN];
char** words;
size_t word_count;
uint8_t* entropy;
size_t entropy_len;
} synor_mnemonic_t;
typedef struct {
bool valid;
char error[SYNOR_CRYPTO_MAX_ERROR_LEN];
} synor_mnemonic_validation_t;
/* ============================================================================
* Address Types
* ============================================================================ */
typedef struct {
char address[SYNOR_CRYPTO_MAX_ADDRESS_LEN];
synor_network_t network;
uint8_t pubkey_hash[32];
} synor_address_t;
/* ============================================================================
* Hash Types
* ============================================================================ */
typedef struct {
char hex[SYNOR_CRYPTO_MAX_HASH_LEN + 1];
uint8_t bytes[32];
} synor_hash256_t;
/* ============================================================================
* Client Handle
* ============================================================================ */
typedef struct synor_crypto_s synor_crypto_t;
/* ============================================================================
* Client Lifecycle
* ============================================================================ */
/**
* Create a new Synor Crypto client.
*
* @param config Configuration for the client
* @return Pointer to the client handle, or NULL on error
*/
synor_crypto_t* synor_crypto_create(const synor_crypto_config_t* config);
/**
* Destroy a Synor Crypto client and free resources.
*
* @param crypto Client handle
*/
void synor_crypto_destroy(synor_crypto_t* crypto);
/**
* Check if the client has been closed.
*
* @param crypto Client handle
* @return true if closed, false otherwise
*/
bool synor_crypto_is_closed(const synor_crypto_t* crypto);
/**
* Perform a health check on the API.
*
* @param crypto Client handle
* @return SYNOR_OK if healthy, error code otherwise
*/
synor_error_t synor_crypto_health_check(synor_crypto_t* crypto);
/* ============================================================================
* Mnemonic Operations
* ============================================================================ */
/**
* Generate a new mnemonic phrase.
*
* @param crypto Client handle
* @param word_count Number of words (12, 15, 18, 21, or 24)
* @param out Output mnemonic
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_mnemonic_generate(
synor_crypto_t* crypto,
uint32_t word_count,
synor_mnemonic_t* out
);
/**
* Parse an existing mnemonic phrase.
*
* @param crypto Client handle
* @param phrase Mnemonic phrase
* @param out Output mnemonic
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_mnemonic_from_phrase(
synor_crypto_t* crypto,
const char* phrase,
synor_mnemonic_t* out
);
/**
* Validate a mnemonic phrase.
*
* @param crypto Client handle
* @param phrase Mnemonic phrase to validate
* @param out Validation result
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_mnemonic_validate(
synor_crypto_t* crypto,
const char* phrase,
synor_mnemonic_validation_t* out
);
/**
* Convert a mnemonic phrase to a seed.
*
* @param crypto Client handle
* @param phrase Mnemonic phrase
* @param passphrase Optional passphrase (can be empty string)
* @param seed Output seed buffer (must be at least 64 bytes)
* @param seed_len Output seed length
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_mnemonic_to_seed(
synor_crypto_t* crypto,
const char* phrase,
const char* passphrase,
uint8_t* seed,
size_t* seed_len
);
/**
* Free mnemonic resources.
*
* @param mnemonic Mnemonic to free
*/
void synor_crypto_mnemonic_free(synor_mnemonic_t* mnemonic);
/* ============================================================================
* Keypair Operations
* ============================================================================ */
/**
* Generate a new hybrid keypair.
*
* @param crypto Client handle
* @param out Output keypair
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_keypair_generate(
synor_crypto_t* crypto,
synor_hybrid_keypair_t* out
);
/**
* Create a keypair from a mnemonic phrase.
*
* @param crypto Client handle
* @param phrase Mnemonic phrase
* @param passphrase Optional passphrase (can be empty string)
* @param out Output keypair
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_keypair_from_mnemonic(
synor_crypto_t* crypto,
const char* phrase,
const char* passphrase,
synor_hybrid_keypair_t* out
);
/**
* Create a keypair from a seed.
*
* @param crypto Client handle
* @param seed Seed bytes
* @param seed_len Seed length
* @param out Output keypair
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_keypair_from_seed(
synor_crypto_t* crypto,
const uint8_t* seed,
size_t seed_len,
synor_hybrid_keypair_t* out
);
/**
* Get an address for a public key.
*
* @param crypto Client handle
* @param public_key Public key
* @param network Network type
* @param out Output address
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_keypair_get_address(
synor_crypto_t* crypto,
const synor_hybrid_public_key_t* public_key,
synor_network_t network,
synor_address_t* out
);
/* ============================================================================
* Signing Operations
* ============================================================================ */
/**
* Sign a message with a hybrid keypair.
*
* @param crypto Client handle
* @param keypair Keypair for signing
* @param message Message to sign
* @param message_len Message length
* @param out Output signature
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_sign(
synor_crypto_t* crypto,
const synor_hybrid_keypair_t* keypair,
const uint8_t* message,
size_t message_len,
synor_hybrid_signature_t* out
);
/**
* Verify a hybrid signature.
*
* @param crypto Client handle
* @param public_key Public key for verification
* @param message Original message
* @param message_len Message length
* @param signature Signature to verify
* @param valid Output: true if valid, false otherwise
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_verify(
synor_crypto_t* crypto,
const synor_hybrid_public_key_t* public_key,
const uint8_t* message,
size_t message_len,
const synor_hybrid_signature_t* signature,
bool* valid
);
/**
* Sign a message with Ed25519.
*
* @param crypto Client handle
* @param secret_key Ed25519 secret key (32 bytes)
* @param message Message to sign
* @param message_len Message length
* @param signature Output signature (64 bytes)
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_sign_ed25519(
synor_crypto_t* crypto,
const uint8_t* secret_key,
const uint8_t* message,
size_t message_len,
uint8_t* signature
);
/* ============================================================================
* Falcon Operations
* ============================================================================ */
/**
* Generate a Falcon keypair.
*
* @param crypto Client handle
* @param variant Falcon variant (512 or 1024)
* @param out Output keypair
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_falcon_generate(
synor_crypto_t* crypto,
synor_falcon_variant_t variant,
synor_falcon_keypair_t* out
);
/**
* Sign a message with Falcon.
*
* @param crypto Client handle
* @param keypair Falcon keypair
* @param message Message to sign
* @param message_len Message length
* @param out Output signature
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_falcon_sign(
synor_crypto_t* crypto,
const synor_falcon_keypair_t* keypair,
const uint8_t* message,
size_t message_len,
synor_falcon_signature_t* out
);
/**
* Verify a Falcon signature.
*
* @param crypto Client handle
* @param public_key Falcon public key
* @param public_key_len Public key length
* @param message Original message
* @param message_len Message length
* @param signature Signature to verify
* @param valid Output: true if valid, false otherwise
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_falcon_verify(
synor_crypto_t* crypto,
const uint8_t* public_key,
size_t public_key_len,
const uint8_t* message,
size_t message_len,
const synor_falcon_signature_t* signature,
bool* valid
);
/**
* Free Falcon keypair resources.
*
* @param keypair Keypair to free
*/
void synor_crypto_falcon_keypair_free(synor_falcon_keypair_t* keypair);
/**
* Free Falcon signature resources.
*
* @param signature Signature to free
*/
void synor_crypto_falcon_signature_free(synor_falcon_signature_t* signature);
/* ============================================================================
* SPHINCS+ Operations
* ============================================================================ */
/**
* Generate a SPHINCS+ keypair.
*
* @param crypto Client handle
* @param variant SPHINCS+ variant
* @param out Output keypair
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_sphincs_generate(
synor_crypto_t* crypto,
synor_sphincs_variant_t variant,
synor_sphincs_keypair_t* out
);
/**
* Sign a message with SPHINCS+.
*
* @param crypto Client handle
* @param keypair SPHINCS+ keypair
* @param message Message to sign
* @param message_len Message length
* @param out Output signature
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_sphincs_sign(
synor_crypto_t* crypto,
const synor_sphincs_keypair_t* keypair,
const uint8_t* message,
size_t message_len,
synor_sphincs_signature_t* out
);
/**
* Verify a SPHINCS+ signature.
*
* @param crypto Client handle
* @param public_key SPHINCS+ public key
* @param public_key_len Public key length
* @param message Original message
* @param message_len Message length
* @param signature Signature to verify
* @param valid Output: true if valid, false otherwise
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_sphincs_verify(
synor_crypto_t* crypto,
const uint8_t* public_key,
size_t public_key_len,
const uint8_t* message,
size_t message_len,
const synor_sphincs_signature_t* signature,
bool* valid
);
/**
* Free SPHINCS+ keypair resources.
*
* @param keypair Keypair to free
*/
void synor_crypto_sphincs_keypair_free(synor_sphincs_keypair_t* keypair);
/**
* Free SPHINCS+ signature resources.
*
* @param signature Signature to free
*/
void synor_crypto_sphincs_signature_free(synor_sphincs_signature_t* signature);
/* ============================================================================
* KDF Operations
* ============================================================================ */
/**
* Derive a key using HKDF.
*
* @param crypto Client handle
* @param seed Input seed
* @param seed_len Seed length
* @param config Derivation configuration
* @param key Output key buffer
* @param key_len Output key length
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_kdf_derive(
synor_crypto_t* crypto,
const uint8_t* seed,
size_t seed_len,
const synor_derivation_config_t* config,
uint8_t* key,
size_t* key_len
);
/**
* Derive a key from a password using PBKDF2.
*
* @param crypto Client handle
* @param password Password bytes
* @param password_len Password length
* @param config Password derivation configuration
* @param key Output key buffer
* @param key_len Output key length
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_kdf_derive_password(
synor_crypto_t* crypto,
const uint8_t* password,
size_t password_len,
const synor_password_derivation_config_t* config,
uint8_t* key,
size_t* key_len
);
/* ============================================================================
* Hash Operations
* ============================================================================ */
/**
* Compute SHA3-256 hash.
*
* @param crypto Client handle
* @param data Input data
* @param data_len Data length
* @param out Output hash
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_hash_sha3_256(
synor_crypto_t* crypto,
const uint8_t* data,
size_t data_len,
synor_hash256_t* out
);
/**
* Compute BLAKE3 hash.
*
* @param crypto Client handle
* @param data Input data
* @param data_len Data length
* @param out Output hash
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_hash_blake3(
synor_crypto_t* crypto,
const uint8_t* data,
size_t data_len,
synor_hash256_t* out
);
/**
* Compute Keccak-256 hash.
*
* @param crypto Client handle
* @param data Input data
* @param data_len Data length
* @param out Output hash
* @return SYNOR_OK on success, error code otherwise
*/
synor_error_t synor_crypto_hash_keccak256(
synor_crypto_t* crypto,
const uint8_t* data,
size_t data_len,
synor_hash256_t* out
);
/* ============================================================================
* Utility Functions
* ============================================================================ */
/**
* Get the signature size for a Falcon variant.
*
* @param variant Falcon variant
* @return Signature size in bytes
*/
size_t synor_crypto_falcon_signature_size(synor_falcon_variant_t variant);
/**
* Get the public key size for a Falcon variant.
*
* @param variant Falcon variant
* @return Public key size in bytes
*/
size_t synor_crypto_falcon_public_key_size(synor_falcon_variant_t variant);
/**
* Get the signature size for a SPHINCS+ variant.
*
* @param variant SPHINCS+ variant
* @return Signature size in bytes
*/
size_t synor_crypto_sphincs_signature_size(synor_sphincs_variant_t variant);
/**
* Get the network name string.
*
* @param network Network type
* @return Network name ("mainnet", "testnet", or "devnet")
*/
const char* synor_crypto_network_name(synor_network_t network);
/**
* Get human-readable error message.
*
* @param error Error code
* @return Error message string
*/
const char* synor_crypto_error_message(synor_error_t error);
/**
* Format a derivation path as a string.
*
* @param path Derivation path
* @param buffer Output buffer
* @param buffer_size Buffer size
* @return Number of characters written (excluding null terminator)
*/
int synor_crypto_derivation_path_format(
const synor_derivation_path_t* path,
char* buffer,
size_t buffer_size
);
#ifdef __cplusplus
}
#endif
#endif /* SYNOR_CRYPTO_H */

View file

@ -0,0 +1,524 @@
/**
* Synor Crypto SDK for C++
*
* Quantum-resistant cryptographic primitives for the Synor blockchain.
*
* Example:
* ```cpp
* #include <synor/crypto.hpp>
*
* int main() {
* synor::crypto::Config config{"your-api-key"};
* synor::crypto::SynorCrypto crypto{config};
*
* // Generate a mnemonic
* auto mnemonic = crypto.mnemonic().generate(24).get();
* std::cout << "Backup words: " << mnemonic.phrase << std::endl;
*
* // Create keypair from mnemonic
* auto keypair = crypto.keypairs().from_mnemonic(mnemonic.phrase, "").get();
* auto address = keypair.get_address(synor::crypto::Network::Mainnet);
*
* // Sign a message
* auto signature = crypto.signing().sign(keypair, "Hello!").get();
* }
* ```
*/
#ifndef SYNOR_CRYPTO_HPP
#define SYNOR_CRYPTO_HPP
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <future>
#include <optional>
#include <stdexcept>
#include <cstdint>
namespace synor {
namespace crypto {
// ============================================================================
// Constants
// ============================================================================
constexpr int ED25519_PUBLIC_KEY_SIZE = 32;
constexpr int ED25519_SECRET_KEY_SIZE = 32;
constexpr int ED25519_SIGNATURE_SIZE = 64;
constexpr int DILITHIUM3_PUBLIC_KEY_SIZE = 1952;
constexpr int DILITHIUM3_SIGNATURE_SIZE = 3293;
constexpr int HYBRID_SIGNATURE_SIZE = 64 + 3293;
constexpr int COIN_TYPE = 0x5359;
constexpr int MIN_PBKDF2_ITERATIONS = 10000;
constexpr int MIN_SALT_LENGTH = 8;
constexpr const char* DEFAULT_ENDPOINT = "https://crypto.synor.io/v1";
// ============================================================================
// Enumerations
// ============================================================================
enum class Network {
Mainnet,
Testnet,
Devnet
};
inline std::string to_string(Network n) {
switch (n) {
case Network::Mainnet: return "mainnet";
case Network::Testnet: return "testnet";
case Network::Devnet: return "devnet";
}
return "mainnet";
}
inline Network network_from_string(const std::string& s) {
if (s == "testnet") return Network::Testnet;
if (s == "devnet") return Network::Devnet;
return Network::Mainnet;
}
enum class FalconVariant {
Falcon512,
Falcon1024
};
inline std::string to_string(FalconVariant v) {
switch (v) {
case FalconVariant::Falcon512: return "falcon512";
case FalconVariant::Falcon1024: return "falcon1024";
}
return "falcon512";
}
inline int signature_size(FalconVariant v) {
return v == FalconVariant::Falcon512 ? 690 : 1330;
}
inline int public_key_size(FalconVariant v) {
return v == FalconVariant::Falcon512 ? 897 : 1793;
}
inline int security_level(FalconVariant v) {
return v == FalconVariant::Falcon512 ? 128 : 256;
}
enum class SphincsVariant {
Shake128s,
Shake192s,
Shake256s
};
inline std::string to_string(SphincsVariant v) {
switch (v) {
case SphincsVariant::Shake128s: return "shake128s";
case SphincsVariant::Shake192s: return "shake192s";
case SphincsVariant::Shake256s: return "shake256s";
}
return "shake128s";
}
inline int signature_size(SphincsVariant v) {
switch (v) {
case SphincsVariant::Shake128s: return 7856;
case SphincsVariant::Shake192s: return 16224;
case SphincsVariant::Shake256s: return 29792;
}
return 7856;
}
inline int security_level(SphincsVariant v) {
switch (v) {
case SphincsVariant::Shake128s: return 128;
case SphincsVariant::Shake192s: return 192;
case SphincsVariant::Shake256s: return 256;
}
return 128;
}
enum class PqAlgorithm {
Dilithium3,
Falcon512,
Falcon1024,
Sphincs128s,
Sphincs192s,
Sphincs256s
};
enum class AlgorithmFamily {
Classical,
Lattice,
HashBased,
Hybrid
};
// ============================================================================
// Error Types
// ============================================================================
class CryptoException : public std::runtime_error {
public:
explicit CryptoException(const std::string& message, const std::string& code = "")
: std::runtime_error(message), code_(code) {}
const std::string& code() const { return code_; }
private:
std::string code_;
};
// ============================================================================
// Configuration Types
// ============================================================================
struct Config {
std::string api_key;
std::string endpoint = DEFAULT_ENDPOINT;
int timeout = 30000;
int retries = 3;
bool debug = false;
Network default_network = Network::Mainnet;
explicit Config(std::string api_key) : api_key(std::move(api_key)) {}
};
struct DerivationConfig {
std::vector<uint8_t> salt;
std::vector<uint8_t> info;
int output_length = 32;
};
struct PasswordDerivationConfig {
std::vector<uint8_t> salt;
int iterations = 100000;
int output_length = 32;
explicit PasswordDerivationConfig(std::vector<uint8_t> salt)
: salt(std::move(salt)) {}
};
struct DerivationPath {
static constexpr int COIN_TYPE = 0x5359;
int account;
int change;
int index;
static DerivationPath external_path(int account, int index) {
return {account, 0, index};
}
static DerivationPath internal_path(int account, int index) {
return {account, 1, index};
}
std::string to_string() const {
return "m/44'/" + std::to_string(COIN_TYPE) + "'/" +
std::to_string(account) + "'/" +
std::to_string(change) + "/" +
std::to_string(index);
}
};
// ============================================================================
// Key Types
// ============================================================================
struct HybridPublicKey {
std::string ed25519;
std::string dilithium;
std::vector<uint8_t> ed25519_bytes() const;
std::vector<uint8_t> dilithium_bytes() const;
size_t size() const;
};
struct SecretKey {
std::string ed25519_seed;
std::string master_seed;
std::vector<uint8_t> ed25519_seed_bytes() const;
std::vector<uint8_t> master_seed_bytes() const;
};
struct FalconPublicKey {
FalconVariant variant;
std::vector<uint8_t> bytes;
};
struct FalconSecretKey {
FalconVariant variant;
std::vector<uint8_t> bytes;
};
struct SphincsPublicKey {
SphincsVariant variant;
std::vector<uint8_t> bytes;
};
struct SphincsSecretKey {
SphincsVariant variant;
std::vector<uint8_t> bytes;
};
// ============================================================================
// Signature Types
// ============================================================================
struct HybridSignature {
std::string ed25519;
std::string dilithium;
std::vector<uint8_t> ed25519_bytes() const;
std::vector<uint8_t> dilithium_bytes() const;
size_t size() const;
std::vector<uint8_t> to_bytes() const;
};
struct FalconSignature {
FalconVariant variant;
std::vector<uint8_t> signature;
size_t size() const { return signature.size(); }
};
struct SphincsSignature {
SphincsVariant variant;
std::vector<uint8_t> signature;
size_t size() const { return signature.size(); }
};
// ============================================================================
// Keypair Types
// ============================================================================
struct HybridKeypair {
HybridPublicKey public_key;
SecretKey secret_key;
std::map<std::string, std::string> addresses;
std::string get_address(Network network) const;
};
struct FalconKeypair {
FalconVariant variant;
FalconPublicKey public_key;
FalconSecretKey secret_key;
};
struct SphincsKeypair {
SphincsVariant variant;
SphincsPublicKey public_key;
SphincsSecretKey secret_key;
};
// ============================================================================
// Mnemonic Types
// ============================================================================
struct Mnemonic {
std::string phrase;
std::vector<std::string> words;
int word_count = 0;
std::vector<uint8_t> entropy;
std::vector<std::string> get_words() const;
int get_word_count() const;
};
struct MnemonicValidation {
bool valid;
std::optional<std::string> error;
};
// ============================================================================
// Address Types
// ============================================================================
struct Address {
std::string address;
Network network;
std::vector<uint8_t> pubkey_hash;
};
// ============================================================================
// Hash Types
// ============================================================================
struct Hash256 {
std::string hash;
std::string hex() const { return hash; }
std::vector<uint8_t> bytes() const;
};
// ============================================================================
// Forward Declarations
// ============================================================================
class SynorCrypto;
// ============================================================================
// Sub-Clients
// ============================================================================
class MnemonicClient {
public:
explicit MnemonicClient(SynorCrypto* crypto) : crypto_(crypto) {}
std::future<Mnemonic> generate(int word_count = 24);
std::future<Mnemonic> from_phrase(const std::string& phrase);
std::future<MnemonicValidation> validate(const std::string& phrase);
std::future<std::vector<uint8_t>> to_seed(const std::string& phrase, const std::string& passphrase = "");
std::future<std::vector<std::string>> suggest_words(const std::string& partial, int limit = 5);
private:
SynorCrypto* crypto_;
};
class KeypairClient {
public:
explicit KeypairClient(SynorCrypto* crypto) : crypto_(crypto) {}
std::future<HybridKeypair> generate();
std::future<HybridKeypair> from_mnemonic(const std::string& phrase, const std::string& passphrase = "");
std::future<HybridKeypair> from_seed(const std::vector<uint8_t>& seed);
std::future<Address> get_address(const HybridPublicKey& public_key, Network network);
private:
SynorCrypto* crypto_;
};
class SigningClient {
public:
explicit SigningClient(SynorCrypto* crypto) : crypto_(crypto) {}
std::future<HybridSignature> sign(const HybridKeypair& keypair, const std::vector<uint8_t>& message);
std::future<HybridSignature> sign(const HybridKeypair& keypair, const std::string& message);
std::future<bool> verify(const HybridPublicKey& public_key, const std::vector<uint8_t>& message, const HybridSignature& signature);
std::future<std::vector<uint8_t>> sign_ed25519(const std::vector<uint8_t>& secret_key, const std::vector<uint8_t>& message);
private:
SynorCrypto* crypto_;
};
class FalconClient {
public:
explicit FalconClient(SynorCrypto* crypto) : crypto_(crypto) {}
std::future<FalconKeypair> generate(FalconVariant variant = FalconVariant::Falcon512);
std::future<FalconSignature> sign(const FalconKeypair& keypair, const std::vector<uint8_t>& message);
std::future<bool> verify(const std::vector<uint8_t>& public_key, const std::vector<uint8_t>& message, const FalconSignature& signature);
private:
SynorCrypto* crypto_;
};
class SphincsClient {
public:
explicit SphincsClient(SynorCrypto* crypto) : crypto_(crypto) {}
std::future<SphincsKeypair> generate(SphincsVariant variant = SphincsVariant::Shake128s);
std::future<SphincsSignature> sign(const SphincsKeypair& keypair, const std::vector<uint8_t>& message);
std::future<bool> verify(const std::vector<uint8_t>& public_key, const std::vector<uint8_t>& message, const SphincsSignature& signature);
private:
SynorCrypto* crypto_;
};
class KdfClient {
public:
explicit KdfClient(SynorCrypto* crypto) : crypto_(crypto) {}
std::future<std::vector<uint8_t>> derive_key(const std::vector<uint8_t>& seed, const DerivationConfig& config = {});
std::future<std::vector<uint8_t>> derive_from_password(const std::vector<uint8_t>& password, const PasswordDerivationConfig& config);
private:
SynorCrypto* crypto_;
};
class HashClient {
public:
explicit HashClient(SynorCrypto* crypto) : crypto_(crypto) {}
std::future<Hash256> sha3_256(const std::vector<uint8_t>& data);
std::future<Hash256> blake3(const std::vector<uint8_t>& data);
std::future<Hash256> keccak256(const std::vector<uint8_t>& data);
private:
SynorCrypto* crypto_;
};
// ============================================================================
// Main Client
// ============================================================================
class SynorCrypto {
public:
explicit SynorCrypto(const Config& config);
~SynorCrypto();
// Non-copyable
SynorCrypto(const SynorCrypto&) = delete;
SynorCrypto& operator=(const SynorCrypto&) = delete;
// Movable
SynorCrypto(SynorCrypto&&) noexcept;
SynorCrypto& operator=(SynorCrypto&&) noexcept;
// Accessors
Network default_network() const { return config_.default_network; }
bool is_closed() const { return closed_; }
// Sub-clients
MnemonicClient& mnemonic() { return mnemonic_client_; }
KeypairClient& keypairs() { return keypair_client_; }
SigningClient& signing() { return signing_client_; }
FalconClient& falcon() { return falcon_client_; }
SphincsClient& sphincs() { return sphincs_client_; }
KdfClient& kdf() { return kdf_client_; }
HashClient& hash() { return hash_client_; }
// Operations
std::future<bool> health_check();
void close();
// Internal HTTP methods (used by sub-clients)
template<typename T>
std::future<T> get(const std::string& path);
template<typename T>
std::future<T> post(const std::string& path, const std::map<std::string, std::string>& body = {});
private:
void check_closed() const;
Config config_;
bool closed_ = false;
MnemonicClient mnemonic_client_;
KeypairClient keypair_client_;
SigningClient signing_client_;
FalconClient falcon_client_;
SphincsClient sphincs_client_;
KdfClient kdf_client_;
HashClient hash_client_;
class Impl;
std::unique_ptr<Impl> impl_;
};
// ============================================================================
// Utility Functions
// ============================================================================
std::string base64_encode(const std::vector<uint8_t>& data);
std::vector<uint8_t> base64_decode(const std::string& encoded);
} // namespace crypto
} // namespace synor
#endif // SYNOR_CRYPTO_HPP

View file

@ -0,0 +1,336 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
namespace Synor.Crypto;
/// <summary>
/// Synor Crypto SDK for C#/.NET
///
/// Quantum-resistant cryptographic primitives for the Synor blockchain.
/// </summary>
public class SynorCrypto : IDisposable
{
private readonly CryptoConfig _config;
private readonly HttpClient _httpClient;
private readonly JsonSerializerOptions _jsonOptions;
private bool _closed;
public MnemonicClient Mnemonic { get; }
public KeypairClient Keypairs { get; }
public SigningClient Signing { get; }
public FalconClient Falcon { get; }
public SphincsClient Sphincs { get; }
public KdfClient Kdf { get; }
public HashClient Hash { get; }
public SynorCrypto(CryptoConfig config)
{
_config = config;
_httpClient = new HttpClient
{
BaseAddress = new Uri(config.Endpoint),
Timeout = TimeSpan.FromMilliseconds(config.Timeout)
};
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {config.ApiKey}");
_httpClient.DefaultRequestHeaders.Add("X-SDK-Version", "csharp/0.1.0");
_jsonOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
Converters = { new JsonStringEnumConverter(JsonNamingPolicy.SnakeCaseLower) }
};
Mnemonic = new MnemonicClient(this);
Keypairs = new KeypairClient(this);
Signing = new SigningClient(this);
Falcon = new FalconClient(this);
Sphincs = new SphincsClient(this);
Kdf = new KdfClient(this);
Hash = new HashClient(this);
}
public Network DefaultNetwork => _config.DefaultNetwork;
public async Task<bool> HealthCheckAsync(CancellationToken ct = default)
{
try
{
var result = await GetAsync<Dictionary<string, object>>("/health", ct);
return result.TryGetValue("status", out var status) && status?.ToString() == "healthy";
}
catch
{
return false;
}
}
public Task<Dictionary<string, object>> GetInfoAsync(CancellationToken ct = default) =>
GetAsync<Dictionary<string, object>>("/info", ct);
public void Close()
{
_closed = true;
_httpClient.Dispose();
}
public bool IsClosed => _closed;
public void Dispose()
{
Close();
GC.SuppressFinalize(this);
}
internal async Task<T> GetAsync<T>(string path, CancellationToken ct = default)
{
CheckClosed();
var response = await _httpClient.GetAsync(path, ct);
return await HandleResponseAsync<T>(response);
}
internal async Task<T> PostAsync<T>(string path, object? body = null, CancellationToken ct = default)
{
CheckClosed();
var content = body != null
? JsonContent.Create(body, options: _jsonOptions)
: JsonContent.Create(new { });
var response = await _httpClient.PostAsync(path, content, ct);
return await HandleResponseAsync<T>(response);
}
private async Task<T> HandleResponseAsync<T>(HttpResponseMessage response)
{
var json = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
var error = JsonSerializer.Deserialize<Dictionary<string, object>>(json, _jsonOptions) ?? new();
throw new CryptoException(
error.TryGetValue("message", out var msg) ? msg?.ToString() ?? $"HTTP {(int)response.StatusCode}" : $"HTTP {(int)response.StatusCode}",
error.TryGetValue("code", out var code) ? code?.ToString() : null,
(int)response.StatusCode
);
}
return JsonSerializer.Deserialize<T>(json, _jsonOptions)!;
}
private void CheckClosed()
{
if (_closed) throw new CryptoException("Client has been closed", "CLIENT_CLOSED");
}
}
/// <summary>Mnemonic sub-client</summary>
public class MnemonicClient
{
private readonly SynorCrypto _crypto;
internal MnemonicClient(SynorCrypto crypto) => _crypto = crypto;
public Task<Mnemonic> GenerateAsync(int wordCount = 24, CancellationToken ct = default) =>
_crypto.PostAsync<Mnemonic>("/mnemonic/generate", new { word_count = wordCount }, ct);
public Task<Mnemonic> FromPhraseAsync(string phrase, CancellationToken ct = default) =>
_crypto.PostAsync<Mnemonic>("/mnemonic/from-phrase", new { phrase }, ct);
public Task<MnemonicValidation> ValidateAsync(string phrase, CancellationToken ct = default) =>
_crypto.PostAsync<MnemonicValidation>("/mnemonic/validate", new { phrase }, ct);
public async Task<byte[]> ToSeedAsync(string phrase, string passphrase = "", CancellationToken ct = default)
{
var result = await _crypto.PostAsync<SeedResponse>("/mnemonic/to-seed", new { phrase, passphrase }, ct);
return Convert.FromBase64String(result.Seed);
}
public async Task<List<string>> SuggestWordsAsync(string partial, int limit = 5, CancellationToken ct = default)
{
var result = await _crypto.PostAsync<SuggestResponse>("/mnemonic/suggest", new { partial, limit }, ct);
return result.Suggestions ?? new List<string>();
}
}
/// <summary>Keypair sub-client</summary>
public class KeypairClient
{
private readonly SynorCrypto _crypto;
internal KeypairClient(SynorCrypto crypto) => _crypto = crypto;
public Task<HybridKeypair> GenerateAsync(CancellationToken ct = default) =>
_crypto.PostAsync<HybridKeypair>("/keypair/generate", null, ct);
public Task<HybridKeypair> FromMnemonicAsync(string phrase, string passphrase = "", CancellationToken ct = default) =>
_crypto.PostAsync<HybridKeypair>("/keypair/from-mnemonic", new { phrase, passphrase }, ct);
public Task<HybridKeypair> FromSeedAsync(byte[] seed, CancellationToken ct = default) =>
_crypto.PostAsync<HybridKeypair>("/keypair/from-seed", new { seed = Convert.ToBase64String(seed) }, ct);
public Task<Address> GetAddressAsync(HybridPublicKey publicKey, Network network, CancellationToken ct = default) =>
_crypto.PostAsync<Address>("/keypair/address", new
{
public_key = publicKey.ToDict(),
network = network.ToApiString()
}, ct);
}
/// <summary>Signing sub-client</summary>
public class SigningClient
{
private readonly SynorCrypto _crypto;
internal SigningClient(SynorCrypto crypto) => _crypto = crypto;
public Task<HybridSignature> SignAsync(HybridKeypair keypair, byte[] message, CancellationToken ct = default) =>
_crypto.PostAsync<HybridSignature>("/sign/hybrid", new
{
secret_key = keypair.SecretKey.ToDict(),
message = Convert.ToBase64String(message)
}, ct);
public async Task<bool> VerifyAsync(HybridPublicKey publicKey, byte[] message, HybridSignature signature, CancellationToken ct = default)
{
var result = await _crypto.PostAsync<ValidResponse>("/sign/verify", new
{
public_key = publicKey.ToDict(),
message = Convert.ToBase64String(message),
signature = signature.ToDict()
}, ct);
return result.Valid;
}
public async Task<byte[]> SignEd25519Async(byte[] secretKey, byte[] message, CancellationToken ct = default)
{
var result = await _crypto.PostAsync<SignatureResponse>("/sign/ed25519", new
{
secret_key = Convert.ToBase64String(secretKey),
message = Convert.ToBase64String(message)
}, ct);
return Convert.FromBase64String(result.Signature);
}
}
/// <summary>Falcon sub-client</summary>
public class FalconClient
{
private readonly SynorCrypto _crypto;
internal FalconClient(SynorCrypto crypto) => _crypto = crypto;
public Task<FalconKeypair> GenerateAsync(FalconVariant variant = FalconVariant.Falcon512, CancellationToken ct = default) =>
_crypto.PostAsync<FalconKeypair>("/falcon/generate", new { variant = variant.ToApiString() }, ct);
public Task<FalconSignature> SignAsync(FalconKeypair keypair, byte[] message, CancellationToken ct = default) =>
_crypto.PostAsync<FalconSignature>("/falcon/sign", new
{
variant = keypair.VariantEnum.ToApiString(),
secret_key = Convert.ToBase64String(keypair.SecretKey.KeyBytes),
message = Convert.ToBase64String(message)
}, ct);
public async Task<bool> VerifyAsync(byte[] publicKey, byte[] message, FalconSignature signature, CancellationToken ct = default)
{
var result = await _crypto.PostAsync<ValidResponse>("/falcon/verify", new
{
variant = signature.VariantEnum.ToApiString(),
public_key = Convert.ToBase64String(publicKey),
message = Convert.ToBase64String(message),
signature = Convert.ToBase64String(signature.SignatureBytes)
}, ct);
return result.Valid;
}
}
/// <summary>SPHINCS+ sub-client</summary>
public class SphincsClient
{
private readonly SynorCrypto _crypto;
internal SphincsClient(SynorCrypto crypto) => _crypto = crypto;
public Task<SphincsKeypair> GenerateAsync(SphincsVariant variant = SphincsVariant.Shake128s, CancellationToken ct = default) =>
_crypto.PostAsync<SphincsKeypair>("/sphincs/generate", new { variant = variant.ToApiString() }, ct);
public Task<SphincsSignature> SignAsync(SphincsKeypair keypair, byte[] message, CancellationToken ct = default) =>
_crypto.PostAsync<SphincsSignature>("/sphincs/sign", new
{
variant = keypair.VariantEnum.ToApiString(),
secret_key = Convert.ToBase64String(keypair.SecretKey.KeyBytes),
message = Convert.ToBase64String(message)
}, ct);
public async Task<bool> VerifyAsync(byte[] publicKey, byte[] message, SphincsSignature signature, CancellationToken ct = default)
{
var result = await _crypto.PostAsync<ValidResponse>("/sphincs/verify", new
{
variant = signature.VariantEnum.ToApiString(),
public_key = Convert.ToBase64String(publicKey),
message = Convert.ToBase64String(message),
signature = Convert.ToBase64String(signature.SignatureBytes)
}, ct);
return result.Valid;
}
}
/// <summary>KDF sub-client</summary>
public class KdfClient
{
private readonly SynorCrypto _crypto;
internal KdfClient(SynorCrypto crypto) => _crypto = crypto;
public async Task<byte[]> DeriveKeyAsync(byte[] seed, DerivationConfig? config = null, CancellationToken ct = default)
{
config ??= new DerivationConfig();
var body = new Dictionary<string, object>
{
["seed"] = Convert.ToBase64String(seed),
["output_length"] = config.OutputLength
};
if (config.Salt != null) body["salt"] = Convert.ToBase64String(config.Salt);
if (config.Info != null) body["info"] = Convert.ToBase64String(config.Info);
var result = await _crypto.PostAsync<KeyResponse>("/kdf/hkdf", body, ct);
return Convert.FromBase64String(result.Key);
}
public async Task<byte[]> DeriveFromPasswordAsync(byte[] password, PasswordDerivationConfig config, CancellationToken ct = default)
{
var result = await _crypto.PostAsync<KeyResponse>("/kdf/pbkdf2", new
{
password = Convert.ToBase64String(password),
salt = Convert.ToBase64String(config.Salt),
iterations = config.Iterations,
output_length = config.OutputLength
}, ct);
return Convert.FromBase64String(result.Key);
}
}
/// <summary>Hash sub-client</summary>
public class HashClient
{
private readonly SynorCrypto _crypto;
internal HashClient(SynorCrypto crypto) => _crypto = crypto;
public Task<Hash256> Sha3_256Async(byte[] data, CancellationToken ct = default) =>
_crypto.PostAsync<Hash256>("/hash/sha3-256", new { data = Convert.ToBase64String(data) }, ct);
public Task<Hash256> Blake3Async(byte[] data, CancellationToken ct = default) =>
_crypto.PostAsync<Hash256>("/hash/blake3", new { data = Convert.ToBase64String(data) }, ct);
public Task<Hash256> Keccak256Async(byte[] data, CancellationToken ct = default) =>
_crypto.PostAsync<Hash256>("/hash/keccak256", new { data = Convert.ToBase64String(data) }, ct);
}
// Response helper types
internal record SeedResponse(string Seed);
internal record SuggestResponse(List<string>? Suggestions);
internal record SignatureResponse(string Signature);
internal record KeyResponse(string Key);
internal record ValidResponse(bool Valid);

View file

@ -0,0 +1,505 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Synor.Crypto;
// ============================================================================
// Enumerations
// ============================================================================
/// <summary>Network type for the Synor blockchain.</summary>
public enum Network
{
Mainnet,
Testnet,
Devnet
}
public static class NetworkExtensions
{
public static string ToApiString(this Network network) => network switch
{
Network.Mainnet => "mainnet",
Network.Testnet => "testnet",
Network.Devnet => "devnet",
_ => "mainnet"
};
public static Network FromApiString(string value) => value switch
{
"mainnet" => Network.Mainnet,
"testnet" => Network.Testnet,
"devnet" => Network.Devnet,
_ => Network.Mainnet
};
}
/// <summary>Falcon signature variant.</summary>
public enum FalconVariant
{
Falcon512,
Falcon1024
}
public static class FalconVariantExtensions
{
public static string ToApiString(this FalconVariant variant) => variant switch
{
FalconVariant.Falcon512 => "falcon512",
FalconVariant.Falcon1024 => "falcon1024",
_ => "falcon512"
};
public static int SignatureSize(this FalconVariant variant) => variant switch
{
FalconVariant.Falcon512 => 690,
FalconVariant.Falcon1024 => 1330,
_ => 690
};
public static int PublicKeySize(this FalconVariant variant) => variant switch
{
FalconVariant.Falcon512 => 897,
FalconVariant.Falcon1024 => 1793,
_ => 897
};
public static int SecurityLevel(this FalconVariant variant) => variant switch
{
FalconVariant.Falcon512 => 128,
FalconVariant.Falcon1024 => 256,
_ => 128
};
}
/// <summary>SPHINCS+ signature variant.</summary>
public enum SphincsVariant
{
Shake128s,
Shake192s,
Shake256s
}
public static class SphincsVariantExtensions
{
public static string ToApiString(this SphincsVariant variant) => variant switch
{
SphincsVariant.Shake128s => "shake128s",
SphincsVariant.Shake192s => "shake192s",
SphincsVariant.Shake256s => "shake256s",
_ => "shake128s"
};
public static int SignatureSize(this SphincsVariant variant) => variant switch
{
SphincsVariant.Shake128s => 7856,
SphincsVariant.Shake192s => 16224,
SphincsVariant.Shake256s => 29792,
_ => 7856
};
public static int SecurityLevel(this SphincsVariant variant) => variant switch
{
SphincsVariant.Shake128s => 128,
SphincsVariant.Shake192s => 192,
SphincsVariant.Shake256s => 256,
_ => 128
};
}
/// <summary>Post-quantum algorithm types.</summary>
public enum PqAlgorithm
{
Dilithium3,
Falcon512,
Falcon1024,
Sphincs128s,
Sphincs192s,
Sphincs256s
}
/// <summary>Cryptographic algorithm family.</summary>
public enum AlgorithmFamily
{
Classical,
Lattice,
HashBased,
Hybrid
}
// ============================================================================
// Configuration Types
// ============================================================================
/// <summary>Configuration for the Crypto SDK.</summary>
public record CryptoConfig
{
public required string ApiKey { get; init; }
public string Endpoint { get; init; } = "https://crypto.synor.io/v1";
public int Timeout { get; init; } = 30000;
public int Retries { get; init; } = 3;
public bool Debug { get; init; } = false;
public Network DefaultNetwork { get; init; } = Network.Mainnet;
}
/// <summary>Configuration for key derivation.</summary>
public record DerivationConfig
{
public byte[]? Salt { get; init; }
public byte[]? Info { get; init; }
public int OutputLength { get; init; } = 32;
}
/// <summary>Configuration for password-based key derivation.</summary>
public record PasswordDerivationConfig
{
public required byte[] Salt { get; init; }
public int Iterations { get; init; } = 100000;
public int OutputLength { get; init; } = 32;
}
/// <summary>BIP-44 derivation path.</summary>
public record DerivationPath(int Account, int Change, int Index)
{
public const int CoinType = 0x5359;
public static DerivationPath External(int account, int index) => new(account, 0, index);
public static DerivationPath Internal(int account, int index) => new(account, 1, index);
public override string ToString() => $"m/44'/{CoinType}'/{Account}'/{Change}/{Index}";
public Dictionary<string, int> ToDict() => new()
{
["account"] = Account,
["change"] = Change,
["index"] = Index
};
}
// ============================================================================
// Key Types
// ============================================================================
/// <summary>Hybrid public key combining Ed25519 and Dilithium3.</summary>
public record HybridPublicKey
{
public string Ed25519 { get; init; } = "";
public string Dilithium { get; init; } = "";
public byte[] Ed25519Bytes => Convert.FromBase64String(Ed25519);
public byte[] DilithiumBytes => Convert.FromBase64String(Dilithium);
public int Size => Ed25519Bytes.Length + DilithiumBytes.Length;
public Dictionary<string, string> ToDict() => new()
{
["ed25519"] = Ed25519,
["dilithium"] = Dilithium
};
}
/// <summary>Secret key for hybrid signatures.</summary>
public record SecretKey
{
[JsonPropertyName("ed25519_seed")]
public string Ed25519Seed { get; init; } = "";
[JsonPropertyName("master_seed")]
public string MasterSeed { get; init; } = "";
public byte[] Ed25519SeedBytes => Convert.FromBase64String(Ed25519Seed);
public byte[] MasterSeedBytes => Convert.FromBase64String(MasterSeed);
public Dictionary<string, string> ToDict() => new()
{
["ed25519_seed"] = Ed25519Seed,
["master_seed"] = MasterSeed
};
}
/// <summary>Falcon public key.</summary>
public record FalconPublicKey
{
public string Variant { get; init; } = "";
public string Bytes { get; init; } = "";
public FalconVariant VariantEnum => Variant.ToLower() switch
{
"falcon512" => FalconVariant.Falcon512,
"falcon1024" => FalconVariant.Falcon1024,
_ => FalconVariant.Falcon512
};
public byte[] KeyBytes => Convert.FromBase64String(Bytes);
}
/// <summary>Falcon secret key.</summary>
public record FalconSecretKey
{
public string Variant { get; init; } = "";
public string Bytes { get; init; } = "";
public FalconVariant VariantEnum => Variant.ToLower() switch
{
"falcon512" => FalconVariant.Falcon512,
"falcon1024" => FalconVariant.Falcon1024,
_ => FalconVariant.Falcon512
};
public byte[] KeyBytes => Convert.FromBase64String(Bytes);
}
/// <summary>SPHINCS+ public key.</summary>
public record SphincsPublicKey
{
public string Variant { get; init; } = "";
public string Bytes { get; init; } = "";
public SphincsVariant VariantEnum => Variant.ToLower() switch
{
"shake128s" => SphincsVariant.Shake128s,
"shake192s" => SphincsVariant.Shake192s,
"shake256s" => SphincsVariant.Shake256s,
_ => SphincsVariant.Shake128s
};
public byte[] KeyBytes => Convert.FromBase64String(Bytes);
}
/// <summary>SPHINCS+ secret key.</summary>
public record SphincsSecretKey
{
public string Variant { get; init; } = "";
public string Bytes { get; init; } = "";
public SphincsVariant VariantEnum => Variant.ToLower() switch
{
"shake128s" => SphincsVariant.Shake128s,
"shake192s" => SphincsVariant.Shake192s,
"shake256s" => SphincsVariant.Shake256s,
_ => SphincsVariant.Shake128s
};
public byte[] KeyBytes => Convert.FromBase64String(Bytes);
}
// ============================================================================
// Signature Types
// ============================================================================
/// <summary>Hybrid signature combining Ed25519 and Dilithium3.</summary>
public record HybridSignature
{
public string Ed25519 { get; init; } = "";
public string Dilithium { get; init; } = "";
public byte[] Ed25519Bytes => Convert.FromBase64String(Ed25519);
public byte[] DilithiumBytes => Convert.FromBase64String(Dilithium);
public int Size => Ed25519Bytes.Length + DilithiumBytes.Length;
public byte[] ToBytes()
{
var e = Ed25519Bytes;
var d = DilithiumBytes;
var result = new byte[e.Length + d.Length];
Buffer.BlockCopy(e, 0, result, 0, e.Length);
Buffer.BlockCopy(d, 0, result, e.Length, d.Length);
return result;
}
public Dictionary<string, string> ToDict() => new()
{
["ed25519"] = Ed25519,
["dilithium"] = Dilithium
};
}
/// <summary>Falcon signature.</summary>
public record FalconSignature
{
public string Variant { get; init; } = "";
public string Signature { get; init; } = "";
public FalconVariant VariantEnum => Variant.ToLower() switch
{
"falcon512" => FalconVariant.Falcon512,
"falcon1024" => FalconVariant.Falcon1024,
_ => FalconVariant.Falcon512
};
public byte[] SignatureBytes => Convert.FromBase64String(Signature);
public int Size => SignatureBytes.Length;
}
/// <summary>SPHINCS+ signature.</summary>
public record SphincsSignature
{
public string Variant { get; init; } = "";
public string Signature { get; init; } = "";
public SphincsVariant VariantEnum => Variant.ToLower() switch
{
"shake128s" => SphincsVariant.Shake128s,
"shake192s" => SphincsVariant.Shake192s,
"shake256s" => SphincsVariant.Shake256s,
_ => SphincsVariant.Shake128s
};
public byte[] SignatureBytes => Convert.FromBase64String(Signature);
public int Size => SignatureBytes.Length;
}
// ============================================================================
// Keypair Types
// ============================================================================
/// <summary>Hybrid keypair for Ed25519 + Dilithium3.</summary>
public record HybridKeypair
{
[JsonPropertyName("public_key")]
public HybridPublicKey PublicKey { get; init; } = new();
[JsonPropertyName("secret_key")]
public SecretKey SecretKey { get; init; } = new();
public Dictionary<string, string> Addresses { get; init; } = new();
public string GetAddress(Network network) =>
Addresses.TryGetValue(network.ToApiString(), out var addr) ? addr : "";
}
/// <summary>Falcon keypair.</summary>
public record FalconKeypair
{
public string Variant { get; init; } = "";
[JsonPropertyName("public_key")]
public FalconPublicKey PublicKey { get; init; } = new();
[JsonPropertyName("secret_key")]
public FalconSecretKey SecretKey { get; init; } = new();
public FalconVariant VariantEnum => PublicKey.VariantEnum;
}
/// <summary>SPHINCS+ keypair.</summary>
public record SphincsKeypair
{
public string Variant { get; init; } = "";
[JsonPropertyName("public_key")]
public SphincsPublicKey PublicKey { get; init; } = new();
[JsonPropertyName("secret_key")]
public SphincsSecretKey SecretKey { get; init; } = new();
public SphincsVariant VariantEnum => PublicKey.VariantEnum;
}
// ============================================================================
// Mnemonic Types
// ============================================================================
/// <summary>BIP-39 mnemonic phrase.</summary>
public record Mnemonic
{
public string Phrase { get; init; } = "";
public List<string>? Words { get; init; }
[JsonPropertyName("word_count")]
public int WordCount { get; init; }
public string? Entropy { get; init; }
public List<string> GetWords() => Words ?? new List<string>(Phrase.Split(' '));
public int GetWordCount() => WordCount > 0 ? WordCount : GetWords().Count;
public byte[] GetEntropy() => Entropy != null ? Convert.FromBase64String(Entropy) : Array.Empty<byte>();
}
/// <summary>Mnemonic validation result.</summary>
public record MnemonicValidation
{
public bool Valid { get; init; }
public string? Error { get; init; }
}
// ============================================================================
// Address Types
// ============================================================================
/// <summary>Blockchain address.</summary>
public record Address
{
[JsonPropertyName("address")]
public string AddressString { get; init; } = "";
public string NetworkString { get; init; } = "";
[JsonPropertyName("pubkey_hash")]
public string? PubkeyHash { get; init; }
public Network Network => NetworkExtensions.FromApiString(NetworkString);
public byte[] PubkeyHashBytes => PubkeyHash != null ? Convert.FromBase64String(PubkeyHash) : Array.Empty<byte>();
}
// ============================================================================
// Hash Types
// ============================================================================
/// <summary>256-bit hash result.</summary>
public record Hash256
{
public string Hash { get; init; } = "";
public string Hex => Hash;
public byte[] Bytes
{
get
{
var result = new byte[Hash.Length / 2];
for (int i = 0; i < result.Length; i++)
{
result[i] = Convert.ToByte(Hash.Substring(i * 2, 2), 16);
}
return result;
}
}
}
// ============================================================================
// Error Types
// ============================================================================
/// <summary>Crypto SDK exception.</summary>
public class CryptoException : Exception
{
public string? Code { get; }
public int? HttpStatus { get; }
public CryptoException(string message, string? code = null, int? httpStatus = null)
: base(message)
{
Code = code;
HttpStatus = httpStatus;
}
}
// ============================================================================
// Constants
// ============================================================================
/// <summary>Cryptographic constants.</summary>
public static class CryptoConstants
{
public const int Ed25519PublicKeySize = 32;
public const int Ed25519SecretKeySize = 32;
public const int Ed25519SignatureSize = 64;
public const int Dilithium3PublicKeySize = 1952;
public const int Dilithium3SignatureSize = 3293;
public const int HybridSignatureSize = 64 + 3293;
public const int CoinType = 0x5359;
public const int MinPbkdf2Iterations = 10000;
public const int MinSaltLength = 8;
public const string DefaultEndpoint = "https://crypto.synor.io/v1";
}

View file

@ -0,0 +1,466 @@
/// Synor Crypto SDK Client for Flutter/Dart
///
/// Quantum-resistant cryptographic primitives for the Synor blockchain.
library synor_crypto;
import 'dart:convert';
import 'dart:typed_data';
import 'package:http/http.dart' as http;
import 'types.dart';
export 'types.dart';
/// Main Synor Crypto client
class SynorCrypto {
final CryptoConfig _config;
final http.Client _client;
bool _closed = false;
late final MnemonicClient mnemonic;
late final KeypairClient keypairs;
late final SigningClient signing;
late final FalconClient falcon;
late final SphincsClient sphincs;
late final KdfClient kdf;
late final HashClient hash;
late final NegotiationClient negotiation;
SynorCrypto(this._config) : _client = http.Client() {
mnemonic = MnemonicClient(this);
keypairs = KeypairClient(this);
signing = SigningClient(this);
falcon = FalconClient(this);
sphincs = SphincsClient(this);
kdf = KdfClient(this);
hash = HashClient(this);
negotiation = NegotiationClient(this);
}
/// Returns the default network
Network get defaultNetwork => _config.defaultNetwork;
/// Checks service health
Future<bool> healthCheck() async {
try {
final result = await _get('/health');
return result['status'] == 'healthy';
} catch (_) {
return false;
}
}
/// Gets service info
Future<Map<String, dynamic>> getInfo() => _get('/info');
/// Closes the client
void close() {
_closed = true;
_client.close();
}
/// Returns true if closed
bool get isClosed => _closed;
Future<Map<String, dynamic>> _get(String path) async {
_checkClosed();
final response = await _client.get(
Uri.parse('${_config.endpoint}$path'),
headers: _headers(),
);
return _handleResponse(response);
}
Future<Map<String, dynamic>> _post(String path, [Map<String, dynamic>? body]) async {
_checkClosed();
final response = await _client.post(
Uri.parse('${_config.endpoint}$path'),
headers: _headers(),
body: body != null ? jsonEncode(body) : null,
);
return _handleResponse(response);
}
Map<String, String> _headers() => {
'Authorization': 'Bearer ${_config.apiKey}',
'Content-Type': 'application/json',
'X-SDK-Version': 'dart/0.1.0',
};
Map<String, dynamic> _handleResponse(http.Response response) {
final json = jsonDecode(response.body) as Map<String, dynamic>;
if (response.statusCode >= 400) {
throw CryptoException(
json['message'] as String? ?? 'HTTP ${response.statusCode}',
json['code'] as String?,
);
}
return json;
}
void _checkClosed() {
if (_closed) {
throw const CryptoException('Client has been closed', 'CLIENT_CLOSED');
}
}
}
/// Mnemonic operations
class MnemonicClient {
final SynorCrypto _crypto;
MnemonicClient(this._crypto);
/// Generates a new random mnemonic
Future<Mnemonic> generate([int wordCount = 24]) async {
final result = await _crypto._post('/mnemonic/generate', {'word_count': wordCount});
return Mnemonic.fromJson(result);
}
/// Creates a mnemonic from a phrase
Future<Mnemonic> fromPhrase(String phrase) async {
final result = await _crypto._post('/mnemonic/from-phrase', {'phrase': phrase});
return Mnemonic.fromJson(result);
}
/// Creates a mnemonic from entropy
Future<Mnemonic> fromEntropy(Uint8List entropy) async {
final result = await _crypto._post('/mnemonic/from-entropy', {
'entropy': base64Encode(entropy),
});
return Mnemonic.fromJson(result);
}
/// Validates a mnemonic phrase
Future<MnemonicValidation> validate(String phrase) async {
final result = await _crypto._post('/mnemonic/validate', {'phrase': phrase});
return MnemonicValidation.fromJson(result);
}
/// Derives a seed from a mnemonic
Future<Uint8List> toSeed(String phrase, [String passphrase = '']) async {
final result = await _crypto._post('/mnemonic/to-seed', {
'phrase': phrase,
'passphrase': passphrase,
});
return base64Decode(result['seed'] as String);
}
/// Suggests word completions
Future<List<String>> suggestWords(String partial, [int limit = 10]) async {
final result = await _crypto._post('/mnemonic/suggest', {
'partial': partial,
'limit': limit,
});
return List<String>.from(result['suggestions'] as List);
}
}
/// Keypair operations
class KeypairClient {
final SynorCrypto _crypto;
KeypairClient(this._crypto);
/// Generates a new random keypair
Future<HybridKeypair> generate() async {
final result = await _crypto._post('/keypair/generate');
return HybridKeypair.fromJson(result);
}
/// Creates a keypair from a mnemonic
Future<HybridKeypair> fromMnemonic(String phrase, [String passphrase = '']) async {
final result = await _crypto._post('/keypair/from-mnemonic', {
'phrase': phrase,
'passphrase': passphrase,
});
return HybridKeypair.fromJson(result);
}
/// Creates a keypair from a seed
Future<HybridKeypair> fromSeed(Uint8List seed) async {
final result = await _crypto._post('/keypair/from-seed', {
'seed': base64Encode(seed),
});
return HybridKeypair.fromJson(result);
}
/// Derives a child keypair
Future<HybridKeypair> derive(HybridKeypair parent, DerivationPath path) async {
final result = await _crypto._post('/keypair/derive', {
'public_key': parent.publicKey.toJson(),
'path': path.toJson(),
});
return HybridKeypair.fromJson(result);
}
/// Gets the address for a public key
Future<Address> getAddress(HybridPublicKey publicKey, Network network) async {
final result = await _crypto._post('/keypair/address', {
'public_key': publicKey.toJson(),
'network': network.toJson(),
});
return Address.fromJson(result);
}
}
/// Signing operations
class SigningClient {
final SynorCrypto _crypto;
SigningClient(this._crypto);
/// Signs a message with a hybrid keypair
Future<HybridSignature> sign(HybridKeypair keypair, Uint8List message) async {
final result = await _crypto._post('/sign/hybrid', {
'secret_key': {
'ed25519_seed': base64Encode(keypair.secretKey.ed25519Seed),
'master_seed': base64Encode(keypair.secretKey.masterSeed),
},
'message': base64Encode(message),
});
return HybridSignature.fromJson(result);
}
/// Verifies a hybrid signature
Future<bool> verify(
HybridPublicKey publicKey,
Uint8List message,
HybridSignature signature,
) async {
final result = await _crypto._post('/sign/verify', {
'public_key': publicKey.toJson(),
'message': base64Encode(message),
'signature': signature.toJson(),
});
return result['valid'] as bool;
}
/// Signs with Ed25519 only
Future<Uint8List> signEd25519(Uint8List secretKey, Uint8List message) async {
final result = await _crypto._post('/sign/ed25519', {
'secret_key': base64Encode(secretKey),
'message': base64Encode(message),
});
return base64Decode(result['signature'] as String);
}
/// Verifies an Ed25519 signature
Future<bool> verifyEd25519(
Uint8List publicKey,
Uint8List message,
Uint8List signature,
) async {
final result = await _crypto._post('/sign/verify-ed25519', {
'public_key': base64Encode(publicKey),
'message': base64Encode(message),
'signature': base64Encode(signature),
});
return result['valid'] as bool;
}
}
/// Falcon operations
class FalconClient {
final SynorCrypto _crypto;
FalconClient(this._crypto);
/// Generates a Falcon keypair
Future<FalconKeypair> generate([FalconVariant variant = FalconVariant.falcon512]) async {
final result = await _crypto._post('/falcon/generate', {'variant': variant.toJson()});
return FalconKeypair.fromJson(result);
}
/// Signs with Falcon
Future<FalconSignature> sign(FalconKeypair keypair, Uint8List message) async {
final result = await _crypto._post('/falcon/sign', {
'variant': keypair.variant.toJson(),
'secret_key': base64Encode(keypair.secretKey.bytes),
'message': base64Encode(message),
});
return FalconSignature.fromJson(result);
}
/// Verifies a Falcon signature
Future<bool> verify(
Uint8List publicKey,
Uint8List message,
FalconSignature signature,
) async {
final result = await _crypto._post('/falcon/verify', {
'variant': signature.variant.toJson(),
'public_key': base64Encode(publicKey),
'message': base64Encode(message),
'signature': base64Encode(signature.bytes),
});
return result['valid'] as bool;
}
}
/// SPHINCS+ operations
class SphincsClient {
final SynorCrypto _crypto;
SphincsClient(this._crypto);
/// Generates a SPHINCS+ keypair
Future<SphincsKeypair> generate([SphincsVariant variant = SphincsVariant.shake128s]) async {
final result = await _crypto._post('/sphincs/generate', {'variant': variant.toJson()});
return SphincsKeypair.fromJson(result);
}
/// Signs with SPHINCS+
Future<SphincsSignature> sign(SphincsKeypair keypair, Uint8List message) async {
final result = await _crypto._post('/sphincs/sign', {
'variant': keypair.variant.toJson(),
'secret_key': base64Encode(keypair.secretKey.bytes),
'message': base64Encode(message),
});
return SphincsSignature.fromJson(result);
}
/// Verifies a SPHINCS+ signature
Future<bool> verify(
Uint8List publicKey,
Uint8List message,
SphincsSignature signature,
) async {
final result = await _crypto._post('/sphincs/verify', {
'variant': signature.variant.toJson(),
'public_key': base64Encode(publicKey),
'message': base64Encode(message),
'signature': base64Encode(signature.bytes),
});
return result['valid'] as bool;
}
}
/// Key derivation operations
class KdfClient {
final SynorCrypto _crypto;
KdfClient(this._crypto);
/// Derives a key using HKDF
Future<Uint8List> deriveKey(Uint8List seed, [DerivationConfig? config]) async {
config ??= const DerivationConfig();
final body = <String, dynamic>{
'seed': base64Encode(seed),
'output_length': config.outputLength,
};
if (config.salt != null) body['salt'] = base64Encode(config.salt!);
if (config.info != null) body['info'] = base64Encode(config.info!);
final result = await _crypto._post('/kdf/hkdf', body);
return base64Decode(result['key'] as String);
}
/// Derives a key from a password
Future<Uint8List> deriveFromPassword(
String password,
PasswordDerivationConfig config,
) async {
final result = await _crypto._post('/kdf/pbkdf2', {
'password': base64Encode(utf8.encode(password)),
'salt': base64Encode(config.salt),
'iterations': config.iterations,
'output_length': config.outputLength,
});
return base64Decode(result['key'] as String);
}
/// Derives a child key
Future<({Uint8List key, Uint8List chainCode})> deriveChildKey(
Uint8List parentKey,
Uint8List chainCode,
int index,
) async {
final result = await _crypto._post('/kdf/child', {
'parent_key': base64Encode(parentKey),
'chain_code': base64Encode(chainCode),
'index': index,
});
return (
key: base64Decode(result['key'] as String),
chainCode: base64Decode(result['chain_code'] as String),
);
}
}
/// Hashing operations
class HashClient {
final SynorCrypto _crypto;
HashClient(this._crypto);
/// Computes SHA3-256 hash
Future<Hash256> sha3_256(Uint8List data) async {
final result = await _crypto._post('/hash/sha3-256', {
'data': base64Encode(data),
});
return Hash256.fromJson(result);
}
/// Computes BLAKE3 hash
Future<Hash256> blake3(Uint8List data) async {
final result = await _crypto._post('/hash/blake3', {
'data': base64Encode(data),
});
return Hash256.fromJson(result);
}
/// Computes Keccak-256 hash
Future<Hash256> keccak256(Uint8List data) async {
final result = await _crypto._post('/hash/keccak256', {
'data': base64Encode(data),
});
return Hash256.fromJson(result);
}
/// Combines multiple hashes
Future<Hash256> combine(List<Uint8List> hashes) async {
final result = await _crypto._post('/hash/combine', {
'hashes': hashes.map(base64Encode).toList(),
});
return Hash256.fromJson(result);
}
}
/// Algorithm negotiation operations
class NegotiationClient {
final SynorCrypto _crypto;
NegotiationClient(this._crypto);
/// Gets local capabilities
Future<AlgorithmCapabilities> getCapabilities() async {
final result = await _crypto._get('/negotiation/capabilities');
return AlgorithmCapabilities.fromJson(result);
}
/// Negotiates with a peer
Future<NegotiationResult> negotiate(
AlgorithmCapabilities peerCapabilities,
NegotiationPolicy policy,
) async {
final result = await _crypto._post('/negotiation/negotiate', {
'peer_capabilities': {
'pq_algorithms': peerCapabilities.pqAlgorithms.map((e) => e.toJson()).toList(),
'classical': peerCapabilities.classical,
'hybrid': peerCapabilities.hybrid,
'preferred': peerCapabilities.preferred?.toJson(),
},
'policy': policy.toJson(),
});
return NegotiationResult.fromJson(result);
}
/// Establishes session parameters
Future<SessionParams> establishSession(
NegotiationResult result,
Uint8List peerPublicKey,
) async {
final resp = await _crypto._post('/negotiation/session', {
'negotiation_result': {
'algorithm': result.algorithm.toJson(),
'security_level': result.securityLevel,
'family': result.family.toJson(),
'hybrid': result.hybrid,
},
'peer_public_key': base64Encode(peerPublicKey),
});
return SessionParams.fromJson(resp);
}
}

View file

@ -0,0 +1,658 @@
/// Synor Crypto SDK Types for Flutter/Dart
///
/// Quantum-resistant cryptographic types for the Synor blockchain.
library synor_crypto_types;
import 'dart:convert';
import 'dart:typed_data';
// ============================================================================
// Enumerations
// ============================================================================
/// Network type for address generation
enum Network {
mainnet,
testnet,
devnet;
String toJson() => name;
static Network fromJson(String json) => Network.values.byName(json);
}
/// Falcon variant selection
enum FalconVariant {
falcon512,
falcon1024;
String toJson() => name;
static FalconVariant fromJson(String json) => FalconVariant.values.byName(json);
/// Returns the signature size for this variant
int get signatureSize => this == falcon512 ? 690 : 1330;
/// Returns the public key size for this variant
int get publicKeySize => this == falcon512 ? 897 : 1793;
/// Returns the security level in bits
int get securityLevel => this == falcon512 ? 128 : 256;
}
/// SPHINCS+ variant selection
enum SphincsVariant {
shake128s,
shake192s,
shake256s;
String toJson() => name;
static SphincsVariant fromJson(String json) => SphincsVariant.values.byName(json);
/// Returns the signature size for this variant
int get signatureSize {
switch (this) {
case shake128s:
return 7856;
case shake192s:
return 16224;
case shake256s:
return 29792;
}
}
/// Returns the security level in bits
int get securityLevel {
switch (this) {
case shake128s:
return 128;
case shake192s:
return 192;
case shake256s:
return 256;
}
}
}
/// Post-quantum algorithm selection
enum PqAlgorithm {
dilithium3,
falcon512,
falcon1024,
sphincs128s,
sphincs192s,
sphincs256s;
String toJson() => name;
static PqAlgorithm fromJson(String json) => PqAlgorithm.values.byName(json);
}
/// Algorithm family classification
enum AlgorithmFamily {
classical,
lattice,
hashBased,
hybrid;
String toJson() => name;
static AlgorithmFamily fromJson(String json) => AlgorithmFamily.values.byName(json);
}
// ============================================================================
// Configuration Types
// ============================================================================
/// Crypto SDK configuration
class CryptoConfig {
final String apiKey;
final String endpoint;
final int timeout;
final int retries;
final bool debug;
final Network defaultNetwork;
const CryptoConfig({
required this.apiKey,
this.endpoint = 'https://crypto.synor.io/v1',
this.timeout = 30000,
this.retries = 3,
this.debug = false,
this.defaultNetwork = Network.mainnet,
});
}
/// Key derivation configuration
class DerivationConfig {
final Uint8List? salt;
final Uint8List? info;
final int outputLength;
const DerivationConfig({
this.salt,
this.info,
this.outputLength = 32,
});
}
/// Password derivation configuration
class PasswordDerivationConfig {
final Uint8List salt;
final int iterations;
final int outputLength;
const PasswordDerivationConfig({
required this.salt,
this.iterations = 100000,
this.outputLength = 32,
});
}
/// BIP-44 derivation path
class DerivationPath {
static const int coinType = 0x5359; // Synor coin type
final int account;
final int change;
final int index;
const DerivationPath({
this.account = 0,
this.change = 0,
this.index = 0,
});
factory DerivationPath.external(int account, int index) =>
DerivationPath(account: account, change: 0, index: index);
factory DerivationPath.internal(int account, int index) =>
DerivationPath(account: account, change: 1, index: index);
@override
String toString() => "m/44'/$coinType'/$account'/$change/$index";
Map<String, dynamic> toJson() => {
'account': account,
'change': change,
'index': index,
};
}
// ============================================================================
// Key Types
// ============================================================================
/// Hybrid public key (Ed25519 + Dilithium3)
class HybridPublicKey {
/// Ed25519 component (32 bytes)
final Uint8List ed25519;
/// Dilithium3 component (~1952 bytes)
final Uint8List dilithium;
const HybridPublicKey({
required this.ed25519,
required this.dilithium,
});
/// Returns the total size in bytes
int get size => ed25519.length + dilithium.length;
factory HybridPublicKey.fromJson(Map<String, dynamic> json) => HybridPublicKey(
ed25519: base64Decode(json['ed25519'] as String),
dilithium: base64Decode(json['dilithium'] as String),
);
Map<String, dynamic> toJson() => {
'ed25519': base64Encode(ed25519),
'dilithium': base64Encode(dilithium),
};
}
/// Secret key (master seed)
class SecretKey {
/// Ed25519 seed (32 bytes)
final Uint8List ed25519Seed;
/// Master seed (64 bytes)
final Uint8List masterSeed;
const SecretKey({
required this.ed25519Seed,
required this.masterSeed,
});
factory SecretKey.fromJson(Map<String, dynamic> json) => SecretKey(
ed25519Seed: base64Decode(json['ed25519_seed'] as String),
masterSeed: base64Decode(json['master_seed'] as String),
);
}
/// Falcon public key
class FalconPublicKey {
final FalconVariant variant;
final Uint8List bytes;
const FalconPublicKey({required this.variant, required this.bytes});
factory FalconPublicKey.fromJson(Map<String, dynamic> json) => FalconPublicKey(
variant: FalconVariant.fromJson(json['variant'] as String),
bytes: base64Decode(json['bytes'] as String),
);
}
/// Falcon secret key
class FalconSecretKey {
final FalconVariant variant;
final Uint8List bytes;
const FalconSecretKey({required this.variant, required this.bytes});
factory FalconSecretKey.fromJson(Map<String, dynamic> json) => FalconSecretKey(
variant: FalconVariant.fromJson(json['variant'] as String),
bytes: base64Decode(json['bytes'] as String),
);
}
/// SPHINCS+ public key
class SphincsPublicKey {
final SphincsVariant variant;
final Uint8List bytes;
const SphincsPublicKey({required this.variant, required this.bytes});
factory SphincsPublicKey.fromJson(Map<String, dynamic> json) => SphincsPublicKey(
variant: SphincsVariant.fromJson(json['variant'] as String),
bytes: base64Decode(json['bytes'] as String),
);
}
/// SPHINCS+ secret key
class SphincsSecretKey {
final SphincsVariant variant;
final Uint8List bytes;
const SphincsSecretKey({required this.variant, required this.bytes});
factory SphincsSecretKey.fromJson(Map<String, dynamic> json) => SphincsSecretKey(
variant: SphincsVariant.fromJson(json['variant'] as String),
bytes: base64Decode(json['bytes'] as String),
);
}
// ============================================================================
// Signature Types
// ============================================================================
/// Hybrid signature (Ed25519 + Dilithium3)
class HybridSignature {
/// Ed25519 component (64 bytes)
final Uint8List ed25519;
/// Dilithium3 component (~3293 bytes)
final Uint8List dilithium;
const HybridSignature({
required this.ed25519,
required this.dilithium,
});
/// Returns the total size in bytes
int get size => ed25519.length + dilithium.length;
/// Serializes to bytes
Uint8List toBytes() {
final result = Uint8List(size);
result.setAll(0, ed25519);
result.setAll(ed25519.length, dilithium);
return result;
}
factory HybridSignature.fromBytes(Uint8List data) {
if (data.length < 64) {
throw ArgumentError('Invalid signature length');
}
return HybridSignature(
ed25519: Uint8List.fromList(data.sublist(0, 64)),
dilithium: Uint8List.fromList(data.sublist(64)),
);
}
factory HybridSignature.fromJson(Map<String, dynamic> json) => HybridSignature(
ed25519: base64Decode(json['ed25519'] as String),
dilithium: base64Decode(json['dilithium'] as String),
);
Map<String, dynamic> toJson() => {
'ed25519': base64Encode(ed25519),
'dilithium': base64Encode(dilithium),
};
}
/// Falcon signature
class FalconSignature {
final FalconVariant variant;
final Uint8List bytes;
const FalconSignature({required this.variant, required this.bytes});
int get size => bytes.length;
factory FalconSignature.fromJson(Map<String, dynamic> json) => FalconSignature(
variant: FalconVariant.fromJson(json['variant'] as String),
bytes: base64Decode(json['signature'] as String),
);
}
/// SPHINCS+ signature
class SphincsSignature {
final SphincsVariant variant;
final Uint8List bytes;
const SphincsSignature({required this.variant, required this.bytes});
int get size => bytes.length;
factory SphincsSignature.fromJson(Map<String, dynamic> json) => SphincsSignature(
variant: SphincsVariant.fromJson(json['variant'] as String),
bytes: base64Decode(json['signature'] as String),
);
}
// ============================================================================
// Keypair Types
// ============================================================================
/// Hybrid keypair (Ed25519 + Dilithium3)
class HybridKeypair {
final HybridPublicKey publicKey;
final SecretKey secretKey;
final Map<Network, String> _addresses;
const HybridKeypair({
required this.publicKey,
required this.secretKey,
Map<Network, String> addresses = const {},
}) : _addresses = addresses;
/// Returns the address for a network
String address(Network network) => _addresses[network] ?? '';
factory HybridKeypair.fromJson(Map<String, dynamic> json) {
final addressesJson = json['addresses'] as Map<String, dynamic>? ?? {};
final addresses = <Network, String>{};
addressesJson.forEach((k, v) {
try {
addresses[Network.fromJson(k)] = v as String;
} catch (_) {}
});
return HybridKeypair(
publicKey: HybridPublicKey.fromJson(json['public_key'] as Map<String, dynamic>),
secretKey: SecretKey.fromJson(json['secret_key'] as Map<String, dynamic>),
addresses: addresses,
);
}
}
/// Falcon keypair
class FalconKeypair {
final FalconVariant variant;
final FalconPublicKey publicKey;
final FalconSecretKey secretKey;
const FalconKeypair({
required this.variant,
required this.publicKey,
required this.secretKey,
});
factory FalconKeypair.fromJson(Map<String, dynamic> json) => FalconKeypair(
variant: FalconVariant.fromJson(json['variant'] as String),
publicKey: FalconPublicKey.fromJson(json['public_key'] as Map<String, dynamic>),
secretKey: FalconSecretKey.fromJson(json['secret_key'] as Map<String, dynamic>),
);
}
/// SPHINCS+ keypair
class SphincsKeypair {
final SphincsVariant variant;
final SphincsPublicKey publicKey;
final SphincsSecretKey secretKey;
const SphincsKeypair({
required this.variant,
required this.publicKey,
required this.secretKey,
});
factory SphincsKeypair.fromJson(Map<String, dynamic> json) => SphincsKeypair(
variant: SphincsVariant.fromJson(json['variant'] as String),
publicKey: SphincsPublicKey.fromJson(json['public_key'] as Map<String, dynamic>),
secretKey: SphincsSecretKey.fromJson(json['secret_key'] as Map<String, dynamic>),
);
}
// ============================================================================
// Mnemonic Types
// ============================================================================
/// BIP-39 mnemonic phrase
class Mnemonic {
final String phrase;
final List<String> words;
final int wordCount;
final Uint8List entropy;
const Mnemonic({
required this.phrase,
required this.words,
required this.wordCount,
required this.entropy,
});
factory Mnemonic.fromJson(Map<String, dynamic> json) => Mnemonic(
phrase: json['phrase'] as String,
words: List<String>.from(json['words'] ?? (json['phrase'] as String).split(' ')),
wordCount: json['word_count'] as int? ?? (json['phrase'] as String).split(' ').length,
entropy: json['entropy'] != null ? base64Decode(json['entropy'] as String) : Uint8List(0),
);
}
/// Mnemonic validation result
class MnemonicValidation {
final bool valid;
final String? error;
const MnemonicValidation({required this.valid, this.error});
factory MnemonicValidation.fromJson(Map<String, dynamic> json) => MnemonicValidation(
valid: json['valid'] as bool,
error: json['error'] as String?,
);
}
// ============================================================================
// Address Types
// ============================================================================
/// Blockchain address
class Address {
final String address;
final Network network;
final Uint8List pubkeyHash;
const Address({
required this.address,
required this.network,
required this.pubkeyHash,
});
factory Address.fromJson(Map<String, dynamic> json) => Address(
address: json['address'] as String,
network: Network.fromJson(json['network'] as String),
pubkeyHash: json['pubkey_hash'] != null
? base64Decode(json['pubkey_hash'] as String)
: Uint8List(0),
);
}
// ============================================================================
// Hash Types
// ============================================================================
/// 256-bit hash
class Hash256 {
final Uint8List bytes;
final String hex;
const Hash256({required this.bytes, required this.hex});
factory Hash256.fromJson(Map<String, dynamic> json) {
final hexStr = json['hash'] as String;
return Hash256(
bytes: _hexDecode(hexStr),
hex: hexStr,
);
}
}
Uint8List _hexDecode(String hex) {
final result = Uint8List(hex.length ~/ 2);
for (var i = 0; i < result.length; i++) {
result[i] = int.parse(hex.substring(i * 2, i * 2 + 2), radix: 16);
}
return result;
}
// ============================================================================
// Negotiation Types
// ============================================================================
/// Algorithm capabilities for negotiation
class AlgorithmCapabilities {
final List<PqAlgorithm> pqAlgorithms;
final bool classical;
final bool hybrid;
final PqAlgorithm? preferred;
const AlgorithmCapabilities({
required this.pqAlgorithms,
this.classical = true,
this.hybrid = true,
this.preferred,
});
factory AlgorithmCapabilities.fromJson(Map<String, dynamic> json) => AlgorithmCapabilities(
pqAlgorithms: (json['pq_algorithms'] as List)
.map((e) => PqAlgorithm.fromJson(e as String))
.toList(),
classical: json['classical'] as bool? ?? true,
hybrid: json['hybrid'] as bool? ?? true,
preferred: json['preferred'] != null
? PqAlgorithm.fromJson(json['preferred'] as String)
: null,
);
}
/// Negotiation policy
class NegotiationPolicy {
final int minSecurityLevel;
final bool preferCompact;
final bool allowClassical;
final List<AlgorithmFamily> requiredFamilies;
const NegotiationPolicy({
this.minSecurityLevel = 128,
this.preferCompact = false,
this.allowClassical = false,
this.requiredFamilies = const [],
});
Map<String, dynamic> toJson() => {
'min_security_level': minSecurityLevel,
'prefer_compact': preferCompact,
'allow_classical': allowClassical,
'required_families': requiredFamilies.map((e) => e.toJson()).toList(),
};
}
/// Negotiation result
class NegotiationResult {
final PqAlgorithm algorithm;
final int securityLevel;
final AlgorithmFamily family;
final bool hybrid;
const NegotiationResult({
required this.algorithm,
required this.securityLevel,
required this.family,
required this.hybrid,
});
factory NegotiationResult.fromJson(Map<String, dynamic> json) => NegotiationResult(
algorithm: PqAlgorithm.fromJson(json['algorithm'] as String),
securityLevel: json['security_level'] as int,
family: AlgorithmFamily.fromJson(json['family'] as String),
hybrid: json['hybrid'] as bool,
);
}
/// Session parameters after negotiation
class SessionParams {
final PqAlgorithm algorithm;
final Uint8List? sessionKey;
final int? expiresAt;
const SessionParams({
required this.algorithm,
this.sessionKey,
this.expiresAt,
});
factory SessionParams.fromJson(Map<String, dynamic> json) => SessionParams(
algorithm: PqAlgorithm.fromJson(json['algorithm'] as String),
sessionKey: json['session_key'] != null
? base64Decode(json['session_key'] as String)
: null,
expiresAt: json['expires_at'] as int?,
);
}
// ============================================================================
// Error Types
// ============================================================================
/// Crypto operation error
class CryptoException implements Exception {
final String message;
final String? code;
const CryptoException(this.message, [this.code]);
@override
String toString() =>
code != null ? 'CryptoException: $message (code: $code)' : 'CryptoException: $message';
}
// ============================================================================
// Constants
// ============================================================================
abstract class CryptoConstants {
static const int ed25519PublicKeySize = 32;
static const int ed25519SecretKeySize = 32;
static const int ed25519SignatureSize = 64;
static const int dilithium3PublicKeySize = 1952;
static const int dilithium3SignatureSize = 3293;
static const int hybridSignatureSize = 64 + 3293;
static const int falcon512SignatureSize = 690;
static const int falcon512PublicKeySize = 897;
static const int falcon1024SignatureSize = 1330;
static const int falcon1024PublicKeySize = 1793;
static const int sphincs128sSignatureSize = 7856;
static const int sphincs192sSignatureSize = 16224;
static const int sphincs256sSignatureSize = 29792;
static const int coinType = 0x5359;
static const int minPbkdf2Iterations = 10000;
static const int minSaltLength = 8;
static const String defaultEndpoint = 'https://crypto.synor.io/v1';
}

691
sdk/go/crypto/client.go Normal file
View file

@ -0,0 +1,691 @@
// 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
}

479
sdk/go/crypto/types.go Normal file
View file

@ -0,0 +1,479 @@
// Package crypto provides quantum-resistant cryptographic primitives for the Synor blockchain.
package crypto
import (
"encoding/base64"
"encoding/hex"
"fmt"
)
// ============================================================================
// Enumerations
// ============================================================================
// Network type for address generation
type Network string
const (
NetworkMainnet Network = "mainnet"
NetworkTestnet Network = "testnet"
NetworkDevnet Network = "devnet"
)
// FalconVariant selection
type FalconVariant string
const (
Falcon512 FalconVariant = "falcon512" // 128-bit security, ~690 byte signatures
Falcon1024 FalconVariant = "falcon1024" // 256-bit security, ~1330 byte signatures
)
// SphincsVariant selection
type SphincsVariant string
const (
Shake128s SphincsVariant = "shake128s" // 128-bit security, ~7.8KB signatures
Shake192s SphincsVariant = "shake192s" // 192-bit security, ~16KB signatures
Shake256s SphincsVariant = "shake256s" // 256-bit security, ~30KB signatures
)
// PqAlgorithm post-quantum algorithm selection
type PqAlgorithm string
const (
Dilithium3 PqAlgorithm = "dilithium3"
PqFalcon512 PqAlgorithm = "falcon512"
PqFalcon1024 PqAlgorithm = "falcon1024"
Sphincs128s PqAlgorithm = "sphincs128s"
Sphincs192s PqAlgorithm = "sphincs192s"
Sphincs256s PqAlgorithm = "sphincs256s"
)
// AlgorithmFamily classification
type AlgorithmFamily string
const (
Classical AlgorithmFamily = "classical"
Lattice AlgorithmFamily = "lattice"
HashBased AlgorithmFamily = "hash_based"
Hybrid AlgorithmFamily = "hybrid"
)
// ============================================================================
// Configuration Types
// ============================================================================
// Config for the crypto SDK
type Config struct {
APIKey string
Endpoint string
Timeout int // milliseconds
Retries int
Debug bool
DefaultNetwork Network
}
// DefaultConfig returns a config with sensible defaults
func DefaultConfig(apiKey string) Config {
return Config{
APIKey: apiKey,
Endpoint: "https://crypto.synor.io/v1",
Timeout: 30000,
Retries: 3,
Debug: false,
DefaultNetwork: NetworkMainnet,
}
}
// DerivationConfig for key derivation
type DerivationConfig struct {
Salt []byte
Info []byte
OutputLength int
}
// PasswordDerivationConfig for password-based key derivation
type PasswordDerivationConfig struct {
Salt []byte
Iterations int
OutputLength int
}
// DerivationPath BIP-44 style path
type DerivationPath struct {
Account int
Change int
Index int
}
// CoinType for Synor in BIP-44
const CoinType = 0x5359
// String formats the derivation path
func (p DerivationPath) String() string {
return fmt.Sprintf("m/44'/%d'/%d'/%d/%d", CoinType, p.Account, p.Change, p.Index)
}
// ExternalPath creates a path for external addresses
func ExternalPath(account, index int) DerivationPath {
return DerivationPath{Account: account, Change: 0, Index: index}
}
// InternalPath creates a path for internal (change) addresses
func InternalPath(account, index int) DerivationPath {
return DerivationPath{Account: account, Change: 1, Index: index}
}
// ============================================================================
// Key Types
// ============================================================================
// HybridPublicKey combines Ed25519 and Dilithium3
type HybridPublicKey struct {
Ed25519 []byte // 32 bytes
Dilithium []byte // ~1952 bytes
}
// Size returns the total key size
func (pk *HybridPublicKey) Size() int {
return len(pk.Ed25519) + len(pk.Dilithium)
}
// SecretKey holds the master seed
type SecretKey struct {
Ed25519Seed []byte // 32 bytes
MasterSeed []byte // 64 bytes
}
// FalconPublicKey for Falcon signatures
type FalconPublicKey struct {
Variant FalconVariant
Bytes []byte
}
// FalconSecretKey for Falcon signatures
type FalconSecretKey struct {
Variant FalconVariant
Bytes []byte
}
// SphincsPublicKey for SPHINCS+ signatures
type SphincsPublicKey struct {
Variant SphincsVariant
Bytes []byte
}
// SphincsSecretKey for SPHINCS+ signatures
type SphincsSecretKey struct {
Variant SphincsVariant
Bytes []byte
}
// ============================================================================
// Signature Types
// ============================================================================
// HybridSignature combines Ed25519 and Dilithium3 signatures
type HybridSignature struct {
Ed25519 []byte // 64 bytes
Dilithium []byte // ~3293 bytes
}
// Size returns the total signature size
func (s *HybridSignature) Size() int {
return len(s.Ed25519) + len(s.Dilithium)
}
// ToBytes serializes the signature
func (s *HybridSignature) ToBytes() []byte {
result := make([]byte, len(s.Ed25519)+len(s.Dilithium))
copy(result, s.Ed25519)
copy(result[len(s.Ed25519):], s.Dilithium)
return result
}
// HybridSignatureFromBytes deserializes a signature
func HybridSignatureFromBytes(data []byte) (*HybridSignature, error) {
if len(data) < 64 {
return nil, fmt.Errorf("invalid signature length: %d", len(data))
}
return &HybridSignature{
Ed25519: data[:64],
Dilithium: data[64:],
}, nil
}
// FalconSignature for Falcon
type FalconSignature struct {
Variant FalconVariant
Bytes []byte
}
// Size returns the signature size
func (s *FalconSignature) Size() int {
return len(s.Bytes)
}
// SphincsSignature for SPHINCS+
type SphincsSignature struct {
Variant SphincsVariant
Bytes []byte
}
// Size returns the signature size
func (s *SphincsSignature) Size() int {
return len(s.Bytes)
}
// ============================================================================
// Keypair Types
// ============================================================================
// HybridKeypair combines Ed25519 and Dilithium3
type HybridKeypair struct {
PublicKey *HybridPublicKey
SecretKey *SecretKey
addresses map[Network]string
}
// Address returns the address for a network
func (kp *HybridKeypair) Address(network Network) string {
if kp.addresses == nil {
return ""
}
return kp.addresses[network]
}
// FalconKeypair for Falcon signatures
type FalconKeypair struct {
Variant FalconVariant
PublicKey *FalconPublicKey
SecretKey *FalconSecretKey
}
// SphincsKeypair for SPHINCS+ signatures
type SphincsKeypair struct {
Variant SphincsVariant
PublicKey *SphincsPublicKey
SecretKey *SphincsSecretKey
}
// ============================================================================
// Mnemonic Types
// ============================================================================
// Mnemonic BIP-39 phrase
type Mnemonic struct {
Phrase string
Words []string
WordCount int
Entropy []byte
}
// MnemonicValidation result
type MnemonicValidation struct {
Valid bool
Error string
}
// ============================================================================
// Address Types
// ============================================================================
// Address on the blockchain
type Address struct {
Address string
Network Network
PubkeyHash []byte
}
// ============================================================================
// Hash Types
// ============================================================================
// Hash256 is a 256-bit hash
type Hash256 struct {
Bytes []byte
Hex string
}
// NewHash256 creates a hash from bytes
func NewHash256(bytes []byte) Hash256 {
return Hash256{
Bytes: bytes,
Hex: hex.EncodeToString(bytes),
}
}
// ============================================================================
// Negotiation Types
// ============================================================================
// AlgorithmCapabilities for negotiation
type AlgorithmCapabilities struct {
PqAlgorithms []PqAlgorithm
Classical bool
Hybrid bool
Preferred *PqAlgorithm
}
// NegotiationPolicy for algorithm selection
type NegotiationPolicy struct {
MinSecurityLevel int
PreferCompact bool
AllowClassical bool
RequiredFamilies []AlgorithmFamily
}
// NegotiationResult after negotiation
type NegotiationResult struct {
Algorithm PqAlgorithm
SecurityLevel int
Family AlgorithmFamily
Hybrid bool
}
// SessionParams after establishing a session
type SessionParams struct {
Algorithm PqAlgorithm
SessionKey []byte
ExpiresAt *int64
}
// ============================================================================
// Error Types
// ============================================================================
// CryptoError represents a crypto operation error
type CryptoError struct {
Message string
Code string
}
func (e *CryptoError) Error() string {
if e.Code != "" {
return fmt.Sprintf("%s (code: %s)", e.Message, e.Code)
}
return e.Message
}
// NewCryptoError creates a new error
func NewCryptoError(message, code string) *CryptoError {
return &CryptoError{Message: message, Code: code}
}
// ============================================================================
// Constants
// ============================================================================
const (
Ed25519PublicKeySize = 32
Ed25519SecretKeySize = 32
Ed25519SignatureSize = 64
Dilithium3PublicKeySize = 1952
Dilithium3SignatureSize = 3293
HybridSignatureSize = 64 + 3293
Falcon512SignatureSize = 690
Falcon512PublicKeySize = 897
Falcon1024SignatureSize = 1330
Falcon1024PublicKeySize = 1793
Sphincs128sSignatureSize = 7856
Sphincs192sSignatureSize = 16224
Sphincs256sSignatureSize = 29792
MinPBKDF2Iterations = 10000
MinSaltLength = 8
DefaultEndpoint = "https://crypto.synor.io/v1"
)
// AlgorithmSizes maps algorithms to their sizes
var AlgorithmSizes = map[string]struct {
Signature int
PublicKey int
}{
"ed25519": {64, 32},
"dilithium3": {3293, 1952},
"hybrid": {3357, 1984},
"falcon512": {690, 897},
"falcon1024": {1330, 1793},
"sphincs128s": {7856, 32},
"sphincs192s": {16224, 48},
"sphincs256s": {29792, 64},
}
// ============================================================================
// Helper Functions
// ============================================================================
// EncodeBase64 encodes bytes to base64
func EncodeBase64(data []byte) string {
return base64.StdEncoding.EncodeToString(data)
}
// DecodeBase64 decodes base64 to bytes
func DecodeBase64(s string) ([]byte, error) {
return base64.StdEncoding.DecodeString(s)
}
// FalconSignatureSize returns the signature size for a variant
func FalconSignatureSize(variant FalconVariant) int {
switch variant {
case Falcon512:
return Falcon512SignatureSize
case Falcon1024:
return Falcon1024SignatureSize
default:
return 0
}
}
// FalconPublicKeySize returns the public key size for a variant
func FalconPublicKeySize(variant FalconVariant) int {
switch variant {
case Falcon512:
return Falcon512PublicKeySize
case Falcon1024:
return Falcon1024PublicKeySize
default:
return 0
}
}
// FalconSecurityLevel returns the security level for a variant
func FalconSecurityLevel(variant FalconVariant) int {
switch variant {
case Falcon512:
return 128
case Falcon1024:
return 256
default:
return 0
}
}
// SphincsSignatureSize returns the signature size for a variant
func SphincsSignatureSize(variant SphincsVariant) int {
switch variant {
case Shake128s:
return Sphincs128sSignatureSize
case Shake192s:
return Sphincs192sSignatureSize
case Shake256s:
return Sphincs256sSignatureSize
default:
return 0
}
}
// SphincsSecurityLevel returns the security level for a variant
func SphincsSecurityLevel(variant SphincsVariant) int {
switch variant {
case Shake128s:
return 128
case Shake192s:
return 192
case Shake256s:
return 256
default:
return 0
}
}

View file

@ -0,0 +1,351 @@
package io.synor.crypto;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Synor Crypto SDK for Java
*
* Quantum-resistant cryptographic primitives for the Synor blockchain.
*
* <pre>{@code
* CryptoConfig config = new CryptoConfig("your-api-key");
* SynorCrypto crypto = new SynorCrypto(config);
*
* // Generate a mnemonic
* Mnemonic mnemonic = crypto.mnemonic().generate(24).join();
* System.out.println("Backup words: " + mnemonic.getPhrase());
*
* // Create keypair from mnemonic
* HybridKeypair keypair = crypto.keypairs().fromMnemonic(mnemonic.getPhrase(), "").join();
* String address = keypair.getAddress(Network.MAINNET);
*
* // Sign a message
* HybridSignature signature = crypto.signing().sign(keypair, "Hello!".getBytes()).join();
* }</pre>
*/
public class SynorCrypto {
private final CryptoConfig config;
private final HttpClient httpClient;
private final Gson gson;
private final AtomicBoolean closed = new AtomicBoolean(false);
private final MnemonicClient mnemonicClient;
private final KeypairClient keypairClient;
private final SigningClient signingClient;
private final FalconClient falconClient;
private final SphincsClient sphincsClient;
private final KdfClient kdfClient;
private final HashClient hashClient;
public SynorCrypto(CryptoConfig config) {
this.config = config;
this.httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofMillis(config.getTimeout()))
.build();
this.gson = new GsonBuilder()
.setFieldNamingPolicy(com.google.gson.FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create();
this.mnemonicClient = new MnemonicClient(this);
this.keypairClient = new KeypairClient(this);
this.signingClient = new SigningClient(this);
this.falconClient = new FalconClient(this);
this.sphincsClient = new SphincsClient(this);
this.kdfClient = new KdfClient(this);
this.hashClient = new HashClient(this);
}
public Network getDefaultNetwork() {
return config.getDefaultNetwork();
}
public MnemonicClient mnemonic() { return mnemonicClient; }
public KeypairClient keypairs() { return keypairClient; }
public SigningClient signing() { return signingClient; }
public FalconClient falcon() { return falconClient; }
public SphincsClient sphincs() { return sphincsClient; }
public KdfClient kdf() { return kdfClient; }
public HashClient hash() { return hashClient; }
public CompletableFuture<Boolean> healthCheck() {
return get("/health", new TypeToken<Map<String, Object>>() {})
.thenApply(result -> "healthy".equals(result.get("status")))
.exceptionally(e -> false);
}
public CompletableFuture<Map<String, Object>> getInfo() {
return get("/info", new TypeToken<Map<String, Object>>() {});
}
public void close() {
closed.set(true);
}
public boolean isClosed() {
return closed.get();
}
<T> CompletableFuture<T> get(String path, TypeToken<T> type) {
checkClosed();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(config.getEndpoint() + path))
.header("Authorization", "Bearer " + config.getApiKey())
.header("X-SDK-Version", "java/0.1.0")
.GET()
.build();
return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(response -> handleResponse(response, type));
}
<T> CompletableFuture<T> post(String path, Object body, TypeToken<T> type) {
checkClosed();
String jsonBody = body != null ? gson.toJson(body) : "{}";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(config.getEndpoint() + path))
.header("Authorization", "Bearer " + config.getApiKey())
.header("Content-Type", "application/json")
.header("X-SDK-Version", "java/0.1.0")
.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
.build();
return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(response -> handleResponse(response, type));
}
private <T> T handleResponse(HttpResponse<String> response, TypeToken<T> type) {
if (response.statusCode() >= 400) {
Map<String, Object> error = gson.fromJson(response.body(), new TypeToken<Map<String, Object>>() {}.getType());
String message = error != null && error.get("message") != null
? (String) error.get("message")
: "HTTP " + response.statusCode();
String code = error != null ? (String) error.get("code") : null;
throw new CryptoException(message, code);
}
return gson.fromJson(response.body(), type.getType());
}
private void checkClosed() {
if (closed.get()) {
throw new CryptoException("Client has been closed", "CLIENT_CLOSED");
}
}
// ========================================================================
// Sub-Clients
// ========================================================================
public static class MnemonicClient {
private final SynorCrypto crypto;
MnemonicClient(SynorCrypto crypto) { this.crypto = crypto; }
public CompletableFuture<Mnemonic> generate(int wordCount) {
Map<String, Object> body = Map.of("word_count", wordCount);
return crypto.post("/mnemonic/generate", body, new TypeToken<Mnemonic>() {});
}
public CompletableFuture<Mnemonic> fromPhrase(String phrase) {
Map<String, Object> body = Map.of("phrase", phrase);
return crypto.post("/mnemonic/from-phrase", body, new TypeToken<Mnemonic>() {});
}
public CompletableFuture<MnemonicValidation> validate(String phrase) {
Map<String, Object> body = Map.of("phrase", phrase);
return crypto.post("/mnemonic/validate", body, new TypeToken<MnemonicValidation>() {});
}
public CompletableFuture<byte[]> toSeed(String phrase, String passphrase) {
Map<String, Object> body = Map.of("phrase", phrase, "passphrase", passphrase);
return crypto.post("/mnemonic/to-seed", body, new TypeToken<Map<String, String>>() {})
.thenApply(result -> Base64.getDecoder().decode(result.get("seed")));
}
public CompletableFuture<List<String>> suggestWords(String partial, int limit) {
Map<String, Object> body = Map.of("partial", partial, "limit", limit);
return crypto.post("/mnemonic/suggest", body, new TypeToken<Map<String, List<String>>>() {})
.thenApply(result -> result.get("suggestions"));
}
}
public static class KeypairClient {
private final SynorCrypto crypto;
KeypairClient(SynorCrypto crypto) { this.crypto = crypto; }
public CompletableFuture<HybridKeypair> generate() {
return crypto.post("/keypair/generate", null, new TypeToken<HybridKeypair>() {});
}
public CompletableFuture<HybridKeypair> fromMnemonic(String phrase, String passphrase) {
Map<String, Object> body = Map.of("phrase", phrase, "passphrase", passphrase);
return crypto.post("/keypair/from-mnemonic", body, new TypeToken<HybridKeypair>() {});
}
public CompletableFuture<HybridKeypair> fromSeed(byte[] seed) {
Map<String, Object> body = Map.of("seed", Base64.getEncoder().encodeToString(seed));
return crypto.post("/keypair/from-seed", body, new TypeToken<HybridKeypair>() {});
}
public CompletableFuture<Address> getAddress(HybridPublicKey publicKey, Network network) {
Map<String, Object> body = Map.of(
"public_key", publicKey.toMap(),
"network", network.getValue()
);
return crypto.post("/keypair/address", body, new TypeToken<Address>() {});
}
}
public static class SigningClient {
private final SynorCrypto crypto;
SigningClient(SynorCrypto crypto) { this.crypto = crypto; }
public CompletableFuture<HybridSignature> sign(HybridKeypair keypair, byte[] message) {
Map<String, Object> body = Map.of(
"secret_key", keypair.getSecretKey().toMap(),
"message", Base64.getEncoder().encodeToString(message)
);
return crypto.post("/sign/hybrid", body, new TypeToken<HybridSignature>() {});
}
public CompletableFuture<Boolean> verify(HybridPublicKey publicKey, byte[] message, HybridSignature signature) {
Map<String, Object> body = Map.of(
"public_key", publicKey.toMap(),
"message", Base64.getEncoder().encodeToString(message),
"signature", signature.toMap()
);
return crypto.post("/sign/verify", body, new TypeToken<Map<String, Boolean>>() {})
.thenApply(result -> result.get("valid"));
}
public CompletableFuture<byte[]> signEd25519(byte[] secretKey, byte[] message) {
Map<String, Object> body = Map.of(
"secret_key", Base64.getEncoder().encodeToString(secretKey),
"message", Base64.getEncoder().encodeToString(message)
);
return crypto.post("/sign/ed25519", body, new TypeToken<Map<String, String>>() {})
.thenApply(result -> Base64.getDecoder().decode(result.get("signature")));
}
}
public static class FalconClient {
private final SynorCrypto crypto;
FalconClient(SynorCrypto crypto) { this.crypto = crypto; }
public CompletableFuture<FalconKeypair> generate(FalconVariant variant) {
Map<String, Object> body = Map.of("variant", variant.getValue());
return crypto.post("/falcon/generate", body, new TypeToken<FalconKeypair>() {});
}
public CompletableFuture<FalconSignature> sign(FalconKeypair keypair, byte[] message) {
Map<String, Object> body = Map.of(
"variant", keypair.getVariant().getValue(),
"secret_key", Base64.getEncoder().encodeToString(keypair.getSecretKey().getBytes()),
"message", Base64.getEncoder().encodeToString(message)
);
return crypto.post("/falcon/sign", body, new TypeToken<FalconSignature>() {});
}
public CompletableFuture<Boolean> verify(byte[] publicKey, byte[] message, FalconSignature signature) {
Map<String, Object> body = Map.of(
"variant", signature.getVariant().getValue(),
"public_key", Base64.getEncoder().encodeToString(publicKey),
"message", Base64.getEncoder().encodeToString(message),
"signature", Base64.getEncoder().encodeToString(signature.getBytes())
);
return crypto.post("/falcon/verify", body, new TypeToken<Map<String, Boolean>>() {})
.thenApply(result -> result.get("valid"));
}
}
public static class SphincsClient {
private final SynorCrypto crypto;
SphincsClient(SynorCrypto crypto) { this.crypto = crypto; }
public CompletableFuture<SphincsKeypair> generate(SphincsVariant variant) {
Map<String, Object> body = Map.of("variant", variant.getValue());
return crypto.post("/sphincs/generate", body, new TypeToken<SphincsKeypair>() {});
}
public CompletableFuture<SphincsSignature> sign(SphincsKeypair keypair, byte[] message) {
Map<String, Object> body = Map.of(
"variant", keypair.getVariant().getValue(),
"secret_key", Base64.getEncoder().encodeToString(keypair.getSecretKey().getBytes()),
"message", Base64.getEncoder().encodeToString(message)
);
return crypto.post("/sphincs/sign", body, new TypeToken<SphincsSignature>() {});
}
public CompletableFuture<Boolean> verify(byte[] publicKey, byte[] message, SphincsSignature signature) {
Map<String, Object> body = Map.of(
"variant", signature.getVariant().getValue(),
"public_key", Base64.getEncoder().encodeToString(publicKey),
"message", Base64.getEncoder().encodeToString(message),
"signature", Base64.getEncoder().encodeToString(signature.getBytes())
);
return crypto.post("/sphincs/verify", body, new TypeToken<Map<String, Boolean>>() {})
.thenApply(result -> result.get("valid"));
}
}
public static class KdfClient {
private final SynorCrypto crypto;
KdfClient(SynorCrypto crypto) { this.crypto = crypto; }
public CompletableFuture<byte[]> deriveKey(byte[] seed, DerivationConfig config) {
Map<String, Object> body = new HashMap<>();
body.put("seed", Base64.getEncoder().encodeToString(seed));
body.put("output_length", config.getOutputLength());
if (config.getSalt() != null) {
body.put("salt", Base64.getEncoder().encodeToString(config.getSalt()));
}
if (config.getInfo() != null) {
body.put("info", Base64.getEncoder().encodeToString(config.getInfo()));
}
return crypto.post("/kdf/hkdf", body, new TypeToken<Map<String, String>>() {})
.thenApply(result -> Base64.getDecoder().decode(result.get("key")));
}
public CompletableFuture<byte[]> deriveFromPassword(byte[] password, PasswordDerivationConfig config) {
Map<String, Object> body = Map.of(
"password", Base64.getEncoder().encodeToString(password),
"salt", Base64.getEncoder().encodeToString(config.getSalt()),
"iterations", config.getIterations(),
"output_length", config.getOutputLength()
);
return crypto.post("/kdf/pbkdf2", body, new TypeToken<Map<String, String>>() {})
.thenApply(result -> Base64.getDecoder().decode(result.get("key")));
}
}
public static class HashClient {
private final SynorCrypto crypto;
HashClient(SynorCrypto crypto) { this.crypto = crypto; }
public CompletableFuture<Hash256> sha3_256(byte[] data) {
Map<String, Object> body = Map.of("data", Base64.getEncoder().encodeToString(data));
return crypto.post("/hash/sha3-256", body, new TypeToken<Hash256>() {});
}
public CompletableFuture<Hash256> blake3(byte[] data) {
Map<String, Object> body = Map.of("data", Base64.getEncoder().encodeToString(data));
return crypto.post("/hash/blake3", body, new TypeToken<Hash256>() {});
}
public CompletableFuture<Hash256> keccak256(byte[] data) {
Map<String, Object> body = Map.of("data", Base64.getEncoder().encodeToString(data));
return crypto.post("/hash/keccak256", body, new TypeToken<Hash256>() {});
}
}
}

View file

@ -0,0 +1,404 @@
package io.synor.crypto;
import java.util.*;
/**
* Synor Crypto SDK Types for Java
*/
// ============================================================================
// Enumerations
// ============================================================================
enum Network {
MAINNET("mainnet"),
TESTNET("testnet"),
DEVNET("devnet");
private final String value;
Network(String value) { this.value = value; }
public String getValue() { return value; }
public static Network fromValue(String value) {
for (Network n : values()) if (n.value.equals(value)) return n;
return MAINNET;
}
}
enum FalconVariant {
FALCON512("falcon512", 690, 897, 128),
FALCON1024("falcon1024", 1330, 1793, 256);
private final String value;
private final int signatureSize;
private final int publicKeySize;
private final int securityLevel;
FalconVariant(String value, int sigSize, int pkSize, int secLevel) {
this.value = value;
this.signatureSize = sigSize;
this.publicKeySize = pkSize;
this.securityLevel = secLevel;
}
public String getValue() { return value; }
public int getSignatureSize() { return signatureSize; }
public int getPublicKeySize() { return publicKeySize; }
public int getSecurityLevel() { return securityLevel; }
}
enum SphincsVariant {
SHAKE128S("shake128s", 7856, 128),
SHAKE192S("shake192s", 16224, 192),
SHAKE256S("shake256s", 29792, 256);
private final String value;
private final int signatureSize;
private final int securityLevel;
SphincsVariant(String value, int sigSize, int secLevel) {
this.value = value;
this.signatureSize = sigSize;
this.securityLevel = secLevel;
}
public String getValue() { return value; }
public int getSignatureSize() { return signatureSize; }
public int getSecurityLevel() { return securityLevel; }
}
enum PqAlgorithm {
DILITHIUM3("dilithium3"),
FALCON512("falcon512"),
FALCON1024("falcon1024"),
SPHINCS128S("sphincs128s"),
SPHINCS192S("sphincs192s"),
SPHINCS256S("sphincs256s");
private final String value;
PqAlgorithm(String value) { this.value = value; }
public String getValue() { return value; }
}
enum AlgorithmFamily {
CLASSICAL("classical"),
LATTICE("lattice"),
HASH_BASED("hash_based"),
HYBRID("hybrid");
private final String value;
AlgorithmFamily(String value) { this.value = value; }
public String getValue() { return value; }
}
// ============================================================================
// Configuration Types
// ============================================================================
class CryptoConfig {
private final String apiKey;
private String endpoint = "https://crypto.synor.io/v1";
private int timeout = 30000;
private int retries = 3;
private boolean debug = false;
private Network defaultNetwork = Network.MAINNET;
public CryptoConfig(String apiKey) { this.apiKey = apiKey; }
public String getApiKey() { return apiKey; }
public String getEndpoint() { return endpoint; }
public int getTimeout() { return timeout; }
public int getRetries() { return retries; }
public boolean isDebug() { return debug; }
public Network getDefaultNetwork() { return defaultNetwork; }
public CryptoConfig setEndpoint(String endpoint) { this.endpoint = endpoint; return this; }
public CryptoConfig setTimeout(int timeout) { this.timeout = timeout; return this; }
public CryptoConfig setRetries(int retries) { this.retries = retries; return this; }
public CryptoConfig setDebug(boolean debug) { this.debug = debug; return this; }
public CryptoConfig setDefaultNetwork(Network network) { this.defaultNetwork = network; return this; }
}
class DerivationConfig {
private byte[] salt;
private byte[] info;
private int outputLength = 32;
public byte[] getSalt() { return salt; }
public byte[] getInfo() { return info; }
public int getOutputLength() { return outputLength; }
public DerivationConfig setSalt(byte[] salt) { this.salt = salt; return this; }
public DerivationConfig setInfo(byte[] info) { this.info = info; return this; }
public DerivationConfig setOutputLength(int len) { this.outputLength = len; return this; }
}
class PasswordDerivationConfig {
private final byte[] salt;
private int iterations = 100000;
private int outputLength = 32;
public PasswordDerivationConfig(byte[] salt) { this.salt = salt; }
public byte[] getSalt() { return salt; }
public int getIterations() { return iterations; }
public int getOutputLength() { return outputLength; }
public PasswordDerivationConfig setIterations(int iterations) { this.iterations = iterations; return this; }
public PasswordDerivationConfig setOutputLength(int len) { this.outputLength = len; return this; }
}
class DerivationPath {
public static final int COIN_TYPE = 0x5359;
private final int account;
private final int change;
private final int index;
public DerivationPath(int account, int change, int index) {
this.account = account;
this.change = change;
this.index = index;
}
public static DerivationPath external(int account, int index) { return new DerivationPath(account, 0, index); }
public static DerivationPath internal(int account, int index) { return new DerivationPath(account, 1, index); }
public int getAccount() { return account; }
public int getChange() { return change; }
public int getIndex() { return index; }
@Override
public String toString() { return String.format("m/44'/%d'/%d'/%d/%d", COIN_TYPE, account, change, index); }
public Map<String, Integer> toMap() { return Map.of("account", account, "change", change, "index", index); }
}
// ============================================================================
// Key Types
// ============================================================================
class HybridPublicKey {
private String ed25519;
private String dilithium;
public byte[] getEd25519() { return Base64.getDecoder().decode(ed25519); }
public byte[] getDilithium() { return Base64.getDecoder().decode(dilithium); }
public int size() { return getEd25519().length + getDilithium().length; }
public Map<String, String> toMap() {
return Map.of("ed25519", ed25519, "dilithium", dilithium);
}
}
class SecretKey {
private String ed25519Seed;
private String masterSeed;
public byte[] getEd25519Seed() { return Base64.getDecoder().decode(ed25519Seed); }
public byte[] getMasterSeed() { return Base64.getDecoder().decode(masterSeed); }
public Map<String, String> toMap() {
return Map.of("ed25519_seed", ed25519Seed, "master_seed", masterSeed);
}
}
class FalconPublicKey {
private String variant;
private String bytes;
public FalconVariant getVariant() { return FalconVariant.valueOf(variant.toUpperCase()); }
public byte[] getBytes() { return Base64.getDecoder().decode(bytes); }
}
class FalconSecretKey {
private String variant;
private String bytes;
public FalconVariant getVariant() { return FalconVariant.valueOf(variant.toUpperCase()); }
public byte[] getBytes() { return Base64.getDecoder().decode(bytes); }
}
class SphincsPublicKey {
private String variant;
private String bytes;
public SphincsVariant getVariant() { return SphincsVariant.valueOf(variant.toUpperCase()); }
public byte[] getBytes() { return Base64.getDecoder().decode(bytes); }
}
class SphincsSecretKey {
private String variant;
private String bytes;
public SphincsVariant getVariant() { return SphincsVariant.valueOf(variant.toUpperCase()); }
public byte[] getBytes() { return Base64.getDecoder().decode(bytes); }
}
// ============================================================================
// Signature Types
// ============================================================================
class HybridSignature {
private String ed25519;
private String dilithium;
public byte[] getEd25519() { return Base64.getDecoder().decode(ed25519); }
public byte[] getDilithium() { return Base64.getDecoder().decode(dilithium); }
public int size() { return getEd25519().length + getDilithium().length; }
public byte[] toBytes() {
byte[] e = getEd25519();
byte[] d = getDilithium();
byte[] result = new byte[e.length + d.length];
System.arraycopy(e, 0, result, 0, e.length);
System.arraycopy(d, 0, result, e.length, d.length);
return result;
}
public Map<String, String> toMap() {
return Map.of("ed25519", ed25519, "dilithium", dilithium);
}
}
class FalconSignature {
private String variant;
private String signature;
public FalconVariant getVariant() { return FalconVariant.valueOf(variant.toUpperCase()); }
public byte[] getBytes() { return Base64.getDecoder().decode(signature); }
public int size() { return getBytes().length; }
}
class SphincsSignature {
private String variant;
private String signature;
public SphincsVariant getVariant() { return SphincsVariant.valueOf(variant.toUpperCase()); }
public byte[] getBytes() { return Base64.getDecoder().decode(signature); }
public int size() { return getBytes().length; }
}
// ============================================================================
// Keypair Types
// ============================================================================
class HybridKeypair {
private HybridPublicKey publicKey;
private SecretKey secretKey;
private Map<String, String> addresses = new HashMap<>();
public HybridPublicKey getPublicKey() { return publicKey; }
public SecretKey getSecretKey() { return secretKey; }
public String getAddress(Network network) {
return addresses.getOrDefault(network.getValue(), "");
}
}
class FalconKeypair {
private String variant;
private FalconPublicKey publicKey;
private FalconSecretKey secretKey;
public FalconVariant getVariant() { return FalconVariant.valueOf(variant.toUpperCase()); }
public FalconPublicKey getPublicKey() { return publicKey; }
public FalconSecretKey getSecretKey() { return secretKey; }
}
class SphincsKeypair {
private String variant;
private SphincsPublicKey publicKey;
private SphincsSecretKey secretKey;
public SphincsVariant getVariant() { return SphincsVariant.valueOf(variant.toUpperCase()); }
public SphincsPublicKey getPublicKey() { return publicKey; }
public SphincsSecretKey getSecretKey() { return secretKey; }
}
// ============================================================================
// Mnemonic Types
// ============================================================================
class Mnemonic {
private String phrase;
private List<String> words;
private int wordCount;
private String entropy;
public String getPhrase() { return phrase; }
public List<String> getWords() { return words != null ? words : Arrays.asList(phrase.split(" ")); }
public int getWordCount() { return wordCount > 0 ? wordCount : getWords().size(); }
public byte[] getEntropy() { return entropy != null ? Base64.getDecoder().decode(entropy) : new byte[0]; }
}
class MnemonicValidation {
private boolean valid;
private String error;
public boolean isValid() { return valid; }
public String getError() { return error; }
}
// ============================================================================
// Address Types
// ============================================================================
class Address {
private String address;
private String network;
private String pubkeyHash;
public String getAddress() { return address; }
public Network getNetwork() { return Network.fromValue(network); }
public byte[] getPubkeyHash() { return pubkeyHash != null ? Base64.getDecoder().decode(pubkeyHash) : new byte[0]; }
}
// ============================================================================
// Hash Types
// ============================================================================
class Hash256 {
private String hash;
public String getHex() { return hash; }
public byte[] getBytes() {
byte[] result = new byte[hash.length() / 2];
for (int i = 0; i < result.length; i++) {
result[i] = (byte) Integer.parseInt(hash.substring(i * 2, i * 2 + 2), 16);
}
return result;
}
}
// ============================================================================
// Error Types
// ============================================================================
class CryptoException extends RuntimeException {
private final String code;
public CryptoException(String message, String code) {
super(message);
this.code = code;
}
public String getCode() { return code; }
}
// ============================================================================
// Constants
// ============================================================================
final class CryptoConstants {
public static final int ED25519_PUBLIC_KEY_SIZE = 32;
public static final int ED25519_SECRET_KEY_SIZE = 32;
public static final int ED25519_SIGNATURE_SIZE = 64;
public static final int DILITHIUM3_PUBLIC_KEY_SIZE = 1952;
public static final int DILITHIUM3_SIGNATURE_SIZE = 3293;
public static final int HYBRID_SIGNATURE_SIZE = 64 + 3293;
public static final int COIN_TYPE = 0x5359;
public static final int MIN_PBKDF2_ITERATIONS = 10000;
public static final int MIN_SALT_LENGTH = 8;
public static final String DEFAULT_ENDPOINT = "https://crypto.synor.io/v1";
private CryptoConstants() {}
}

767
sdk/js/src/crypto/index.ts Normal file
View file

@ -0,0 +1,767 @@
/**
* Synor Crypto SDK for JavaScript/TypeScript
*
* Quantum-resistant cryptographic primitives for the Synor blockchain.
*
* Features:
* - Hybrid Ed25519 + Dilithium3 signatures (quantum-resistant)
* - BIP-39 mnemonic support (12-24 words)
* - BIP-44 hierarchical key derivation
* - Post-quantum algorithms: Falcon, SPHINCS+
* - Secure key derivation (HKDF, PBKDF2)
*
* @example
* ```typescript
* import { SynorCrypto } from '@synor/crypto';
*
* const crypto = new SynorCrypto({ apiKey: 'your-api-key' });
*
* // Generate a mnemonic
* const mnemonic = await crypto.mnemonic.generate(24);
* console.log('Backup words:', mnemonic.phrase);
*
* // Create keypair from mnemonic
* const keypair = await crypto.keypairs.fromMnemonic(mnemonic);
* const address = keypair.address('mainnet');
*
* // Sign a message
* const signature = await crypto.signing.sign(keypair, Buffer.from('Hello!'));
* ```
*/
import type {
CryptoConfig,
Network,
MnemonicWordCount,
Mnemonic,
MnemonicValidation,
HybridKeypair,
HybridPublicKey,
HybridSignature,
FalconVariant,
FalconKeypair,
FalconSignature,
SphincsVariant,
SphincsKeypair,
SphincsSignature,
DerivationPath,
DerivationConfig,
PasswordDerivationConfig,
AlgorithmCapabilities,
NegotiationPolicy,
NegotiationResult,
SessionParams,
Hash256,
Address,
} from './types';
export * from './types';
// ============================================================================
// Mnemonic Client
// ============================================================================
/** Mnemonic operations */
export class MnemonicClient {
constructor(private crypto: SynorCrypto) {}
/**
* Generates a new random mnemonic.
* @param wordCount Number of words (12, 15, 18, 21, or 24)
*/
async generate(wordCount: MnemonicWordCount = 24): Promise<Mnemonic> {
const body = { word_count: wordCount };
return this.crypto.post<Mnemonic>('/mnemonic/generate', body);
}
/**
* Creates a mnemonic from a phrase string.
*/
async fromPhrase(phrase: string): Promise<Mnemonic> {
return this.crypto.post<Mnemonic>('/mnemonic/from-phrase', { phrase });
}
/**
* Creates a mnemonic from entropy bytes.
*/
async fromEntropy(entropy: Uint8Array): Promise<Mnemonic> {
const entropyBase64 = Buffer.from(entropy).toString('base64');
return this.crypto.post<Mnemonic>('/mnemonic/from-entropy', { entropy: entropyBase64 });
}
/**
* Validates a mnemonic phrase.
*/
async validate(phrase: string): Promise<MnemonicValidation> {
return this.crypto.post<MnemonicValidation>('/mnemonic/validate', { phrase });
}
/**
* Derives a 64-byte seed from a mnemonic.
* @param mnemonic The mnemonic phrase or object
* @param passphrase Optional BIP-39 passphrase
*/
async toSeed(mnemonic: Mnemonic | string, passphrase: string = ''): Promise<Uint8Array> {
const phrase = typeof mnemonic === 'string' ? mnemonic : mnemonic.phrase;
const result = await this.crypto.post<{ seed: string }>('/mnemonic/to-seed', {
phrase,
passphrase,
});
return Buffer.from(result.seed, 'base64');
}
/**
* Suggests word completions from the BIP-39 wordlist.
*/
async suggestWords(partial: string, limit: number = 10): Promise<string[]> {
const result = await this.crypto.post<{ suggestions: string[] }>('/mnemonic/suggest', {
partial,
limit,
});
return result.suggestions;
}
}
// ============================================================================
// Keypair Client
// ============================================================================
/** Keypair operations */
export class KeypairClient {
constructor(private crypto: SynorCrypto) {}
/**
* Generates a new random hybrid keypair.
*/
async generate(): Promise<HybridKeypair> {
const result = await this.crypto.post<HybridKeypairResponse>('/keypair/generate');
return this.wrapKeypair(result);
}
/**
* Creates a keypair from a mnemonic.
* @param mnemonic The mnemonic phrase or object
* @param passphrase Optional BIP-39 passphrase
*/
async fromMnemonic(mnemonic: Mnemonic | string, passphrase: string = ''): Promise<HybridKeypair> {
const phrase = typeof mnemonic === 'string' ? mnemonic : mnemonic.phrase;
const result = await this.crypto.post<HybridKeypairResponse>('/keypair/from-mnemonic', {
phrase,
passphrase,
});
return this.wrapKeypair(result);
}
/**
* Creates a keypair from a 64-byte seed.
*/
async fromSeed(seed: Uint8Array): Promise<HybridKeypair> {
const seedBase64 = Buffer.from(seed).toString('base64');
const result = await this.crypto.post<HybridKeypairResponse>('/keypair/from-seed', {
seed: seedBase64,
});
return this.wrapKeypair(result);
}
/**
* Derives a child keypair using BIP-44 path.
*/
async derive(
parentKeypair: HybridKeypair,
path: DerivationPath
): Promise<HybridKeypair> {
const result = await this.crypto.post<HybridKeypairResponse>('/keypair/derive', {
public_key: this.encodePublicKey(parentKeypair.publicKey),
path,
});
return this.wrapKeypair(result);
}
/**
* Gets the address for a public key.
*/
async getAddress(publicKey: HybridPublicKey, network: Network): Promise<Address> {
return this.crypto.post<Address>('/keypair/address', {
public_key: this.encodePublicKey(publicKey),
network,
});
}
private wrapKeypair(response: HybridKeypairResponse): HybridKeypair {
const publicKey: HybridPublicKey = {
ed25519: Buffer.from(response.public_key.ed25519, 'base64'),
dilithium: Buffer.from(response.public_key.dilithium, 'base64'),
};
return {
publicKey,
secretKey: {
ed25519Seed: Buffer.from(response.secret_key.ed25519_seed, 'base64'),
masterSeed: Buffer.from(response.secret_key.master_seed, 'base64'),
},
address: (network: Network) => response.addresses[network] || '',
};
}
private encodePublicKey(pk: HybridPublicKey): object {
return {
ed25519: Buffer.from(pk.ed25519).toString('base64'),
dilithium: Buffer.from(pk.dilithium).toString('base64'),
};
}
}
interface HybridKeypairResponse {
public_key: {
ed25519: string;
dilithium: string;
};
secret_key: {
ed25519_seed: string;
master_seed: string;
};
addresses: Record<Network, string>;
}
// ============================================================================
// Signing Client
// ============================================================================
/** Signing and verification operations */
export class SigningClient {
constructor(private crypto: SynorCrypto) {}
/**
* Signs a message with a hybrid keypair.
*/
async sign(keypair: HybridKeypair, message: Uint8Array): Promise<HybridSignature> {
const result = await this.crypto.post<{ ed25519: string; dilithium: string }>(
'/sign/hybrid',
{
secret_key: {
ed25519_seed: Buffer.from(keypair.secretKey.ed25519Seed).toString('base64'),
master_seed: Buffer.from(keypair.secretKey.masterSeed).toString('base64'),
},
message: Buffer.from(message).toString('base64'),
}
);
return {
ed25519: Buffer.from(result.ed25519, 'base64'),
dilithium: Buffer.from(result.dilithium, 'base64'),
};
}
/**
* Verifies a hybrid signature.
*/
async verify(
publicKey: HybridPublicKey,
message: Uint8Array,
signature: HybridSignature
): Promise<boolean> {
const result = await this.crypto.post<{ valid: boolean }>('/sign/verify', {
public_key: {
ed25519: Buffer.from(publicKey.ed25519).toString('base64'),
dilithium: Buffer.from(publicKey.dilithium).toString('base64'),
},
message: Buffer.from(message).toString('base64'),
signature: {
ed25519: Buffer.from(signature.ed25519).toString('base64'),
dilithium: Buffer.from(signature.dilithium).toString('base64'),
},
});
return result.valid;
}
/**
* Signs a message using Ed25519 only (faster but not quantum-resistant).
*/
async signEd25519(secretKey: Uint8Array, message: Uint8Array): Promise<Uint8Array> {
const result = await this.crypto.post<{ signature: string }>('/sign/ed25519', {
secret_key: Buffer.from(secretKey).toString('base64'),
message: Buffer.from(message).toString('base64'),
});
return Buffer.from(result.signature, 'base64');
}
/**
* Verifies an Ed25519 signature.
*/
async verifyEd25519(
publicKey: Uint8Array,
message: Uint8Array,
signature: Uint8Array
): Promise<boolean> {
const result = await this.crypto.post<{ valid: boolean }>('/sign/verify-ed25519', {
public_key: Buffer.from(publicKey).toString('base64'),
message: Buffer.from(message).toString('base64'),
signature: Buffer.from(signature).toString('base64'),
});
return result.valid;
}
}
// ============================================================================
// Falcon Client
// ============================================================================
/** Falcon (FIPS 206) compact signature operations */
export class FalconClient {
constructor(private crypto: SynorCrypto) {}
/**
* Generates a Falcon keypair.
* @param variant Falcon-512 (128-bit) or Falcon-1024 (256-bit)
*/
async generate(variant: FalconVariant = 'falcon512'): Promise<FalconKeypair> {
return this.crypto.post<FalconKeypair>('/falcon/generate', { variant });
}
/**
* Signs a message with Falcon.
*/
async sign(keypair: FalconKeypair, message: Uint8Array): Promise<FalconSignature> {
const result = await this.crypto.post<{ signature: string; variant: FalconVariant }>(
'/falcon/sign',
{
variant: keypair.variant,
secret_key: Buffer.from(keypair.secretKey.bytes).toString('base64'),
message: Buffer.from(message).toString('base64'),
}
);
return {
variant: result.variant,
bytes: Buffer.from(result.signature, 'base64'),
};
}
/**
* Verifies a Falcon signature.
*/
async verify(
publicKey: Uint8Array,
message: Uint8Array,
signature: FalconSignature
): Promise<boolean> {
const result = await this.crypto.post<{ valid: boolean }>('/falcon/verify', {
variant: signature.variant,
public_key: Buffer.from(publicKey).toString('base64'),
message: Buffer.from(message).toString('base64'),
signature: Buffer.from(signature.bytes).toString('base64'),
});
return result.valid;
}
/**
* Returns the signature size for a variant.
*/
signatureSize(variant: FalconVariant): number {
return variant === 'falcon512' ? 690 : 1330;
}
/**
* Returns the public key size for a variant.
*/
publicKeySize(variant: FalconVariant): number {
return variant === 'falcon512' ? 897 : 1793;
}
/**
* Returns the security level in bits.
*/
securityLevel(variant: FalconVariant): number {
return variant === 'falcon512' ? 128 : 256;
}
}
// ============================================================================
// SPHINCS+ Client
// ============================================================================
/** SPHINCS+ (FIPS 205) hash-based signature operations */
export class SphincsClient {
constructor(private crypto: SynorCrypto) {}
/**
* Generates a SPHINCS+ keypair.
*/
async generate(variant: SphincsVariant = 'shake128s'): Promise<SphincsKeypair> {
return this.crypto.post<SphincsKeypair>('/sphincs/generate', { variant });
}
/**
* Signs a message with SPHINCS+.
*/
async sign(keypair: SphincsKeypair, message: Uint8Array): Promise<SphincsSignature> {
const result = await this.crypto.post<{ signature: string; variant: SphincsVariant }>(
'/sphincs/sign',
{
variant: keypair.variant,
secret_key: Buffer.from(keypair.secretKey.bytes).toString('base64'),
message: Buffer.from(message).toString('base64'),
}
);
return {
variant: result.variant,
bytes: Buffer.from(result.signature, 'base64'),
};
}
/**
* Verifies a SPHINCS+ signature.
*/
async verify(
publicKey: Uint8Array,
message: Uint8Array,
signature: SphincsSignature
): Promise<boolean> {
const result = await this.crypto.post<{ valid: boolean }>('/sphincs/verify', {
variant: signature.variant,
public_key: Buffer.from(publicKey).toString('base64'),
message: Buffer.from(message).toString('base64'),
signature: Buffer.from(signature.bytes).toString('base64'),
});
return result.valid;
}
/**
* Returns the signature size for a variant.
*/
signatureSize(variant: SphincsVariant): number {
const sizes: Record<SphincsVariant, number> = {
shake128s: 7856,
shake192s: 16224,
shake256s: 29792,
};
return sizes[variant];
}
/**
* Returns the security level in bits.
*/
securityLevel(variant: SphincsVariant): number {
const levels: Record<SphincsVariant, number> = {
shake128s: 128,
shake192s: 192,
shake256s: 256,
};
return levels[variant];
}
}
// ============================================================================
// Key Derivation Client
// ============================================================================
/** Key derivation operations */
export class KdfClient {
constructor(private crypto: SynorCrypto) {}
/**
* Derives a key using HKDF-SHA3-256.
*/
async deriveKey(
seed: Uint8Array,
config: DerivationConfig = {}
): Promise<Uint8Array> {
const result = await this.crypto.post<{ key: string }>('/kdf/hkdf', {
seed: Buffer.from(seed).toString('base64'),
salt: config.salt ? Buffer.from(config.salt).toString('base64') : undefined,
info: config.info ? Buffer.from(config.info).toString('base64') : undefined,
output_length: config.outputLength ?? 32,
});
return Buffer.from(result.key, 'base64');
}
/**
* Derives a key from a password using PBKDF2.
*/
async deriveFromPassword(
password: string | Uint8Array,
config: PasswordDerivationConfig
): Promise<Uint8Array> {
const passwordBytes = typeof password === 'string'
? Buffer.from(password, 'utf-8')
: password;
const result = await this.crypto.post<{ key: string }>('/kdf/pbkdf2', {
password: Buffer.from(passwordBytes).toString('base64'),
salt: Buffer.from(config.salt).toString('base64'),
iterations: config.iterations,
output_length: config.outputLength ?? 32,
});
return Buffer.from(result.key, 'base64');
}
/**
* Derives an Ed25519 key from a master seed.
*/
async deriveEd25519Key(masterSeed: Uint8Array, account: number): Promise<Uint8Array> {
const result = await this.crypto.post<{ key: string }>('/kdf/ed25519', {
master_seed: Buffer.from(masterSeed).toString('base64'),
account,
});
return Buffer.from(result.key, 'base64');
}
/**
* Derives a child key using BIP-32 style derivation.
*/
async deriveChildKey(
parentKey: Uint8Array,
chainCode: Uint8Array,
index: number
): Promise<{ key: Uint8Array; chainCode: Uint8Array }> {
const result = await this.crypto.post<{ key: string; chain_code: string }>('/kdf/child', {
parent_key: Buffer.from(parentKey).toString('base64'),
chain_code: Buffer.from(chainCode).toString('base64'),
index,
});
return {
key: Buffer.from(result.key, 'base64'),
chainCode: Buffer.from(result.chain_code, 'base64'),
};
}
/**
* Creates a BIP-44 derivation path.
*/
createPath(account: number, change: number = 0, index: number = 0): DerivationPath {
return { account, change, index };
}
/**
* Formats a derivation path as a string.
*/
formatPath(path: DerivationPath): string {
const coinType = 0x5359; // Synor coin type
return `m/44'/${coinType}'/${path.account}'/${path.change}/${path.index}`;
}
}
// ============================================================================
// Hashing Client
// ============================================================================
/** Hashing operations */
export class HashClient {
constructor(private crypto: SynorCrypto) {}
/**
* Computes SHA3-256 hash.
*/
async sha3_256(data: Uint8Array): Promise<Hash256> {
const result = await this.crypto.post<{ hash: string }>('/hash/sha3-256', {
data: Buffer.from(data).toString('base64'),
});
const bytes = Buffer.from(result.hash, 'hex');
return { bytes, hex: result.hash };
}
/**
* Computes BLAKE3 hash.
*/
async blake3(data: Uint8Array): Promise<Hash256> {
const result = await this.crypto.post<{ hash: string }>('/hash/blake3', {
data: Buffer.from(data).toString('base64'),
});
const bytes = Buffer.from(result.hash, 'hex');
return { bytes, hex: result.hash };
}
/**
* Computes Keccak-256 hash (Ethereum compatible).
*/
async keccak256(data: Uint8Array): Promise<Hash256> {
const result = await this.crypto.post<{ hash: string }>('/hash/keccak256', {
data: Buffer.from(data).toString('base64'),
});
const bytes = Buffer.from(result.hash, 'hex');
return { bytes, hex: result.hash };
}
/**
* Combines multiple hashes.
*/
async combine(hashes: Uint8Array[]): Promise<Hash256> {
const result = await this.crypto.post<{ hash: string }>('/hash/combine', {
hashes: hashes.map(h => Buffer.from(h).toString('base64')),
});
const bytes = Buffer.from(result.hash, 'hex');
return { bytes, hex: result.hash };
}
}
// ============================================================================
// Negotiation Client
// ============================================================================
/** Algorithm negotiation operations */
export class NegotiationClient {
constructor(private crypto: SynorCrypto) {}
/**
* Gets the local capabilities.
*/
async getCapabilities(): Promise<AlgorithmCapabilities> {
return this.crypto.get<AlgorithmCapabilities>('/negotiation/capabilities');
}
/**
* Negotiates algorithm selection with a peer.
*/
async negotiate(
peerCapabilities: AlgorithmCapabilities,
policy: NegotiationPolicy
): Promise<NegotiationResult> {
return this.crypto.post<NegotiationResult>('/negotiation/negotiate', {
peer_capabilities: peerCapabilities,
policy,
});
}
/**
* Establishes session parameters after negotiation.
*/
async establishSession(
result: NegotiationResult,
peerPublicKey: Uint8Array
): Promise<SessionParams> {
return this.crypto.post<SessionParams>('/negotiation/session', {
negotiation_result: result,
peer_public_key: Buffer.from(peerPublicKey).toString('base64'),
});
}
}
// ============================================================================
// Main Client
// ============================================================================
/**
* Synor Crypto SDK Client
*
* Provides quantum-resistant cryptographic operations for the Synor blockchain.
*/
export class SynorCrypto {
private config: Required<CryptoConfig>;
private closed = false;
/** Mnemonic operations */
readonly mnemonic: MnemonicClient;
/** Keypair operations */
readonly keypairs: KeypairClient;
/** Signing operations */
readonly signing: SigningClient;
/** Falcon (compact PQ) operations */
readonly falcon: FalconClient;
/** SPHINCS+ (hash-based) operations */
readonly sphincs: SphincsClient;
/** Key derivation operations */
readonly kdf: KdfClient;
/** Hashing operations */
readonly hash: HashClient;
/** Algorithm negotiation */
readonly negotiation: NegotiationClient;
constructor(config: CryptoConfig) {
this.config = {
apiKey: config.apiKey,
endpoint: config.endpoint ?? 'https://crypto.synor.io/v1',
timeout: config.timeout ?? 30000,
retries: config.retries ?? 3,
debug: config.debug ?? false,
defaultNetwork: config.defaultNetwork ?? 'mainnet',
};
this.mnemonic = new MnemonicClient(this);
this.keypairs = new KeypairClient(this);
this.signing = new SigningClient(this);
this.falcon = new FalconClient(this);
this.sphincs = new SphincsClient(this);
this.kdf = new KdfClient(this);
this.hash = new HashClient(this);
this.negotiation = new NegotiationClient(this);
}
/** Default network */
get defaultNetwork(): Network {
return this.config.defaultNetwork;
}
/** Health check */
async healthCheck(): Promise<boolean> {
try {
const result = await this.get<{ status: string }>('/health');
return result.status === 'healthy';
} catch {
return false;
}
}
/** Get service info */
async getInfo(): Promise<Record<string, unknown>> {
return this.get<Record<string, unknown>>('/info');
}
/** Close the client */
close(): void {
this.closed = true;
}
/** Check if client is closed */
get isClosed(): boolean {
return this.closed;
}
/** @internal */
async get<T>(path: string): Promise<T> {
this.checkClosed();
const response = await fetch(`${this.config.endpoint}${path}`, {
method: 'GET',
headers: this.headers(),
});
return this.handleResponse<T>(response);
}
/** @internal */
async post<T>(path: string, body?: unknown): Promise<T> {
this.checkClosed();
const response = await fetch(`${this.config.endpoint}${path}`, {
method: 'POST',
headers: this.headers(),
body: body ? JSON.stringify(body) : undefined,
});
return this.handleResponse<T>(response);
}
private headers(): Record<string, string> {
return {
'Authorization': `Bearer ${this.config.apiKey}`,
'Content-Type': 'application/json',
'X-SDK-Version': 'js/0.1.0',
};
}
private async handleResponse<T>(response: Response): Promise<T> {
const json = await response.json();
if (!response.ok) {
const { CryptoError } = await import('./types');
throw new CryptoError(
json.message ?? `HTTP ${response.status}`,
json.code
);
}
return json as T;
}
private checkClosed(): void {
if (this.closed) {
const { CryptoError } = require('./types');
throw new CryptoError('Client has been closed', 'NETWORK_ERROR');
}
}
}
export default SynorCrypto;

370
sdk/js/src/crypto/types.ts Normal file
View file

@ -0,0 +1,370 @@
/**
* Synor Crypto SDK Types
*
* Quantum-resistant cryptographic primitives for the Synor blockchain.
*/
// ============================================================================
// Enumerations
// ============================================================================
/** Network type for address generation */
export type Network = 'mainnet' | 'testnet' | 'devnet';
/** Supported mnemonic word counts */
export type MnemonicWordCount = 12 | 15 | 18 | 21 | 24;
/** Falcon variant selection */
export type FalconVariant = 'falcon512' | 'falcon1024';
/** SPHINCS+ variant selection */
export type SphincsVariant = 'shake128s' | 'shake192s' | 'shake256s';
/** Post-quantum algorithm family */
export type PqAlgorithm = 'dilithium3' | 'falcon512' | 'falcon1024' | 'sphincs128s' | 'sphincs192s' | 'sphincs256s';
/** Algorithm family */
export type AlgorithmFamily = 'classical' | 'lattice' | 'hash_based' | 'hybrid';
// ============================================================================
// Configuration Types
// ============================================================================
/** Crypto SDK configuration */
export interface CryptoConfig {
apiKey: string;
endpoint?: string;
timeout?: number;
retries?: number;
debug?: boolean;
defaultNetwork?: Network;
}
/** Key derivation configuration */
export interface DerivationConfig {
/** Salt for HKDF (optional) */
salt?: Uint8Array;
/** Info/context for domain separation */
info?: Uint8Array;
/** Output key length in bytes */
outputLength?: number;
}
/** Password derivation configuration */
export interface PasswordDerivationConfig {
/** Salt (minimum 8 bytes) */
salt: Uint8Array;
/** Number of PBKDF2 iterations (minimum 10,000) */
iterations: number;
/** Output key length in bytes (max 64) */
outputLength?: number;
}
/** BIP-44 derivation path */
export interface DerivationPath {
/** Account number (hardened) */
account: number;
/** Change: 0 = external, 1 = internal */
change: number;
/** Address index */
index: number;
}
// ============================================================================
// Key Types
// ============================================================================
/** Ed25519 public key (32 bytes) */
export interface Ed25519PublicKey {
bytes: Uint8Array;
}
/** Dilithium3 public key (~1952 bytes) */
export interface Dilithium3PublicKey {
bytes: Uint8Array;
}
/** Hybrid public key (Ed25519 + Dilithium3) */
export interface HybridPublicKey {
/** Ed25519 component (32 bytes) */
ed25519: Uint8Array;
/** Dilithium3 component (~1952 bytes) */
dilithium: Uint8Array;
}
/** Secret key (master seed) */
export interface SecretKey {
/** Ed25519 seed (32 bytes) */
ed25519Seed: Uint8Array;
/** Master seed for derivation (64 bytes) */
masterSeed: Uint8Array;
}
/** Falcon public key */
export interface FalconPublicKey {
variant: FalconVariant;
bytes: Uint8Array;
}
/** Falcon secret key */
export interface FalconSecretKey {
variant: FalconVariant;
bytes: Uint8Array;
}
/** SPHINCS+ public key */
export interface SphincsPublicKey {
variant: SphincsVariant;
bytes: Uint8Array;
}
/** SPHINCS+ secret key */
export interface SphincsSecretKey {
variant: SphincsVariant;
bytes: Uint8Array;
}
// ============================================================================
// Signature Types
// ============================================================================
/** Ed25519 signature (64 bytes) */
export interface Ed25519Signature {
bytes: Uint8Array;
}
/** Dilithium3 signature (~3293 bytes) */
export interface Dilithium3Signature {
bytes: Uint8Array;
}
/** Hybrid signature (Ed25519 + Dilithium3) */
export interface HybridSignature {
/** Ed25519 component (64 bytes) */
ed25519: Uint8Array;
/** Dilithium3 component (~3293 bytes) */
dilithium: Uint8Array;
}
/** Falcon signature */
export interface FalconSignature {
variant: FalconVariant;
bytes: Uint8Array;
}
/** SPHINCS+ signature */
export interface SphincsSignature {
variant: SphincsVariant;
bytes: Uint8Array;
}
// ============================================================================
// Keypair Types
// ============================================================================
/** Ed25519 keypair */
export interface Ed25519Keypair {
publicKey: Ed25519PublicKey;
secretKey: Uint8Array;
}
/** Hybrid keypair (Ed25519 + Dilithium3) */
export interface HybridKeypair {
publicKey: HybridPublicKey;
secretKey: SecretKey;
/** Get address for this keypair */
address(network: Network): string;
}
/** Falcon keypair */
export interface FalconKeypair {
variant: FalconVariant;
publicKey: FalconPublicKey;
secretKey: FalconSecretKey;
}
/** SPHINCS+ keypair */
export interface SphincsKeypair {
variant: SphincsVariant;
publicKey: SphincsPublicKey;
secretKey: SphincsSecretKey;
}
// ============================================================================
// Mnemonic Types
// ============================================================================
/** Mnemonic phrase representation */
export interface Mnemonic {
/** The mnemonic phrase */
phrase: string;
/** Individual words */
words: string[];
/** Word count */
wordCount: MnemonicWordCount;
/** Entropy bytes */
entropy: Uint8Array;
}
/** Mnemonic validation result */
export interface MnemonicValidation {
valid: boolean;
error?: string;
}
// ============================================================================
// Address Types
// ============================================================================
/** Blockchain address */
export interface Address {
/** Address string (bech32 encoded) */
address: string;
/** Network */
network: Network;
/** Public key hash */
pubkeyHash: Uint8Array;
}
// ============================================================================
// Hash Types
// ============================================================================
/** 256-bit hash */
export interface Hash256 {
bytes: Uint8Array;
hex: string;
}
// ============================================================================
// Algorithm Negotiation Types
// ============================================================================
/** Algorithm capabilities */
export interface AlgorithmCapabilities {
/** Supported post-quantum algorithms */
pqAlgorithms: PqAlgorithm[];
/** Classical algorithm support */
classical: boolean;
/** Hybrid mode support */
hybrid: boolean;
/** Preferred algorithm */
preferred?: PqAlgorithm;
}
/** Negotiation policy */
export interface NegotiationPolicy {
/** Required minimum security level (bits) */
minSecurityLevel: number;
/** Prefer smaller signatures */
preferCompact: boolean;
/** Allow classical-only fallback */
allowClassical: boolean;
/** Required algorithm families */
requiredFamilies: AlgorithmFamily[];
}
/** Negotiation result */
export interface NegotiationResult {
/** Selected algorithm */
algorithm: PqAlgorithm;
/** Security level in bits */
securityLevel: number;
/** Algorithm family */
family: AlgorithmFamily;
/** Is hybrid mode */
hybrid: boolean;
}
/** Session parameters after negotiation */
export interface SessionParams {
/** Negotiated algorithm */
algorithm: PqAlgorithm;
/** Session key (if established) */
sessionKey?: Uint8Array;
/** Expiry timestamp */
expiresAt?: number;
}
// ============================================================================
// Error Types
// ============================================================================
/** Crypto error codes */
export type CryptoErrorCode =
| 'INVALID_MNEMONIC'
| 'INVALID_WORD_COUNT'
| 'INVALID_SEED'
| 'INVALID_KEY'
| 'INVALID_SIGNATURE'
| 'VERIFICATION_FAILED'
| 'DERIVATION_FAILED'
| 'ALGORITHM_MISMATCH'
| 'NEGOTIATION_FAILED'
| 'NETWORK_ERROR'
| 'TIMEOUT';
/** Crypto exception */
export class CryptoError extends Error {
constructor(
message: string,
public readonly code?: CryptoErrorCode,
public readonly cause?: unknown
) {
super(message);
this.name = 'CryptoError';
}
}
// ============================================================================
// Constants
// ============================================================================
export const CryptoConstants = {
/** Ed25519 public key size in bytes */
ED25519_PUBLIC_KEY_SIZE: 32,
/** Ed25519 secret key size in bytes */
ED25519_SECRET_KEY_SIZE: 32,
/** Ed25519 signature size in bytes */
ED25519_SIGNATURE_SIZE: 64,
/** Dilithium3 public key size in bytes */
DILITHIUM3_PUBLIC_KEY_SIZE: 1952,
/** Dilithium3 signature size in bytes */
DILITHIUM3_SIGNATURE_SIZE: 3293,
/** Hybrid signature size (Ed25519 + Dilithium3) */
HYBRID_SIGNATURE_SIZE: 64 + 3293,
/** Falcon-512 signature size */
FALCON512_SIGNATURE_SIZE: 690,
/** Falcon-512 public key size */
FALCON512_PUBLIC_KEY_SIZE: 897,
/** Falcon-1024 signature size */
FALCON1024_SIGNATURE_SIZE: 1330,
/** Falcon-1024 public key size */
FALCON1024_PUBLIC_KEY_SIZE: 1793,
/** SPHINCS+-128s signature size */
SPHINCS128S_SIGNATURE_SIZE: 7856,
/** SPHINCS+-192s signature size */
SPHINCS192S_SIGNATURE_SIZE: 16224,
/** SPHINCS+-256s signature size */
SPHINCS256S_SIGNATURE_SIZE: 29792,
/** BIP-44 coin type for Synor */
COIN_TYPE: 0x5359,
/** Minimum PBKDF2 iterations */
MIN_PBKDF2_ITERATIONS: 10000,
/** Minimum salt length for password derivation */
MIN_SALT_LENGTH: 8,
/** Default API endpoint */
DEFAULT_ENDPOINT: 'https://crypto.synor.io/v1',
} as const;
/** Algorithm size comparison */
export const AlgorithmSizes = {
ed25519: { signature: 64, publicKey: 32 },
dilithium3: { signature: 3293, publicKey: 1952 },
hybrid: { signature: 3357, publicKey: 1984 },
falcon512: { signature: 690, publicKey: 897 },
falcon1024: { signature: 1330, publicKey: 1793 },
sphincs128s: { signature: 7856, publicKey: 32 },
sphincs192s: { signature: 16224, publicKey: 48 },
sphincs256s: { signature: 29792, publicKey: 64 },
} as const;

View file

@ -0,0 +1,290 @@
package io.synor.crypto
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.*
import java.util.Base64
import java.util.concurrent.atomic.AtomicBoolean
/**
* Synor Crypto SDK for Kotlin
*
* Quantum-resistant cryptographic primitives for the Synor blockchain.
*
* Example:
* ```kotlin
* val config = CryptoConfig("your-api-key")
* val crypto = SynorCrypto(config)
*
* // Generate a mnemonic
* val mnemonic = crypto.mnemonic().generate(24)
* println("Backup words: ${mnemonic.phrase}")
*
* // Create keypair from mnemonic
* val keypair = crypto.keypairs().fromMnemonic(mnemonic.phrase, "")
* val address = keypair.getAddress(Network.MAINNET)
*
* // Sign a message
* val signature = crypto.signing().sign(keypair, "Hello!".toByteArray())
* ```
*/
class SynorCrypto(private val config: CryptoConfig) {
private val httpClient: HttpClient
private val json = Json {
ignoreUnknownKeys = true
namingStrategy = JsonNamingStrategy.SnakeCase
}
private val closed = AtomicBoolean(false)
private val mnemonicClient: MnemonicClient
private val keypairClient: KeypairClient
private val signingClient: SigningClient
private val falconClient: FalconClient
private val sphincsClient: SphincsClient
private val kdfClient: KdfClient
private val hashClient: HashClient
init {
httpClient = HttpClient(CIO) {
install(ContentNegotiation) {
json(json)
}
install(HttpTimeout) {
requestTimeoutMillis = config.timeout
connectTimeoutMillis = config.timeout
}
defaultRequest {
header("Authorization", "Bearer ${config.apiKey}")
header("X-SDK-Version", "kotlin/0.1.0")
}
}
mnemonicClient = MnemonicClient(this)
keypairClient = KeypairClient(this)
signingClient = SigningClient(this)
falconClient = FalconClient(this)
sphincsClient = SphincsClient(this)
kdfClient = KdfClient(this)
hashClient = HashClient(this)
}
fun getDefaultNetwork(): Network = config.defaultNetwork
fun mnemonic(): MnemonicClient = mnemonicClient
fun keypairs(): KeypairClient = keypairClient
fun signing(): SigningClient = signingClient
fun falcon(): FalconClient = falconClient
fun sphincs(): SphincsClient = sphincsClient
fun kdf(): KdfClient = kdfClient
fun hash(): HashClient = hashClient
suspend fun healthCheck(): Boolean = try {
val result = get<Map<String, Any>>("/health")
result["status"] == "healthy"
} catch (e: Exception) {
false
}
suspend fun getInfo(): Map<String, Any> = get("/info")
fun close() {
closed.set(true)
httpClient.close()
}
fun isClosed(): Boolean = closed.get()
internal suspend inline fun <reified T> get(path: String): T {
checkClosed()
val response = httpClient.get("${config.endpoint}$path")
return handleResponse(response)
}
internal suspend inline fun <reified T> post(path: String, body: Any? = null): T {
checkClosed()
val response = httpClient.post("${config.endpoint}$path") {
contentType(ContentType.Application.Json)
setBody(body ?: emptyMap<String, Any>())
}
return handleResponse(response)
}
@PublishedApi
internal suspend inline fun <reified T> handleResponse(response: HttpResponse): T {
if (response.status.value >= 400) {
val errorBody = response.bodyAsText()
val error = try {
json.decodeFromString<Map<String, String>>(errorBody)
} catch (e: Exception) {
emptyMap()
}
throw CryptoException(
error["message"] ?: "HTTP ${response.status.value}",
error["code"]
)
}
return response.body()
}
private fun checkClosed() {
if (closed.get()) {
throw CryptoException("Client has been closed", "CLIENT_CLOSED")
}
}
// ========================================================================
// Sub-Clients
// ========================================================================
class MnemonicClient(private val crypto: SynorCrypto) {
suspend fun generate(wordCount: Int = 24): Mnemonic =
crypto.post("/mnemonic/generate", mapOf("word_count" to wordCount))
suspend fun fromPhrase(phrase: String): Mnemonic =
crypto.post("/mnemonic/from-phrase", mapOf("phrase" to phrase))
suspend fun validate(phrase: String): MnemonicValidation =
crypto.post("/mnemonic/validate", mapOf("phrase" to phrase))
suspend fun toSeed(phrase: String, passphrase: String = ""): ByteArray {
val result: Map<String, String> = crypto.post(
"/mnemonic/to-seed",
mapOf("phrase" to phrase, "passphrase" to passphrase)
)
return Base64.getDecoder().decode(result["seed"])
}
suspend fun suggestWords(partial: String, limit: Int = 5): List<String> {
val result: Map<String, List<String>> = crypto.post(
"/mnemonic/suggest",
mapOf("partial" to partial, "limit" to limit)
)
return result["suggestions"] ?: emptyList()
}
}
class KeypairClient(private val crypto: SynorCrypto) {
suspend fun generate(): HybridKeypair =
crypto.post("/keypair/generate")
suspend fun fromMnemonic(phrase: String, passphrase: String = ""): HybridKeypair =
crypto.post("/keypair/from-mnemonic", mapOf("phrase" to phrase, "passphrase" to passphrase))
suspend fun fromSeed(seed: ByteArray): HybridKeypair =
crypto.post("/keypair/from-seed", mapOf("seed" to Base64.getEncoder().encodeToString(seed)))
suspend fun getAddress(publicKey: HybridPublicKey, network: Network): Address =
crypto.post("/keypair/address", mapOf("public_key" to publicKey.toMap(), "network" to network.value))
}
class SigningClient(private val crypto: SynorCrypto) {
suspend fun sign(keypair: HybridKeypair, message: ByteArray): HybridSignature =
crypto.post("/sign/hybrid", mapOf(
"secret_key" to keypair.secretKey.toMap(),
"message" to Base64.getEncoder().encodeToString(message)
))
suspend fun verify(publicKey: HybridPublicKey, message: ByteArray, signature: HybridSignature): Boolean {
val result: Map<String, Boolean> = crypto.post("/sign/verify", mapOf(
"public_key" to publicKey.toMap(),
"message" to Base64.getEncoder().encodeToString(message),
"signature" to signature.toMap()
))
return result["valid"] ?: false
}
suspend fun signEd25519(secretKey: ByteArray, message: ByteArray): ByteArray {
val result: Map<String, String> = crypto.post("/sign/ed25519", mapOf(
"secret_key" to Base64.getEncoder().encodeToString(secretKey),
"message" to Base64.getEncoder().encodeToString(message)
))
return Base64.getDecoder().decode(result["signature"])
}
}
class FalconClient(private val crypto: SynorCrypto) {
suspend fun generate(variant: FalconVariant = FalconVariant.FALCON512): FalconKeypair =
crypto.post("/falcon/generate", mapOf("variant" to variant.value))
suspend fun sign(keypair: FalconKeypair, message: ByteArray): FalconSignature =
crypto.post("/falcon/sign", mapOf(
"variant" to keypair.getVariantEnum().value,
"secret_key" to Base64.getEncoder().encodeToString(keypair.secretKey.getKeyBytes()),
"message" to Base64.getEncoder().encodeToString(message)
))
suspend fun verify(publicKey: ByteArray, message: ByteArray, signature: FalconSignature): Boolean {
val result: Map<String, Boolean> = crypto.post("/falcon/verify", mapOf(
"variant" to signature.getVariantEnum().value,
"public_key" to Base64.getEncoder().encodeToString(publicKey),
"message" to Base64.getEncoder().encodeToString(message),
"signature" to Base64.getEncoder().encodeToString(signature.getBytes())
))
return result["valid"] ?: false
}
}
class SphincsClient(private val crypto: SynorCrypto) {
suspend fun generate(variant: SphincsVariant = SphincsVariant.SHAKE128S): SphincsKeypair =
crypto.post("/sphincs/generate", mapOf("variant" to variant.value))
suspend fun sign(keypair: SphincsKeypair, message: ByteArray): SphincsSignature =
crypto.post("/sphincs/sign", mapOf(
"variant" to keypair.getVariantEnum().value,
"secret_key" to Base64.getEncoder().encodeToString(keypair.secretKey.getKeyBytes()),
"message" to Base64.getEncoder().encodeToString(message)
))
suspend fun verify(publicKey: ByteArray, message: ByteArray, signature: SphincsSignature): Boolean {
val result: Map<String, Boolean> = crypto.post("/sphincs/verify", mapOf(
"variant" to signature.getVariantEnum().value,
"public_key" to Base64.getEncoder().encodeToString(publicKey),
"message" to Base64.getEncoder().encodeToString(message),
"signature" to Base64.getEncoder().encodeToString(signature.getBytes())
))
return result["valid"] ?: false
}
}
class KdfClient(private val crypto: SynorCrypto) {
suspend fun deriveKey(seed: ByteArray, config: DerivationConfig = DerivationConfig()): ByteArray {
val body = mutableMapOf<String, Any>(
"seed" to Base64.getEncoder().encodeToString(seed),
"output_length" to config.outputLength
)
config.salt?.let { body["salt"] = Base64.getEncoder().encodeToString(it) }
config.info?.let { body["info"] = Base64.getEncoder().encodeToString(it) }
val result: Map<String, String> = crypto.post("/kdf/hkdf", body)
return Base64.getDecoder().decode(result["key"])
}
suspend fun deriveFromPassword(password: ByteArray, config: PasswordDerivationConfig): ByteArray {
val result: Map<String, String> = crypto.post("/kdf/pbkdf2", mapOf(
"password" to Base64.getEncoder().encodeToString(password),
"salt" to Base64.getEncoder().encodeToString(config.salt),
"iterations" to config.iterations,
"output_length" to config.outputLength
))
return Base64.getDecoder().decode(result["key"])
}
}
class HashClient(private val crypto: SynorCrypto) {
suspend fun sha3_256(data: ByteArray): Hash256 =
crypto.post("/hash/sha3-256", mapOf("data" to Base64.getEncoder().encodeToString(data)))
suspend fun blake3(data: ByteArray): Hash256 =
crypto.post("/hash/blake3", mapOf("data" to Base64.getEncoder().encodeToString(data)))
suspend fun keccak256(data: ByteArray): Hash256 =
crypto.post("/hash/keccak256", mapOf("data" to Base64.getEncoder().encodeToString(data)))
}
}

View file

@ -0,0 +1,353 @@
package io.synor.crypto
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import java.util.Base64
// ============================================================================
// Enumerations
// ============================================================================
@Serializable
enum class Network(val value: String) {
@SerialName("mainnet") MAINNET("mainnet"),
@SerialName("testnet") TESTNET("testnet"),
@SerialName("devnet") DEVNET("devnet");
companion object {
fun fromValue(value: String): Network =
entries.find { it.value == value } ?: MAINNET
}
}
@Serializable
enum class FalconVariant(
val value: String,
val signatureSize: Int,
val publicKeySize: Int,
val securityLevel: Int
) {
@SerialName("falcon512") FALCON512("falcon512", 690, 897, 128),
@SerialName("falcon1024") FALCON1024("falcon1024", 1330, 1793, 256);
companion object {
fun fromValue(value: String): FalconVariant =
entries.find { it.value == value } ?: FALCON512
}
}
@Serializable
enum class SphincsVariant(
val value: String,
val signatureSize: Int,
val securityLevel: Int
) {
@SerialName("shake128s") SHAKE128S("shake128s", 7856, 128),
@SerialName("shake192s") SHAKE192S("shake192s", 16224, 192),
@SerialName("shake256s") SHAKE256S("shake256s", 29792, 256);
companion object {
fun fromValue(value: String): SphincsVariant =
entries.find { it.value == value } ?: SHAKE128S
}
}
@Serializable
enum class PqAlgorithm(val value: String) {
@SerialName("dilithium3") DILITHIUM3("dilithium3"),
@SerialName("falcon512") FALCON512("falcon512"),
@SerialName("falcon1024") FALCON1024("falcon1024"),
@SerialName("sphincs128s") SPHINCS128S("sphincs128s"),
@SerialName("sphincs192s") SPHINCS192S("sphincs192s"),
@SerialName("sphincs256s") SPHINCS256S("sphincs256s")
}
@Serializable
enum class AlgorithmFamily(val value: String) {
@SerialName("classical") CLASSICAL("classical"),
@SerialName("lattice") LATTICE("lattice"),
@SerialName("hash_based") HASH_BASED("hash_based"),
@SerialName("hybrid") HYBRID("hybrid")
}
// ============================================================================
// Configuration Types
// ============================================================================
data class CryptoConfig(
val apiKey: String,
var endpoint: String = "https://crypto.synor.io/v1",
var timeout: Long = 30000,
var retries: Int = 3,
var debug: Boolean = false,
var defaultNetwork: Network = Network.MAINNET
)
data class DerivationConfig(
var salt: ByteArray? = null,
var info: ByteArray? = null,
var outputLength: Int = 32
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is DerivationConfig) return false
return salt.contentEquals(other.salt) && info.contentEquals(other.info) && outputLength == other.outputLength
}
override fun hashCode(): Int {
var result = salt?.contentHashCode() ?: 0
result = 31 * result + (info?.contentHashCode() ?: 0)
result = 31 * result + outputLength
return result
}
}
data class PasswordDerivationConfig(
val salt: ByteArray,
var iterations: Int = 100000,
var outputLength: Int = 32
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is PasswordDerivationConfig) return false
return salt.contentEquals(other.salt) && iterations == other.iterations && outputLength == other.outputLength
}
override fun hashCode(): Int {
var result = salt.contentHashCode()
result = 31 * result + iterations
result = 31 * result + outputLength
return result
}
}
data class DerivationPath(
val account: Int,
val change: Int,
val index: Int
) {
companion object {
const val COIN_TYPE = 0x5359
fun external(account: Int, index: Int) = DerivationPath(account, 0, index)
fun internal(account: Int, index: Int) = DerivationPath(account, 1, index)
}
override fun toString(): String = "m/44'/$COIN_TYPE'/$account'/$change/$index"
fun toMap(): Map<String, Int> = mapOf("account" to account, "change" to change, "index" to index)
}
// ============================================================================
// Key Types
// ============================================================================
@Serializable
data class HybridPublicKey(
val ed25519: String,
val dilithium: String
) {
fun getEd25519Bytes(): ByteArray = Base64.getDecoder().decode(ed25519)
fun getDilithiumBytes(): ByteArray = Base64.getDecoder().decode(dilithium)
fun size(): Int = getEd25519Bytes().size + getDilithiumBytes().size
fun toMap(): Map<String, String> = mapOf("ed25519" to ed25519, "dilithium" to dilithium)
}
@Serializable
data class SecretKey(
@SerialName("ed25519_seed") val ed25519Seed: String,
@SerialName("master_seed") val masterSeed: String
) {
fun getEd25519SeedBytes(): ByteArray = Base64.getDecoder().decode(ed25519Seed)
fun getMasterSeedBytes(): ByteArray = Base64.getDecoder().decode(masterSeed)
fun toMap(): Map<String, String> = mapOf("ed25519_seed" to ed25519Seed, "master_seed" to masterSeed)
}
@Serializable
data class FalconPublicKey(
val variant: String,
val bytes: String
) {
fun getVariantEnum(): FalconVariant = FalconVariant.fromValue(variant)
fun getKeyBytes(): ByteArray = Base64.getDecoder().decode(bytes)
}
@Serializable
data class FalconSecretKey(
val variant: String,
val bytes: String
) {
fun getVariantEnum(): FalconVariant = FalconVariant.fromValue(variant)
fun getKeyBytes(): ByteArray = Base64.getDecoder().decode(bytes)
}
@Serializable
data class SphincsPublicKey(
val variant: String,
val bytes: String
) {
fun getVariantEnum(): SphincsVariant = SphincsVariant.fromValue(variant)
fun getKeyBytes(): ByteArray = Base64.getDecoder().decode(bytes)
}
@Serializable
data class SphincsSecretKey(
val variant: String,
val bytes: String
) {
fun getVariantEnum(): SphincsVariant = SphincsVariant.fromValue(variant)
fun getKeyBytes(): ByteArray = Base64.getDecoder().decode(bytes)
}
// ============================================================================
// Signature Types
// ============================================================================
@Serializable
data class HybridSignature(
val ed25519: String,
val dilithium: String
) {
fun getEd25519Bytes(): ByteArray = Base64.getDecoder().decode(ed25519)
fun getDilithiumBytes(): ByteArray = Base64.getDecoder().decode(dilithium)
fun size(): Int = getEd25519Bytes().size + getDilithiumBytes().size
fun toBytes(): ByteArray {
val e = getEd25519Bytes()
val d = getDilithiumBytes()
return e + d
}
fun toMap(): Map<String, String> = mapOf("ed25519" to ed25519, "dilithium" to dilithium)
}
@Serializable
data class FalconSignature(
val variant: String,
val signature: String
) {
fun getVariantEnum(): FalconVariant = FalconVariant.fromValue(variant)
fun getBytes(): ByteArray = Base64.getDecoder().decode(signature)
fun size(): Int = getBytes().size
}
@Serializable
data class SphincsSignature(
val variant: String,
val signature: String
) {
fun getVariantEnum(): SphincsVariant = SphincsVariant.fromValue(variant)
fun getBytes(): ByteArray = Base64.getDecoder().decode(signature)
fun size(): Int = getBytes().size
}
// ============================================================================
// Keypair Types
// ============================================================================
@Serializable
data class HybridKeypair(
@SerialName("public_key") val publicKey: HybridPublicKey,
@SerialName("secret_key") val secretKey: SecretKey,
val addresses: Map<String, String> = emptyMap()
) {
fun getAddress(network: Network): String = addresses[network.value] ?: ""
}
@Serializable
data class FalconKeypair(
val variant: String,
@SerialName("public_key") val publicKey: FalconPublicKey,
@SerialName("secret_key") val secretKey: FalconSecretKey
) {
fun getVariantEnum(): FalconVariant = FalconVariant.fromValue(variant)
}
@Serializable
data class SphincsKeypair(
val variant: String,
@SerialName("public_key") val publicKey: SphincsPublicKey,
@SerialName("secret_key") val secretKey: SphincsSecretKey
) {
fun getVariantEnum(): SphincsVariant = SphincsVariant.fromValue(variant)
}
// ============================================================================
// Mnemonic Types
// ============================================================================
@Serializable
data class Mnemonic(
val phrase: String,
val words: List<String>? = null,
@SerialName("word_count") val wordCount: Int = 0,
val entropy: String? = null
) {
fun getWords(): List<String> = words ?: phrase.split(" ")
fun getWordCount(): Int = if (wordCount > 0) wordCount else getWords().size
fun getEntropy(): ByteArray = entropy?.let { Base64.getDecoder().decode(it) } ?: ByteArray(0)
}
@Serializable
data class MnemonicValidation(
val valid: Boolean,
val error: String? = null
)
// ============================================================================
// Address Types
// ============================================================================
@Serializable
data class Address(
val address: String,
val network: String,
@SerialName("pubkey_hash") val pubkeyHash: String? = null
) {
fun getNetwork(): Network = Network.fromValue(network)
fun getPubkeyHashBytes(): ByteArray = pubkeyHash?.let { Base64.getDecoder().decode(it) } ?: ByteArray(0)
}
// ============================================================================
// Hash Types
// ============================================================================
@Serializable
data class Hash256(
val hash: String
) {
fun getHex(): String = hash
fun getBytes(): ByteArray {
val result = ByteArray(hash.length / 2)
for (i in result.indices) {
result[i] = hash.substring(i * 2, i * 2 + 2).toInt(16).toByte()
}
return result
}
}
// ============================================================================
// Error Types
// ============================================================================
class CryptoException(
message: String,
val code: String? = null
) : RuntimeException(message)
// ============================================================================
// Constants
// ============================================================================
object CryptoConstants {
const val ED25519_PUBLIC_KEY_SIZE = 32
const val ED25519_SECRET_KEY_SIZE = 32
const val ED25519_SIGNATURE_SIZE = 64
const val DILITHIUM3_PUBLIC_KEY_SIZE = 1952
const val DILITHIUM3_SIGNATURE_SIZE = 3293
const val HYBRID_SIGNATURE_SIZE = 64 + 3293
const val COIN_TYPE = 0x5359
const val MIN_PBKDF2_ITERATIONS = 10000
const val MIN_SALT_LENGTH = 8
const val DEFAULT_ENDPOINT = "https://crypto.synor.io/v1"
}

View file

@ -0,0 +1,173 @@
"""
Synor Crypto SDK for Python
Quantum-resistant cryptographic primitives for the Synor blockchain.
Features:
- Hybrid Ed25519 + Dilithium3 signatures (quantum-resistant)
- BIP-39 mnemonic support (12-24 words)
- BIP-44 hierarchical key derivation
- Post-quantum algorithms: Falcon, SPHINCS+
- Secure key derivation (HKDF, PBKDF2)
Example:
```python
from synor_crypto import SynorCrypto, CryptoConfig, Network
async def main():
crypto = SynorCrypto(CryptoConfig(api_key='your-api-key'))
# Generate a mnemonic
mnemonic = await crypto.mnemonic.generate(24)
print(f'Backup words: {mnemonic.phrase}')
# Create keypair from mnemonic
keypair = await crypto.keypairs.from_mnemonic(mnemonic)
address = keypair.address(Network.MAINNET)
print(f'Address: {address}')
# Sign a message
message = b'Hello, Synor!'
signature = await crypto.signing.sign(keypair, message)
# Verify signature
valid = await crypto.signing.verify(keypair.public_key, message, signature)
print(f'Signature valid: {valid}')
await crypto.close()
```
"""
from .types import (
# Enumerations
Network,
FalconVariant,
SphincsVariant,
PqAlgorithm,
AlgorithmFamily,
# Configuration
CryptoConfig,
DerivationConfig,
PasswordDerivationConfig,
DerivationPath,
# Keys
HybridPublicKey,
SecretKey,
FalconPublicKey,
FalconSecretKey,
SphincsPublicKey,
SphincsSecretKey,
# Signatures
HybridSignature,
FalconSignature,
SphincsSignature,
# Keypairs
HybridKeypair,
FalconKeypair,
SphincsKeypair,
# Mnemonic
Mnemonic,
MnemonicValidation,
# Address & Hash
Address,
Hash256,
# Negotiation
AlgorithmCapabilities,
NegotiationPolicy,
NegotiationResult,
SessionParams,
# Error
CryptoError,
# Constants
CryptoConstants,
ALGORITHM_SIZES,
)
from .client import (
SynorCrypto,
MnemonicClient,
KeypairClient,
SigningClient,
FalconClient,
SphincsClient,
KdfClient,
HashClient,
NegotiationClient,
)
__version__ = '0.1.0'
__all__ = [
# Main client
'SynorCrypto',
# Sub-clients
'MnemonicClient',
'KeypairClient',
'SigningClient',
'FalconClient',
'SphincsClient',
'KdfClient',
'HashClient',
'NegotiationClient',
# Enumerations
'Network',
'FalconVariant',
'SphincsVariant',
'PqAlgorithm',
'AlgorithmFamily',
# Configuration
'CryptoConfig',
'DerivationConfig',
'PasswordDerivationConfig',
'DerivationPath',
# Keys
'HybridPublicKey',
'SecretKey',
'FalconPublicKey',
'FalconSecretKey',
'SphincsPublicKey',
'SphincsSecretKey',
# Signatures
'HybridSignature',
'FalconSignature',
'SphincsSignature',
# Keypairs
'HybridKeypair',
'FalconKeypair',
'SphincsKeypair',
# Mnemonic
'Mnemonic',
'MnemonicValidation',
# Address & Hash
'Address',
'Hash256',
# Negotiation
'AlgorithmCapabilities',
'NegotiationPolicy',
'NegotiationResult',
'SessionParams',
# Error
'CryptoError',
# Constants
'CryptoConstants',
'ALGORITHM_SIZES',
]

View file

@ -0,0 +1,552 @@
"""
Synor Crypto SDK Client for Python
Quantum-resistant cryptographic primitives for the Synor blockchain.
"""
import base64
from typing import Optional, List, Dict, Any, Union
import httpx
from .types import (
CryptoConfig, Network, Mnemonic, MnemonicValidation,
HybridKeypair, HybridPublicKey, HybridSignature, SecretKey,
FalconVariant, FalconKeypair, FalconSignature,
SphincsVariant, SphincsKeypair, SphincsSignature,
DerivationPath, DerivationConfig, PasswordDerivationConfig,
AlgorithmCapabilities, NegotiationPolicy, NegotiationResult, SessionParams,
Hash256, Address, CryptoError
)
class MnemonicClient:
"""Mnemonic operations."""
def __init__(self, crypto: 'SynorCrypto'):
self._crypto = crypto
async def generate(self, word_count: int = 24) -> Mnemonic:
"""Generates a new random mnemonic."""
result = await self._crypto._post('/mnemonic/generate', {'word_count': word_count})
return Mnemonic.from_dict(result)
async def from_phrase(self, phrase: str) -> Mnemonic:
"""Creates a mnemonic from a phrase string."""
result = await self._crypto._post('/mnemonic/from-phrase', {'phrase': phrase})
return Mnemonic.from_dict(result)
async def from_entropy(self, entropy: bytes) -> Mnemonic:
"""Creates a mnemonic from entropy bytes."""
result = await self._crypto._post('/mnemonic/from-entropy', {
'entropy': base64.b64encode(entropy).decode()
})
return Mnemonic.from_dict(result)
async def validate(self, phrase: str) -> MnemonicValidation:
"""Validates a mnemonic phrase."""
result = await self._crypto._post('/mnemonic/validate', {'phrase': phrase})
return MnemonicValidation.from_dict(result)
async def to_seed(self, mnemonic: Union[Mnemonic, str], passphrase: str = '') -> bytes:
"""Derives a 64-byte seed from a mnemonic."""
phrase = mnemonic.phrase if isinstance(mnemonic, Mnemonic) else mnemonic
result = await self._crypto._post('/mnemonic/to-seed', {
'phrase': phrase,
'passphrase': passphrase
})
return base64.b64decode(result['seed'])
async def suggest_words(self, partial: str, limit: int = 10) -> List[str]:
"""Suggests word completions from the BIP-39 wordlist."""
result = await self._crypto._post('/mnemonic/suggest', {
'partial': partial,
'limit': limit
})
return result['suggestions']
class KeypairClient:
"""Keypair operations."""
def __init__(self, crypto: 'SynorCrypto'):
self._crypto = crypto
async def generate(self) -> HybridKeypair:
"""Generates a new random hybrid keypair."""
result = await self._crypto._post('/keypair/generate')
return HybridKeypair.from_dict(result)
async def from_mnemonic(
self,
mnemonic: Union[Mnemonic, str],
passphrase: str = ''
) -> HybridKeypair:
"""Creates a keypair from a mnemonic."""
phrase = mnemonic.phrase if isinstance(mnemonic, Mnemonic) else mnemonic
result = await self._crypto._post('/keypair/from-mnemonic', {
'phrase': phrase,
'passphrase': passphrase
})
return HybridKeypair.from_dict(result)
async def from_seed(self, seed: bytes) -> HybridKeypair:
"""Creates a keypair from a 64-byte seed."""
result = await self._crypto._post('/keypair/from-seed', {
'seed': base64.b64encode(seed).decode()
})
return HybridKeypair.from_dict(result)
async def derive(
self,
parent_keypair: HybridKeypair,
path: DerivationPath
) -> HybridKeypair:
"""Derives a child keypair using BIP-44 path."""
result = await self._crypto._post('/keypair/derive', {
'public_key': parent_keypair.public_key.to_dict(),
'path': {'account': path.account, 'change': path.change, 'index': path.index}
})
return HybridKeypair.from_dict(result)
async def get_address(
self,
public_key: HybridPublicKey,
network: Network
) -> Address:
"""Gets the address for a public key."""
result = await self._crypto._post('/keypair/address', {
'public_key': public_key.to_dict(),
'network': network.value
})
return Address.from_dict(result)
class SigningClient:
"""Signing and verification operations."""
def __init__(self, crypto: 'SynorCrypto'):
self._crypto = crypto
async def sign(self, keypair: HybridKeypair, message: bytes) -> HybridSignature:
"""Signs a message with a hybrid keypair."""
result = await self._crypto._post('/sign/hybrid', {
'secret_key': {
'ed25519_seed': base64.b64encode(keypair.secret_key.ed25519_seed).decode(),
'master_seed': base64.b64encode(keypair.secret_key.master_seed).decode()
},
'message': base64.b64encode(message).decode()
})
return HybridSignature.from_dict(result)
async def verify(
self,
public_key: HybridPublicKey,
message: bytes,
signature: HybridSignature
) -> bool:
"""Verifies a hybrid signature."""
result = await self._crypto._post('/sign/verify', {
'public_key': public_key.to_dict(),
'message': base64.b64encode(message).decode(),
'signature': {
'ed25519': base64.b64encode(signature.ed25519).decode(),
'dilithium': base64.b64encode(signature.dilithium).decode()
}
})
return result['valid']
async def sign_ed25519(self, secret_key: bytes, message: bytes) -> bytes:
"""Signs a message using Ed25519 only."""
result = await self._crypto._post('/sign/ed25519', {
'secret_key': base64.b64encode(secret_key).decode(),
'message': base64.b64encode(message).decode()
})
return base64.b64decode(result['signature'])
async def verify_ed25519(
self,
public_key: bytes,
message: bytes,
signature: bytes
) -> bool:
"""Verifies an Ed25519 signature."""
result = await self._crypto._post('/sign/verify-ed25519', {
'public_key': base64.b64encode(public_key).decode(),
'message': base64.b64encode(message).decode(),
'signature': base64.b64encode(signature).decode()
})
return result['valid']
class FalconClient:
"""Falcon (FIPS 206) compact signature operations."""
def __init__(self, crypto: 'SynorCrypto'):
self._crypto = crypto
async def generate(self, variant: FalconVariant = FalconVariant.FALCON512) -> FalconKeypair:
"""Generates a Falcon keypair."""
result = await self._crypto._post('/falcon/generate', {'variant': variant.value})
return FalconKeypair.from_dict(result)
async def sign(self, keypair: FalconKeypair, message: bytes) -> FalconSignature:
"""Signs a message with Falcon."""
result = await self._crypto._post('/falcon/sign', {
'variant': keypair.variant.value,
'secret_key': base64.b64encode(keypair.secret_key.bytes).decode(),
'message': base64.b64encode(message).decode()
})
return FalconSignature.from_dict(result)
async def verify(
self,
public_key: bytes,
message: bytes,
signature: FalconSignature
) -> bool:
"""Verifies a Falcon signature."""
result = await self._crypto._post('/falcon/verify', {
'variant': signature.variant.value,
'public_key': base64.b64encode(public_key).decode(),
'message': base64.b64encode(message).decode(),
'signature': base64.b64encode(signature.bytes).decode()
})
return result['valid']
def signature_size(self, variant: FalconVariant) -> int:
"""Returns the signature size for a variant."""
return 690 if variant == FalconVariant.FALCON512 else 1330
def public_key_size(self, variant: FalconVariant) -> int:
"""Returns the public key size for a variant."""
return 897 if variant == FalconVariant.FALCON512 else 1793
def security_level(self, variant: FalconVariant) -> int:
"""Returns the security level in bits."""
return 128 if variant == FalconVariant.FALCON512 else 256
class SphincsClient:
"""SPHINCS+ (FIPS 205) hash-based signature operations."""
def __init__(self, crypto: 'SynorCrypto'):
self._crypto = crypto
async def generate(self, variant: SphincsVariant = SphincsVariant.SHAKE128S) -> SphincsKeypair:
"""Generates a SPHINCS+ keypair."""
result = await self._crypto._post('/sphincs/generate', {'variant': variant.value})
return SphincsKeypair.from_dict(result)
async def sign(self, keypair: SphincsKeypair, message: bytes) -> SphincsSignature:
"""Signs a message with SPHINCS+."""
result = await self._crypto._post('/sphincs/sign', {
'variant': keypair.variant.value,
'secret_key': base64.b64encode(keypair.secret_key.bytes).decode(),
'message': base64.b64encode(message).decode()
})
return SphincsSignature.from_dict(result)
async def verify(
self,
public_key: bytes,
message: bytes,
signature: SphincsSignature
) -> bool:
"""Verifies a SPHINCS+ signature."""
result = await self._crypto._post('/sphincs/verify', {
'variant': signature.variant.value,
'public_key': base64.b64encode(public_key).decode(),
'message': base64.b64encode(message).decode(),
'signature': base64.b64encode(signature.bytes).decode()
})
return result['valid']
def signature_size(self, variant: SphincsVariant) -> int:
"""Returns the signature size for a variant."""
sizes = {
SphincsVariant.SHAKE128S: 7856,
SphincsVariant.SHAKE192S: 16224,
SphincsVariant.SHAKE256S: 29792,
}
return sizes[variant]
def security_level(self, variant: SphincsVariant) -> int:
"""Returns the security level in bits."""
levels = {
SphincsVariant.SHAKE128S: 128,
SphincsVariant.SHAKE192S: 192,
SphincsVariant.SHAKE256S: 256,
}
return levels[variant]
class KdfClient:
"""Key derivation operations."""
def __init__(self, crypto: 'SynorCrypto'):
self._crypto = crypto
async def derive_key(
self,
seed: bytes,
config: Optional[DerivationConfig] = None
) -> bytes:
"""Derives a key using HKDF-SHA3-256."""
cfg = config or DerivationConfig()
body: Dict[str, Any] = {
'seed': base64.b64encode(seed).decode(),
'output_length': cfg.output_length
}
if cfg.salt:
body['salt'] = base64.b64encode(cfg.salt).decode()
if cfg.info:
body['info'] = base64.b64encode(cfg.info).decode()
result = await self._crypto._post('/kdf/hkdf', body)
return base64.b64decode(result['key'])
async def derive_from_password(
self,
password: Union[str, bytes],
config: PasswordDerivationConfig
) -> bytes:
"""Derives a key from a password using PBKDF2."""
password_bytes = password.encode() if isinstance(password, str) else password
result = await self._crypto._post('/kdf/pbkdf2', {
'password': base64.b64encode(password_bytes).decode(),
'salt': base64.b64encode(config.salt).decode(),
'iterations': config.iterations,
'output_length': config.output_length
})
return base64.b64decode(result['key'])
async def derive_ed25519_key(self, master_seed: bytes, account: int) -> bytes:
"""Derives an Ed25519 key from a master seed."""
result = await self._crypto._post('/kdf/ed25519', {
'master_seed': base64.b64encode(master_seed).decode(),
'account': account
})
return base64.b64decode(result['key'])
async def derive_child_key(
self,
parent_key: bytes,
chain_code: bytes,
index: int
) -> tuple[bytes, bytes]:
"""Derives a child key using BIP-32 style derivation."""
result = await self._crypto._post('/kdf/child', {
'parent_key': base64.b64encode(parent_key).decode(),
'chain_code': base64.b64encode(chain_code).decode(),
'index': index
})
return (
base64.b64decode(result['key']),
base64.b64decode(result['chain_code'])
)
def create_path(
self,
account: int,
change: int = 0,
index: int = 0
) -> DerivationPath:
"""Creates a BIP-44 derivation path."""
return DerivationPath(account=account, change=change, index=index)
class HashClient:
"""Hashing operations."""
def __init__(self, crypto: 'SynorCrypto'):
self._crypto = crypto
async def sha3_256(self, data: bytes) -> Hash256:
"""Computes SHA3-256 hash."""
result = await self._crypto._post('/hash/sha3-256', {
'data': base64.b64encode(data).decode()
})
return Hash256.from_dict(result)
async def blake3(self, data: bytes) -> Hash256:
"""Computes BLAKE3 hash."""
result = await self._crypto._post('/hash/blake3', {
'data': base64.b64encode(data).decode()
})
return Hash256.from_dict(result)
async def keccak256(self, data: bytes) -> Hash256:
"""Computes Keccak-256 hash."""
result = await self._crypto._post('/hash/keccak256', {
'data': base64.b64encode(data).decode()
})
return Hash256.from_dict(result)
async def combine(self, hashes: List[bytes]) -> Hash256:
"""Combines multiple hashes."""
result = await self._crypto._post('/hash/combine', {
'hashes': [base64.b64encode(h).decode() for h in hashes]
})
return Hash256.from_dict(result)
class NegotiationClient:
"""Algorithm negotiation operations."""
def __init__(self, crypto: 'SynorCrypto'):
self._crypto = crypto
async def get_capabilities(self) -> AlgorithmCapabilities:
"""Gets the local capabilities."""
result = await self._crypto._get('/negotiation/capabilities')
return AlgorithmCapabilities.from_dict(result)
async def negotiate(
self,
peer_capabilities: AlgorithmCapabilities,
policy: NegotiationPolicy
) -> NegotiationResult:
"""Negotiates algorithm selection with a peer."""
result = await self._crypto._post('/negotiation/negotiate', {
'peer_capabilities': {
'pq_algorithms': [a.value for a in peer_capabilities.pq_algorithms],
'classical': peer_capabilities.classical,
'hybrid': peer_capabilities.hybrid,
'preferred': peer_capabilities.preferred.value if peer_capabilities.preferred else None
},
'policy': {
'min_security_level': policy.min_security_level,
'prefer_compact': policy.prefer_compact,
'allow_classical': policy.allow_classical,
'required_families': [f.value for f in policy.required_families]
}
})
return NegotiationResult.from_dict(result)
async def establish_session(
self,
result: NegotiationResult,
peer_public_key: bytes
) -> SessionParams:
"""Establishes session parameters after negotiation."""
resp = await self._crypto._post('/negotiation/session', {
'negotiation_result': {
'algorithm': result.algorithm.value,
'security_level': result.security_level,
'family': result.family.value,
'hybrid': result.hybrid
},
'peer_public_key': base64.b64encode(peer_public_key).decode()
})
return SessionParams.from_dict(resp)
class SynorCrypto:
"""
Synor Crypto SDK Client
Provides quantum-resistant cryptographic operations for the Synor blockchain.
Example:
```python
from synor_crypto import SynorCrypto, CryptoConfig
async def main():
crypto = SynorCrypto(CryptoConfig(api_key='your-api-key'))
# Generate a mnemonic
mnemonic = await crypto.mnemonic.generate(24)
print(f'Backup words: {mnemonic.phrase}')
# Create keypair from mnemonic
keypair = await crypto.keypairs.from_mnemonic(mnemonic)
address = keypair.address(Network.MAINNET)
# Sign a message
signature = await crypto.signing.sign(keypair, b'Hello!')
await crypto.close()
```
"""
def __init__(self, config: CryptoConfig):
self._config = config
self._client = httpx.AsyncClient(
base_url=config.endpoint,
timeout=config.timeout / 1000,
headers={
'Authorization': f'Bearer {config.api_key}',
'Content-Type': 'application/json',
'X-SDK-Version': 'python/0.1.0'
}
)
self._closed = False
self.mnemonic = MnemonicClient(self)
self.keypairs = KeypairClient(self)
self.signing = SigningClient(self)
self.falcon = FalconClient(self)
self.sphincs = SphincsClient(self)
self.kdf = KdfClient(self)
self.hash = HashClient(self)
self.negotiation = NegotiationClient(self)
@property
def default_network(self) -> Network:
"""Returns the default network."""
return self._config.default_network
async def health_check(self) -> bool:
"""Checks if the service is healthy."""
try:
result = await self._get('/health')
return result.get('status') == 'healthy'
except Exception:
return False
async def get_info(self) -> Dict[str, Any]:
"""Gets service information."""
return await self._get('/info')
async def close(self) -> None:
"""Closes the client."""
self._closed = True
await self._client.aclose()
@property
def is_closed(self) -> bool:
"""Returns True if the client is closed."""
return self._closed
async def __aenter__(self) -> 'SynorCrypto':
return self
async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
await self.close()
async def _get(self, path: str) -> Dict[str, Any]:
"""Makes a GET request."""
self._check_closed()
response = await self._client.get(path)
return self._handle_response(response)
async def _post(self, path: str, body: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
"""Makes a POST request."""
self._check_closed()
response = await self._client.post(path, json=body or {})
return self._handle_response(response)
def _handle_response(self, response: httpx.Response) -> Dict[str, Any]:
"""Handles the HTTP response."""
data = response.json()
if not response.is_success:
raise CryptoError(
data.get('message', f'HTTP {response.status_code}'),
data.get('code')
)
return data
def _check_closed(self) -> None:
"""Checks if the client is closed."""
if self._closed:
raise CryptoError('Client has been closed', 'CLIENT_CLOSED')

View file

@ -0,0 +1,526 @@
"""
Synor Crypto SDK Types
Quantum-resistant cryptographic types for the Synor blockchain.
"""
from dataclasses import dataclass, field
from enum import Enum
from typing import List, Optional, Dict, Callable
import base64
# ============================================================================
# Enumerations
# ============================================================================
class Network(str, Enum):
"""Network type for address generation."""
MAINNET = "mainnet"
TESTNET = "testnet"
DEVNET = "devnet"
class FalconVariant(str, Enum):
"""Falcon variant selection."""
FALCON512 = "falcon512" # 128-bit security, ~690 byte signatures
FALCON1024 = "falcon1024" # 256-bit security, ~1330 byte signatures
class SphincsVariant(str, Enum):
"""SPHINCS+ variant selection."""
SHAKE128S = "shake128s" # 128-bit security, ~7.8KB signatures
SHAKE192S = "shake192s" # 192-bit security, ~16KB signatures
SHAKE256S = "shake256s" # 256-bit security, ~30KB signatures
class PqAlgorithm(str, Enum):
"""Post-quantum algorithm selection."""
DILITHIUM3 = "dilithium3"
FALCON512 = "falcon512"
FALCON1024 = "falcon1024"
SPHINCS128S = "sphincs128s"
SPHINCS192S = "sphincs192s"
SPHINCS256S = "sphincs256s"
class AlgorithmFamily(str, Enum):
"""Algorithm family classification."""
CLASSICAL = "classical"
LATTICE = "lattice"
HASH_BASED = "hash_based"
HYBRID = "hybrid"
# ============================================================================
# Configuration Types
# ============================================================================
@dataclass
class CryptoConfig:
"""Crypto SDK configuration."""
api_key: str
endpoint: str = "https://crypto.synor.io/v1"
timeout: int = 30000
retries: int = 3
debug: bool = False
default_network: Network = Network.MAINNET
@dataclass
class DerivationConfig:
"""Key derivation configuration."""
salt: Optional[bytes] = None
info: Optional[bytes] = None
output_length: int = 32
@dataclass
class PasswordDerivationConfig:
"""Password derivation configuration."""
salt: bytes = field(default_factory=bytes)
iterations: int = 100000
output_length: int = 32
@dataclass
class DerivationPath:
"""BIP-44 derivation path."""
account: int = 0
change: int = 0
index: int = 0
COIN_TYPE: int = 0x5359 # Synor coin type
def __str__(self) -> str:
return f"m/44'/{self.COIN_TYPE}'/{self.account}'/{self.change}/{self.index}"
@classmethod
def external(cls, account: int, index: int) -> 'DerivationPath':
"""Creates a path for external addresses."""
return cls(account=account, change=0, index=index)
@classmethod
def internal(cls, account: int, index: int) -> 'DerivationPath':
"""Creates a path for internal (change) addresses."""
return cls(account=account, change=1, index=index)
# ============================================================================
# Key Types
# ============================================================================
@dataclass
class HybridPublicKey:
"""Hybrid public key (Ed25519 + Dilithium3)."""
ed25519: bytes # 32 bytes
dilithium: bytes # ~1952 bytes
@classmethod
def from_dict(cls, data: dict) -> 'HybridPublicKey':
return cls(
ed25519=base64.b64decode(data['ed25519']),
dilithium=base64.b64decode(data['dilithium'])
)
def to_dict(self) -> dict:
return {
'ed25519': base64.b64encode(self.ed25519).decode(),
'dilithium': base64.b64encode(self.dilithium).decode()
}
def size(self) -> int:
"""Returns the total size in bytes."""
return len(self.ed25519) + len(self.dilithium)
@dataclass
class SecretKey:
"""Secret key (master seed)."""
ed25519_seed: bytes # 32 bytes
master_seed: bytes # 64 bytes
@classmethod
def from_dict(cls, data: dict) -> 'SecretKey':
return cls(
ed25519_seed=base64.b64decode(data['ed25519_seed']),
master_seed=base64.b64decode(data['master_seed'])
)
@dataclass
class FalconPublicKey:
"""Falcon public key."""
variant: FalconVariant
bytes: bytes
@classmethod
def from_dict(cls, data: dict) -> 'FalconPublicKey':
return cls(
variant=FalconVariant(data['variant']),
bytes=base64.b64decode(data['bytes'])
)
@dataclass
class FalconSecretKey:
"""Falcon secret key."""
variant: FalconVariant
bytes: bytes
@classmethod
def from_dict(cls, data: dict) -> 'FalconSecretKey':
return cls(
variant=FalconVariant(data['variant']),
bytes=base64.b64decode(data['bytes'])
)
@dataclass
class SphincsPublicKey:
"""SPHINCS+ public key."""
variant: SphincsVariant
bytes: bytes
@classmethod
def from_dict(cls, data: dict) -> 'SphincsPublicKey':
return cls(
variant=SphincsVariant(data['variant']),
bytes=base64.b64decode(data['bytes'])
)
@dataclass
class SphincsSecretKey:
"""SPHINCS+ secret key."""
variant: SphincsVariant
bytes: bytes
@classmethod
def from_dict(cls, data: dict) -> 'SphincsSecretKey':
return cls(
variant=SphincsVariant(data['variant']),
bytes=base64.b64decode(data['bytes'])
)
# ============================================================================
# Signature Types
# ============================================================================
@dataclass
class HybridSignature:
"""Hybrid signature (Ed25519 + Dilithium3)."""
ed25519: bytes # 64 bytes
dilithium: bytes # ~3293 bytes
@classmethod
def from_dict(cls, data: dict) -> 'HybridSignature':
return cls(
ed25519=base64.b64decode(data['ed25519']),
dilithium=base64.b64decode(data['dilithium'])
)
def to_bytes(self) -> bytes:
"""Serializes the signature to bytes."""
return self.ed25519 + self.dilithium
@classmethod
def from_bytes(cls, data: bytes) -> 'HybridSignature':
"""Deserializes a signature from bytes."""
if len(data) < 64:
raise ValueError("Invalid signature length")
return cls(
ed25519=data[:64],
dilithium=data[64:]
)
def size(self) -> int:
"""Returns the total size in bytes."""
return len(self.ed25519) + len(self.dilithium)
@dataclass
class FalconSignature:
"""Falcon signature."""
variant: FalconVariant
bytes: bytes
@classmethod
def from_dict(cls, data: dict) -> 'FalconSignature':
return cls(
variant=FalconVariant(data['variant']),
bytes=base64.b64decode(data['signature'])
)
def size(self) -> int:
return len(self.bytes)
@dataclass
class SphincsSignature:
"""SPHINCS+ signature."""
variant: SphincsVariant
bytes: bytes
@classmethod
def from_dict(cls, data: dict) -> 'SphincsSignature':
return cls(
variant=SphincsVariant(data['variant']),
bytes=base64.b64decode(data['signature'])
)
def size(self) -> int:
return len(self.bytes)
# ============================================================================
# Keypair Types
# ============================================================================
@dataclass
class HybridKeypair:
"""Hybrid keypair (Ed25519 + Dilithium3)."""
public_key: HybridPublicKey
secret_key: SecretKey
_addresses: Dict[str, str] = field(default_factory=dict)
def address(self, network: Network) -> str:
"""Returns the address for the given network."""
return self._addresses.get(network.value, "")
@classmethod
def from_dict(cls, data: dict) -> 'HybridKeypair':
return cls(
public_key=HybridPublicKey.from_dict(data['public_key']),
secret_key=SecretKey.from_dict(data['secret_key']),
_addresses=data.get('addresses', {})
)
@dataclass
class FalconKeypair:
"""Falcon keypair."""
variant: FalconVariant
public_key: FalconPublicKey
secret_key: FalconSecretKey
@classmethod
def from_dict(cls, data: dict) -> 'FalconKeypair':
return cls(
variant=FalconVariant(data['variant']),
public_key=FalconPublicKey.from_dict(data['public_key']),
secret_key=FalconSecretKey.from_dict(data['secret_key'])
)
@dataclass
class SphincsKeypair:
"""SPHINCS+ keypair."""
variant: SphincsVariant
public_key: SphincsPublicKey
secret_key: SphincsSecretKey
@classmethod
def from_dict(cls, data: dict) -> 'SphincsKeypair':
return cls(
variant=SphincsVariant(data['variant']),
public_key=SphincsPublicKey.from_dict(data['public_key']),
secret_key=SphincsSecretKey.from_dict(data['secret_key'])
)
# ============================================================================
# Mnemonic Types
# ============================================================================
@dataclass
class Mnemonic:
"""BIP-39 mnemonic phrase."""
phrase: str
words: List[str] = field(default_factory=list)
word_count: int = 24
entropy: bytes = field(default_factory=bytes)
def __post_init__(self):
if not self.words:
self.words = self.phrase.split()
if not self.word_count:
self.word_count = len(self.words)
@classmethod
def from_dict(cls, data: dict) -> 'Mnemonic':
return cls(
phrase=data['phrase'],
words=data.get('words', data['phrase'].split()),
word_count=data.get('word_count', len(data['phrase'].split())),
entropy=base64.b64decode(data.get('entropy', '')) if data.get('entropy') else b''
)
@dataclass
class MnemonicValidation:
"""Mnemonic validation result."""
valid: bool
error: Optional[str] = None
@classmethod
def from_dict(cls, data: dict) -> 'MnemonicValidation':
return cls(
valid=data['valid'],
error=data.get('error')
)
# ============================================================================
# Address Types
# ============================================================================
@dataclass
class Address:
"""Blockchain address."""
address: str
network: Network
pubkey_hash: bytes = field(default_factory=bytes)
@classmethod
def from_dict(cls, data: dict) -> 'Address':
return cls(
address=data['address'],
network=Network(data['network']),
pubkey_hash=base64.b64decode(data.get('pubkey_hash', '')) if data.get('pubkey_hash') else b''
)
# ============================================================================
# Hash Types
# ============================================================================
@dataclass
class Hash256:
"""256-bit hash."""
bytes: bytes
hex: str
@classmethod
def from_dict(cls, data: dict) -> 'Hash256':
hex_str = data['hash']
return cls(
bytes=bytes.fromhex(hex_str),
hex=hex_str
)
# ============================================================================
# Negotiation Types
# ============================================================================
@dataclass
class AlgorithmCapabilities:
"""Algorithm capabilities for negotiation."""
pq_algorithms: List[PqAlgorithm]
classical: bool = True
hybrid: bool = True
preferred: Optional[PqAlgorithm] = None
@classmethod
def from_dict(cls, data: dict) -> 'AlgorithmCapabilities':
return cls(
pq_algorithms=[PqAlgorithm(a) for a in data.get('pq_algorithms', [])],
classical=data.get('classical', True),
hybrid=data.get('hybrid', True),
preferred=PqAlgorithm(data['preferred']) if data.get('preferred') else None
)
@dataclass
class NegotiationPolicy:
"""Negotiation policy."""
min_security_level: int = 128
prefer_compact: bool = False
allow_classical: bool = False
required_families: List[AlgorithmFamily] = field(default_factory=list)
@dataclass
class NegotiationResult:
"""Negotiation result."""
algorithm: PqAlgorithm
security_level: int
family: AlgorithmFamily
hybrid: bool
@classmethod
def from_dict(cls, data: dict) -> 'NegotiationResult':
return cls(
algorithm=PqAlgorithm(data['algorithm']),
security_level=data['security_level'],
family=AlgorithmFamily(data['family']),
hybrid=data['hybrid']
)
@dataclass
class SessionParams:
"""Session parameters after negotiation."""
algorithm: PqAlgorithm
session_key: Optional[bytes] = None
expires_at: Optional[int] = None
@classmethod
def from_dict(cls, data: dict) -> 'SessionParams':
return cls(
algorithm=PqAlgorithm(data['algorithm']),
session_key=base64.b64decode(data['session_key']) if data.get('session_key') else None,
expires_at=data.get('expires_at')
)
# ============================================================================
# Error Types
# ============================================================================
class CryptoError(Exception):
"""Crypto operation error."""
def __init__(self, message: str, code: Optional[str] = None):
super().__init__(message)
self.code = code
# ============================================================================
# Constants
# ============================================================================
class CryptoConstants:
"""Crypto constants."""
ED25519_PUBLIC_KEY_SIZE = 32
ED25519_SECRET_KEY_SIZE = 32
ED25519_SIGNATURE_SIZE = 64
DILITHIUM3_PUBLIC_KEY_SIZE = 1952
DILITHIUM3_SIGNATURE_SIZE = 3293
HYBRID_SIGNATURE_SIZE = 64 + 3293
FALCON512_SIGNATURE_SIZE = 690
FALCON512_PUBLIC_KEY_SIZE = 897
FALCON1024_SIGNATURE_SIZE = 1330
FALCON1024_PUBLIC_KEY_SIZE = 1793
SPHINCS128S_SIGNATURE_SIZE = 7856
SPHINCS192S_SIGNATURE_SIZE = 16224
SPHINCS256S_SIGNATURE_SIZE = 29792
COIN_TYPE = 0x5359
MIN_PBKDF2_ITERATIONS = 10000
MIN_SALT_LENGTH = 8
DEFAULT_ENDPOINT = "https://crypto.synor.io/v1"
# Algorithm size comparison
ALGORITHM_SIZES = {
'ed25519': {'signature': 64, 'public_key': 32},
'dilithium3': {'signature': 3293, 'public_key': 1952},
'hybrid': {'signature': 3357, 'public_key': 1984},
'falcon512': {'signature': 690, 'public_key': 897},
'falcon1024': {'signature': 1330, 'public_key': 1793},
'sphincs128s': {'signature': 7856, 'public_key': 32},
'sphincs192s': {'signature': 16224, 'public_key': 48},
'sphincs256s': {'signature': 29792, 'public_key': 64},
}

View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
require_relative 'crypto/types'
require_relative 'crypto/client'
module Synor
# Synor Crypto SDK for Ruby
#
# Quantum-resistant cryptographic primitives for the Synor blockchain.
module Crypto
VERSION = '0.1.0'
end
end

View file

@ -0,0 +1,334 @@
# frozen_string_literal: true
require 'net/http'
require 'json'
require 'uri'
require 'base64'
require_relative 'types'
module Synor
module Crypto
# Synor Crypto SDK for Ruby
#
# Quantum-resistant cryptographic primitives for the Synor blockchain.
#
# @example
# config = Synor::Crypto::CryptoConfig.new(api_key: 'your-api-key')
# crypto = Synor::Crypto::SynorCrypto.new(config)
#
# # Generate a mnemonic
# mnemonic = crypto.mnemonic.generate(24)
# puts "Backup words: #{mnemonic.phrase}"
#
# # Create keypair from mnemonic
# keypair = crypto.keypairs.from_mnemonic(mnemonic.phrase, '')
# address = keypair.get_address(Synor::Crypto::Network::MAINNET)
#
# # Sign a message
# signature = crypto.signing.sign(keypair, 'Hello!')
#
class SynorCrypto
attr_reader :config, :mnemonic, :keypairs, :signing, :falcon, :sphincs, :kdf, :hash
def initialize(config)
@config = config
@closed = false
@mnemonic = MnemonicClient.new(self)
@keypairs = KeypairClient.new(self)
@signing = SigningClient.new(self)
@falcon = FalconClient.new(self)
@sphincs = SphincsClient.new(self)
@kdf = KdfClient.new(self)
@hash = HashClient.new(self)
end
def default_network
config.default_network
end
def health_check
result = get('/health')
result['status'] == 'healthy'
rescue StandardError
false
end
def get_info
get('/info')
end
def close
@closed = true
end
def closed?
@closed
end
# @api private
def get(path)
check_closed!
request(:get, path)
end
# @api private
def post(path, body = {})
check_closed!
request(:post, path, body)
end
private
def request(method, path, body = nil)
uri = URI.parse("#{config.endpoint}#{path}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'
http.open_timeout = config.timeout / 1000.0
http.read_timeout = config.timeout / 1000.0
request = case method
when :get
Net::HTTP::Get.new(uri.request_uri)
when :post
req = Net::HTTP::Post.new(uri.request_uri)
req.body = JSON.generate(body || {})
req
end
request['Authorization'] = "Bearer #{config.api_key}"
request['Content-Type'] = 'application/json'
request['X-SDK-Version'] = 'ruby/0.1.0'
response = http.request(request)
handle_response(response)
end
def handle_response(response)
body = JSON.parse(response.body)
unless response.is_a?(Net::HTTPSuccess)
message = body['message'] || "HTTP #{response.code}"
code = body['code']
raise CryptoError.new(message, code: code, http_status: response.code.to_i)
end
body
end
def check_closed!
raise CryptoError.new('Client has been closed', code: 'CLIENT_CLOSED') if @closed
end
end
# Mnemonic sub-client
class MnemonicClient
def initialize(crypto)
@crypto = crypto
end
def generate(word_count = 24)
result = @crypto.post('/mnemonic/generate', { word_count: word_count })
Mnemonic.from_hash(result)
end
def from_phrase(phrase)
result = @crypto.post('/mnemonic/from-phrase', { phrase: phrase })
Mnemonic.from_hash(result)
end
def validate(phrase)
result = @crypto.post('/mnemonic/validate', { phrase: phrase })
MnemonicValidation.from_hash(result)
end
def to_seed(phrase, passphrase = '')
result = @crypto.post('/mnemonic/to-seed', { phrase: phrase, passphrase: passphrase })
Base64.strict_decode64(result['seed'])
end
def suggest_words(partial, limit = 5)
result = @crypto.post('/mnemonic/suggest', { partial: partial, limit: limit })
result['suggestions'] || []
end
end
# Keypair sub-client
class KeypairClient
def initialize(crypto)
@crypto = crypto
end
def generate
result = @crypto.post('/keypair/generate')
HybridKeypair.from_hash(result)
end
def from_mnemonic(phrase, passphrase = '')
result = @crypto.post('/keypair/from-mnemonic', { phrase: phrase, passphrase: passphrase })
HybridKeypair.from_hash(result)
end
def from_seed(seed)
result = @crypto.post('/keypair/from-seed', { seed: Base64.strict_encode64(seed) })
HybridKeypair.from_hash(result)
end
def get_address(public_key, network)
result = @crypto.post('/keypair/address', {
public_key: public_key.to_h,
network: network
})
Address.from_hash(result)
end
end
# Signing sub-client
class SigningClient
def initialize(crypto)
@crypto = crypto
end
def sign(keypair, message)
message_bytes = message.is_a?(String) ? message.encode('UTF-8').bytes.pack('C*') : message
result = @crypto.post('/sign/hybrid', {
secret_key: keypair.secret_key.to_h,
message: Base64.strict_encode64(message_bytes)
})
HybridSignature.from_hash(result)
end
def verify(public_key, message, signature)
message_bytes = message.is_a?(String) ? message.encode('UTF-8').bytes.pack('C*') : message
result = @crypto.post('/sign/verify', {
public_key: public_key.to_h,
message: Base64.strict_encode64(message_bytes),
signature: signature.to_h
})
result['valid'] == true
end
def sign_ed25519(secret_key, message)
result = @crypto.post('/sign/ed25519', {
secret_key: Base64.strict_encode64(secret_key),
message: Base64.strict_encode64(message)
})
Base64.strict_decode64(result['signature'])
end
end
# Falcon sub-client
class FalconClient
def initialize(crypto)
@crypto = crypto
end
def generate(variant = FalconVariant::FALCON512)
result = @crypto.post('/falcon/generate', { variant: variant })
FalconKeypair.from_hash(result)
end
def sign(keypair, message)
result = @crypto.post('/falcon/sign', {
variant: keypair.variant,
secret_key: Base64.strict_encode64(keypair.secret_key.key_bytes),
message: Base64.strict_encode64(message)
})
FalconSignature.from_hash(result)
end
def verify(public_key, message, signature)
result = @crypto.post('/falcon/verify', {
variant: signature.variant,
public_key: Base64.strict_encode64(public_key),
message: Base64.strict_encode64(message),
signature: Base64.strict_encode64(signature.signature_bytes)
})
result['valid'] == true
end
end
# SPHINCS+ sub-client
class SphincsClient
def initialize(crypto)
@crypto = crypto
end
def generate(variant = SphincsVariant::SHAKE128S)
result = @crypto.post('/sphincs/generate', { variant: variant })
SphincsKeypair.from_hash(result)
end
def sign(keypair, message)
result = @crypto.post('/sphincs/sign', {
variant: keypair.variant,
secret_key: Base64.strict_encode64(keypair.secret_key.key_bytes),
message: Base64.strict_encode64(message)
})
SphincsSignature.from_hash(result)
end
def verify(public_key, message, signature)
result = @crypto.post('/sphincs/verify', {
variant: signature.variant,
public_key: Base64.strict_encode64(public_key),
message: Base64.strict_encode64(message),
signature: Base64.strict_encode64(signature.signature_bytes)
})
result['valid'] == true
end
end
# KDF sub-client
class KdfClient
def initialize(crypto)
@crypto = crypto
end
def derive_key(seed, config = DerivationConfig.new)
body = {
seed: Base64.strict_encode64(seed),
output_length: config.output_length
}
body[:salt] = Base64.strict_encode64(config.salt) if config.salt
body[:info] = Base64.strict_encode64(config.info) if config.info
result = @crypto.post('/kdf/hkdf', body)
Base64.strict_decode64(result['key'])
end
def derive_from_password(password, config)
result = @crypto.post('/kdf/pbkdf2', {
password: Base64.strict_encode64(password),
salt: Base64.strict_encode64(config.salt),
iterations: config.iterations,
output_length: config.output_length
})
Base64.strict_decode64(result['key'])
end
end
# Hash sub-client
class HashClient
def initialize(crypto)
@crypto = crypto
end
def sha3_256(data)
result = @crypto.post('/hash/sha3-256', { data: Base64.strict_encode64(data) })
Hash256.from_hash(result)
end
def blake3(data)
result = @crypto.post('/hash/blake3', { data: Base64.strict_encode64(data) })
Hash256.from_hash(result)
end
def keccak256(data)
result = @crypto.post('/hash/keccak256', { data: Base64.strict_encode64(data) })
Hash256.from_hash(result)
end
end
end
end

View file

@ -0,0 +1,576 @@
# frozen_string_literal: true
require 'base64'
module Synor
module Crypto
# ============================================================================
# Constants
# ============================================================================
ED25519_PUBLIC_KEY_SIZE = 32
ED25519_SECRET_KEY_SIZE = 32
ED25519_SIGNATURE_SIZE = 64
DILITHIUM3_PUBLIC_KEY_SIZE = 1952
DILITHIUM3_SIGNATURE_SIZE = 3293
HYBRID_SIGNATURE_SIZE = 64 + 3293
COIN_TYPE = 0x5359
MIN_PBKDF2_ITERATIONS = 10_000
MIN_SALT_LENGTH = 8
DEFAULT_ENDPOINT = 'https://crypto.synor.io/v1'
# ============================================================================
# Enumerations
# ============================================================================
module Network
MAINNET = 'mainnet'
TESTNET = 'testnet'
DEVNET = 'devnet'
def self.all
[MAINNET, TESTNET, DEVNET]
end
end
module FalconVariant
FALCON512 = 'falcon512'
FALCON1024 = 'falcon1024'
SIGNATURE_SIZES = {
FALCON512 => 690,
FALCON1024 => 1330
}.freeze
PUBLIC_KEY_SIZES = {
FALCON512 => 897,
FALCON1024 => 1793
}.freeze
SECURITY_LEVELS = {
FALCON512 => 128,
FALCON1024 => 256
}.freeze
def self.signature_size(variant)
SIGNATURE_SIZES[variant] || 690
end
def self.public_key_size(variant)
PUBLIC_KEY_SIZES[variant] || 897
end
def self.security_level(variant)
SECURITY_LEVELS[variant] || 128
end
end
module SphincsVariant
SHAKE128S = 'shake128s'
SHAKE192S = 'shake192s'
SHAKE256S = 'shake256s'
SIGNATURE_SIZES = {
SHAKE128S => 7856,
SHAKE192S => 16_224,
SHAKE256S => 29_792
}.freeze
SECURITY_LEVELS = {
SHAKE128S => 128,
SHAKE192S => 192,
SHAKE256S => 256
}.freeze
def self.signature_size(variant)
SIGNATURE_SIZES[variant] || 7856
end
def self.security_level(variant)
SECURITY_LEVELS[variant] || 128
end
end
module PqAlgorithm
DILITHIUM3 = 'dilithium3'
FALCON512 = 'falcon512'
FALCON1024 = 'falcon1024'
SPHINCS128S = 'sphincs128s'
SPHINCS192S = 'sphincs192s'
SPHINCS256S = 'sphincs256s'
end
module AlgorithmFamily
CLASSICAL = 'classical'
LATTICE = 'lattice'
HASH_BASED = 'hash_based'
HYBRID = 'hybrid'
end
# ============================================================================
# Configuration Types
# ============================================================================
# Configuration for the Crypto SDK.
class CryptoConfig
attr_accessor :api_key, :endpoint, :timeout, :retries, :debug, :default_network
def initialize(api_key:, endpoint: DEFAULT_ENDPOINT, timeout: 30_000, retries: 3, debug: false, default_network: Network::MAINNET)
@api_key = api_key
@endpoint = endpoint
@timeout = timeout
@retries = retries
@debug = debug
@default_network = default_network
end
end
# Configuration for key derivation.
class DerivationConfig
attr_accessor :salt, :info, :output_length
def initialize(salt: nil, info: nil, output_length: 32)
@salt = salt
@info = info
@output_length = output_length
end
end
# Configuration for password-based key derivation.
class PasswordDerivationConfig
attr_accessor :salt, :iterations, :output_length
def initialize(salt:, iterations: 100_000, output_length: 32)
@salt = salt
@iterations = iterations
@output_length = output_length
end
end
# BIP-44 derivation path.
class DerivationPath
COIN_TYPE = 0x5359
attr_reader :account, :change, :index
def initialize(account:, change:, index:)
@account = account
@change = change
@index = index
end
def self.external(account:, index:)
new(account: account, change: 0, index: index)
end
def self.internal(account:, index:)
new(account: account, change: 1, index: index)
end
def to_s
"m/44'/#{COIN_TYPE}'/#{account}'/#{change}/#{index}"
end
def to_h
{ account: account, change: change, index: index }
end
end
# ============================================================================
# Key Types
# ============================================================================
# Hybrid public key combining Ed25519 and Dilithium3.
class HybridPublicKey
attr_accessor :ed25519, :dilithium
def initialize(ed25519: nil, dilithium: nil)
@ed25519 = ed25519
@dilithium = dilithium
end
def ed25519_bytes
Base64.strict_decode64(@ed25519 || '')
end
def dilithium_bytes
Base64.strict_decode64(@dilithium || '')
end
def size
ed25519_bytes.bytesize + dilithium_bytes.bytesize
end
def to_h
{ 'ed25519' => ed25519, 'dilithium' => dilithium }
end
def self.from_hash(hash)
new(ed25519: hash['ed25519'], dilithium: hash['dilithium'])
end
end
# Secret key for hybrid signatures.
class SecretKey
attr_accessor :ed25519_seed, :master_seed
def initialize(ed25519_seed: nil, master_seed: nil)
@ed25519_seed = ed25519_seed
@master_seed = master_seed
end
def ed25519_seed_bytes
Base64.strict_decode64(@ed25519_seed || '')
end
def master_seed_bytes
Base64.strict_decode64(@master_seed || '')
end
def to_h
{ 'ed25519_seed' => ed25519_seed, 'master_seed' => master_seed }
end
def self.from_hash(hash)
new(ed25519_seed: hash['ed25519_seed'], master_seed: hash['master_seed'])
end
end
# Falcon public key.
class FalconPublicKey
attr_accessor :variant, :bytes
def initialize(variant: nil, bytes: nil)
@variant = variant
@bytes = bytes
end
def key_bytes
Base64.strict_decode64(@bytes || '')
end
def self.from_hash(hash)
new(variant: hash['variant'], bytes: hash['bytes'])
end
end
# Falcon secret key.
class FalconSecretKey
attr_accessor :variant, :bytes
def initialize(variant: nil, bytes: nil)
@variant = variant
@bytes = bytes
end
def key_bytes
Base64.strict_decode64(@bytes || '')
end
def self.from_hash(hash)
new(variant: hash['variant'], bytes: hash['bytes'])
end
end
# SPHINCS+ public key.
class SphincsPublicKey
attr_accessor :variant, :bytes
def initialize(variant: nil, bytes: nil)
@variant = variant
@bytes = bytes
end
def key_bytes
Base64.strict_decode64(@bytes || '')
end
def self.from_hash(hash)
new(variant: hash['variant'], bytes: hash['bytes'])
end
end
# SPHINCS+ secret key.
class SphincsSecretKey
attr_accessor :variant, :bytes
def initialize(variant: nil, bytes: nil)
@variant = variant
@bytes = bytes
end
def key_bytes
Base64.strict_decode64(@bytes || '')
end
def self.from_hash(hash)
new(variant: hash['variant'], bytes: hash['bytes'])
end
end
# ============================================================================
# Signature Types
# ============================================================================
# Hybrid signature combining Ed25519 and Dilithium3.
class HybridSignature
attr_accessor :ed25519, :dilithium
def initialize(ed25519: nil, dilithium: nil)
@ed25519 = ed25519
@dilithium = dilithium
end
def ed25519_bytes
Base64.strict_decode64(@ed25519 || '')
end
def dilithium_bytes
Base64.strict_decode64(@dilithium || '')
end
def size
ed25519_bytes.bytesize + dilithium_bytes.bytesize
end
def to_bytes
ed25519_bytes + dilithium_bytes
end
def to_h
{ 'ed25519' => ed25519, 'dilithium' => dilithium }
end
def self.from_hash(hash)
new(ed25519: hash['ed25519'], dilithium: hash['dilithium'])
end
end
# Falcon signature.
class FalconSignature
attr_accessor :variant, :signature
def initialize(variant: nil, signature: nil)
@variant = variant
@signature = signature
end
def signature_bytes
Base64.strict_decode64(@signature || '')
end
def size
signature_bytes.bytesize
end
def self.from_hash(hash)
new(variant: hash['variant'], signature: hash['signature'])
end
end
# SPHINCS+ signature.
class SphincsSignature
attr_accessor :variant, :signature
def initialize(variant: nil, signature: nil)
@variant = variant
@signature = signature
end
def signature_bytes
Base64.strict_decode64(@signature || '')
end
def size
signature_bytes.bytesize
end
def self.from_hash(hash)
new(variant: hash['variant'], signature: hash['signature'])
end
end
# ============================================================================
# Keypair Types
# ============================================================================
# Hybrid keypair for Ed25519 + Dilithium3.
class HybridKeypair
attr_accessor :public_key, :secret_key, :addresses
def initialize(public_key: nil, secret_key: nil, addresses: {})
@public_key = public_key
@secret_key = secret_key
@addresses = addresses
end
def get_address(network)
addresses[network] || ''
end
def self.from_hash(hash)
new(
public_key: HybridPublicKey.from_hash(hash['public_key'] || {}),
secret_key: SecretKey.from_hash(hash['secret_key'] || {}),
addresses: hash['addresses'] || {}
)
end
end
# Falcon keypair.
class FalconKeypair
attr_accessor :variant, :public_key, :secret_key
def initialize(variant: nil, public_key: nil, secret_key: nil)
@variant = variant
@public_key = public_key
@secret_key = secret_key
end
def self.from_hash(hash)
new(
variant: hash['variant'],
public_key: FalconPublicKey.from_hash(hash['public_key'] || {}),
secret_key: FalconSecretKey.from_hash(hash['secret_key'] || {})
)
end
end
# SPHINCS+ keypair.
class SphincsKeypair
attr_accessor :variant, :public_key, :secret_key
def initialize(variant: nil, public_key: nil, secret_key: nil)
@variant = variant
@public_key = public_key
@secret_key = secret_key
end
def self.from_hash(hash)
new(
variant: hash['variant'],
public_key: SphincsPublicKey.from_hash(hash['public_key'] || {}),
secret_key: SphincsSecretKey.from_hash(hash['secret_key'] || {})
)
end
end
# ============================================================================
# Mnemonic Types
# ============================================================================
# BIP-39 mnemonic phrase.
class Mnemonic
attr_accessor :phrase, :words, :word_count, :entropy
def initialize(phrase: nil, words: nil, word_count: 0, entropy: nil)
@phrase = phrase
@words = words
@word_count = word_count
@entropy = entropy
end
def get_words
words || phrase&.split(' ') || []
end
def get_word_count
word_count.positive? ? word_count : get_words.size
end
def entropy_bytes
entropy ? Base64.strict_decode64(entropy) : ''
end
def self.from_hash(hash)
new(
phrase: hash['phrase'],
words: hash['words'],
word_count: hash['word_count'] || 0,
entropy: hash['entropy']
)
end
end
# Mnemonic validation result.
class MnemonicValidation
attr_accessor :valid, :error
def initialize(valid: false, error: nil)
@valid = valid
@error = error
end
def self.from_hash(hash)
new(valid: hash['valid'], error: hash['error'])
end
end
# ============================================================================
# Address Types
# ============================================================================
# Blockchain address.
class Address
attr_accessor :address, :network, :pubkey_hash
def initialize(address: nil, network: nil, pubkey_hash: nil)
@address = address
@network = network
@pubkey_hash = pubkey_hash
end
def pubkey_hash_bytes
pubkey_hash ? Base64.strict_decode64(pubkey_hash) : ''
end
def self.from_hash(hash)
new(
address: hash['address'],
network: hash['network'],
pubkey_hash: hash['pubkey_hash']
)
end
end
# ============================================================================
# Hash Types
# ============================================================================
# 256-bit hash result.
class Hash256
attr_accessor :hash
def initialize(hash: nil)
@hash = hash
end
def hex
hash
end
def bytes
[hash].pack('H*')
end
def self.from_hash(hash_data)
new(hash: hash_data['hash'])
end
end
# ============================================================================
# Error Types
# ============================================================================
# Crypto SDK exception.
class CryptoError < StandardError
attr_reader :code, :http_status
def initialize(message, code: nil, http_status: nil)
super(message)
@code = code
@http_status = http_status
end
end
end
end

View file

@ -0,0 +1,673 @@
//! Crypto SDK client implementation
use super::types::*;
use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
/// Main Synor Crypto client
pub struct SynorCrypto {
config: CryptoConfig,
client: Client,
closed: Arc<AtomicBool>,
}
impl SynorCrypto {
/// Creates a new client
pub fn new(config: CryptoConfig) -> Self {
let client = Client::builder()
.timeout(std::time::Duration::from_millis(config.timeout_ms))
.build()
.expect("Failed to create HTTP client");
Self {
config,
client,
closed: Arc::new(AtomicBool::new(false)),
}
}
/// Returns the default network
pub fn default_network(&self) -> Network {
self.config.default_network
}
/// Returns the mnemonic client
pub fn mnemonic(&self) -> MnemonicClient {
MnemonicClient { crypto: self }
}
/// Returns the keypair client
pub fn keypairs(&self) -> KeypairClient {
KeypairClient { crypto: self }
}
/// Returns the signing client
pub fn signing(&self) -> SigningClient {
SigningClient { crypto: self }
}
/// Returns the Falcon client
pub fn falcon(&self) -> FalconClient {
FalconClient { crypto: self }
}
/// Returns the SPHINCS+ client
pub fn sphincs(&self) -> SphincsClient {
SphincsClient { crypto: self }
}
/// Returns the KDF client
pub fn kdf(&self) -> KdfClient {
KdfClient { crypto: self }
}
/// Returns the hash client
pub fn hash(&self) -> HashClient {
HashClient { crypto: self }
}
/// Checks service health
pub async fn health_check(&self) -> Result<bool, CryptoError> {
#[derive(Deserialize)]
struct HealthResponse {
status: String,
}
match self.get::<HealthResponse>("/health").await {
Ok(r) => Ok(r.status == "healthy"),
Err(_) => Ok(false),
}
}
/// Closes the client
pub fn close(&self) {
self.closed.store(true, Ordering::SeqCst);
}
/// Returns true if closed
pub fn is_closed(&self) -> bool {
self.closed.load(Ordering::SeqCst)
}
async fn get<T: for<'de> Deserialize<'de>>(&self, path: &str) -> Result<T, CryptoError> {
self.check_closed()?;
let resp = self
.client
.get(format!("{}{}", self.config.endpoint, path))
.header("Authorization", format!("Bearer {}", self.config.api_key))
.header("X-SDK-Version", "rust/0.1.0")
.send()
.await
.map_err(|e| CryptoError::NetworkError(e.to_string()))?;
self.handle_response(resp).await
}
async fn post<T: for<'de> Deserialize<'de>, B: Serialize>(
&self,
path: &str,
body: &B,
) -> Result<T, CryptoError> {
self.check_closed()?;
let resp = self
.client
.post(format!("{}{}", self.config.endpoint, path))
.header("Authorization", format!("Bearer {}", self.config.api_key))
.header("Content-Type", "application/json")
.header("X-SDK-Version", "rust/0.1.0")
.json(body)
.send()
.await
.map_err(|e| CryptoError::NetworkError(e.to_string()))?;
self.handle_response(resp).await
}
async fn handle_response<T: for<'de> Deserialize<'de>>(
&self,
resp: reqwest::Response,
) -> Result<T, CryptoError> {
let status = resp.status();
let text = resp.text().await.map_err(|e| CryptoError::NetworkError(e.to_string()))?;
if !status.is_success() {
#[derive(Deserialize)]
struct ErrorResponse {
message: Option<String>,
code: Option<String>,
}
let err: ErrorResponse = serde_json::from_str(&text).unwrap_or(ErrorResponse {
message: Some(format!("HTTP {}", status)),
code: None,
});
return Err(CryptoError::ApiError {
message: err.message.unwrap_or_else(|| format!("HTTP {}", status)),
code: err.code,
});
}
serde_json::from_str(&text).map_err(|e| CryptoError::NetworkError(e.to_string()))
}
fn check_closed(&self) -> Result<(), CryptoError> {
if self.is_closed() {
return Err(CryptoError::ClientClosed);
}
Ok(())
}
}
// ============================================================================
// Mnemonic Client
// ============================================================================
/// Mnemonic operations
pub struct MnemonicClient<'a> {
crypto: &'a SynorCrypto,
}
impl<'a> MnemonicClient<'a> {
/// Generates a new random mnemonic
pub async fn generate(&self, word_count: usize) -> Result<Mnemonic, CryptoError> {
#[derive(Serialize)]
struct Request {
word_count: usize,
}
#[derive(Deserialize)]
struct Response {
phrase: String,
words: Vec<String>,
word_count: usize,
entropy: Option<String>,
}
let resp: Response = self.crypto.post("/mnemonic/generate", &Request { word_count }).await?;
Ok(Mnemonic {
phrase: resp.phrase,
words: resp.words,
word_count: resp.word_count,
entropy: resp.entropy.map(|e| BASE64.decode(e).unwrap_or_default()).unwrap_or_default(),
})
}
/// Creates a mnemonic from a phrase
pub async fn from_phrase(&self, phrase: &str) -> Result<Mnemonic, CryptoError> {
#[derive(Serialize)]
struct Request<'a> {
phrase: &'a str,
}
#[derive(Deserialize)]
struct Response {
phrase: String,
words: Vec<String>,
word_count: usize,
entropy: Option<String>,
}
let resp: Response = self.crypto.post("/mnemonic/from-phrase", &Request { phrase }).await?;
Ok(Mnemonic {
phrase: resp.phrase,
words: resp.words,
word_count: resp.word_count,
entropy: resp.entropy.map(|e| BASE64.decode(e).unwrap_or_default()).unwrap_or_default(),
})
}
/// Validates a mnemonic phrase
pub async fn validate(&self, phrase: &str) -> Result<MnemonicValidation, CryptoError> {
#[derive(Serialize)]
struct Request<'a> {
phrase: &'a str,
}
#[derive(Deserialize)]
struct Response {
valid: bool,
error: Option<String>,
}
let resp: Response = self.crypto.post("/mnemonic/validate", &Request { phrase }).await?;
Ok(MnemonicValidation {
valid: resp.valid,
error: resp.error,
})
}
/// Derives a seed from a mnemonic
pub async fn to_seed(&self, phrase: &str, passphrase: &str) -> Result<Vec<u8>, CryptoError> {
#[derive(Serialize)]
struct Request<'a> {
phrase: &'a str,
passphrase: &'a str,
}
#[derive(Deserialize)]
struct Response {
seed: String,
}
let resp: Response = self.crypto.post("/mnemonic/to-seed", &Request { phrase, passphrase }).await?;
BASE64.decode(resp.seed).map_err(|e| CryptoError::DerivationFailed(e.to_string()))
}
}
// ============================================================================
// Keypair Client
// ============================================================================
/// Keypair operations
pub struct KeypairClient<'a> {
crypto: &'a SynorCrypto,
}
impl<'a> KeypairClient<'a> {
/// Generates a new random keypair
pub async fn generate(&self) -> Result<HybridKeypair, CryptoError> {
let resp: KeypairResponse = self.crypto.post("/keypair/generate", &()).await?;
Ok(resp.into_keypair())
}
/// Creates a keypair from a mnemonic
pub async fn from_mnemonic(&self, phrase: &str, passphrase: &str) -> Result<HybridKeypair, CryptoError> {
#[derive(Serialize)]
struct Request<'a> {
phrase: &'a str,
passphrase: &'a str,
}
let resp: KeypairResponse = self.crypto.post("/keypair/from-mnemonic", &Request { phrase, passphrase }).await?;
Ok(resp.into_keypair())
}
/// Creates a keypair from a seed
pub async fn from_seed(&self, seed: &[u8]) -> Result<HybridKeypair, CryptoError> {
#[derive(Serialize)]
struct Request {
seed: String,
}
let resp: KeypairResponse = self.crypto.post("/keypair/from-seed", &Request {
seed: BASE64.encode(seed),
}).await?;
Ok(resp.into_keypair())
}
}
#[derive(Deserialize)]
struct KeypairResponse {
public_key: PublicKeyResponse,
secret_key: SecretKeyResponse,
addresses: HashMap<String, String>,
}
#[derive(Deserialize)]
struct PublicKeyResponse {
ed25519: String,
dilithium: String,
}
#[derive(Deserialize)]
struct SecretKeyResponse {
ed25519_seed: String,
master_seed: String,
}
impl KeypairResponse {
fn into_keypair(self) -> HybridKeypair {
let ed25519 = BASE64.decode(&self.public_key.ed25519).unwrap_or_default();
let dilithium = BASE64.decode(&self.public_key.dilithium).unwrap_or_default();
let ed25519_seed = BASE64.decode(&self.secret_key.ed25519_seed).unwrap_or_default();
let master_seed = BASE64.decode(&self.secret_key.master_seed).unwrap_or_default();
let mut addresses = HashMap::new();
for (k, v) in self.addresses {
if let Ok(network) = serde_json::from_str::<Network>(&format!("\"{}\"", k)) {
addresses.insert(network, v);
}
}
HybridKeypair::new(
HybridPublicKey { ed25519, dilithium },
SecretKey { ed25519_seed, master_seed },
addresses,
)
}
}
// ============================================================================
// Signing Client
// ============================================================================
/// Signing operations
pub struct SigningClient<'a> {
crypto: &'a SynorCrypto,
}
impl<'a> SigningClient<'a> {
/// Signs a message with a hybrid keypair
pub async fn sign(&self, keypair: &HybridKeypair, message: &[u8]) -> Result<HybridSignature, CryptoError> {
#[derive(Serialize)]
struct Request {
secret_key: SecretKeyRequest,
message: String,
}
#[derive(Serialize)]
struct SecretKeyRequest {
ed25519_seed: String,
master_seed: String,
}
#[derive(Deserialize)]
struct Response {
ed25519: String,
dilithium: String,
}
let resp: Response = self.crypto.post("/sign/hybrid", &Request {
secret_key: SecretKeyRequest {
ed25519_seed: BASE64.encode(&keypair.secret_key.ed25519_seed),
master_seed: BASE64.encode(&keypair.secret_key.master_seed),
},
message: BASE64.encode(message),
}).await?;
Ok(HybridSignature {
ed25519: BASE64.decode(resp.ed25519).unwrap_or_default(),
dilithium: BASE64.decode(resp.dilithium).unwrap_or_default(),
})
}
/// Verifies a hybrid signature
pub async fn verify(
&self,
public_key: &HybridPublicKey,
message: &[u8],
signature: &HybridSignature,
) -> Result<bool, CryptoError> {
#[derive(Serialize)]
struct Request {
public_key: PublicKeyRequest,
message: String,
signature: SignatureRequest,
}
#[derive(Serialize)]
struct PublicKeyRequest {
ed25519: String,
dilithium: String,
}
#[derive(Serialize)]
struct SignatureRequest {
ed25519: String,
dilithium: String,
}
#[derive(Deserialize)]
struct Response {
valid: bool,
}
let resp: Response = self.crypto.post("/sign/verify", &Request {
public_key: PublicKeyRequest {
ed25519: BASE64.encode(&public_key.ed25519),
dilithium: BASE64.encode(&public_key.dilithium),
},
message: BASE64.encode(message),
signature: SignatureRequest {
ed25519: BASE64.encode(&signature.ed25519),
dilithium: BASE64.encode(&signature.dilithium),
},
}).await?;
Ok(resp.valid)
}
}
// ============================================================================
// Falcon Client
// ============================================================================
/// Falcon operations
pub struct FalconClient<'a> {
crypto: &'a SynorCrypto,
}
impl<'a> FalconClient<'a> {
/// Generates a Falcon keypair
pub async fn generate(&self, variant: FalconVariant) -> Result<FalconKeypair, CryptoError> {
#[derive(Serialize)]
struct Request {
variant: FalconVariant,
}
#[derive(Deserialize)]
struct Response {
variant: FalconVariant,
public_key: KeyBytes,
secret_key: KeyBytes,
}
#[derive(Deserialize)]
struct KeyBytes {
bytes: String,
}
let resp: Response = self.crypto.post("/falcon/generate", &Request { variant }).await?;
Ok(FalconKeypair {
variant: resp.variant,
public_key: FalconPublicKey {
variant: resp.variant,
bytes: BASE64.decode(resp.public_key.bytes).unwrap_or_default(),
},
secret_key: FalconSecretKey {
variant: resp.variant,
bytes: BASE64.decode(resp.secret_key.bytes).unwrap_or_default(),
},
})
}
/// Signs with Falcon
pub async fn sign(&self, keypair: &FalconKeypair, message: &[u8]) -> Result<FalconSignature, CryptoError> {
#[derive(Serialize)]
struct Request {
variant: FalconVariant,
secret_key: String,
message: String,
}
#[derive(Deserialize)]
struct Response {
signature: String,
variant: FalconVariant,
}
let resp: Response = self.crypto.post("/falcon/sign", &Request {
variant: keypair.variant,
secret_key: BASE64.encode(&keypair.secret_key.bytes),
message: BASE64.encode(message),
}).await?;
Ok(FalconSignature {
variant: resp.variant,
bytes: BASE64.decode(resp.signature).unwrap_or_default(),
})
}
}
// ============================================================================
// SPHINCS+ Client
// ============================================================================
/// SPHINCS+ operations
pub struct SphincsClient<'a> {
crypto: &'a SynorCrypto,
}
impl<'a> SphincsClient<'a> {
/// Generates a SPHINCS+ keypair
pub async fn generate(&self, variant: SphincsVariant) -> Result<SphincsKeypair, CryptoError> {
#[derive(Serialize)]
struct Request {
variant: SphincsVariant,
}
#[derive(Deserialize)]
struct Response {
variant: SphincsVariant,
public_key: KeyBytes,
secret_key: KeyBytes,
}
#[derive(Deserialize)]
struct KeyBytes {
bytes: String,
}
let resp: Response = self.crypto.post("/sphincs/generate", &Request { variant }).await?;
Ok(SphincsKeypair {
variant: resp.variant,
public_key: SphincsPublicKey {
variant: resp.variant,
bytes: BASE64.decode(resp.public_key.bytes).unwrap_or_default(),
},
secret_key: SphincsSecretKey {
variant: resp.variant,
bytes: BASE64.decode(resp.secret_key.bytes).unwrap_or_default(),
},
})
}
}
// ============================================================================
// KDF Client
// ============================================================================
/// Key derivation operations
pub struct KdfClient<'a> {
crypto: &'a SynorCrypto,
}
impl<'a> KdfClient<'a> {
/// Derives a key using HKDF
pub async fn derive_key(&self, seed: &[u8], config: &DerivationConfig) -> Result<Vec<u8>, CryptoError> {
#[derive(Serialize)]
struct Request {
seed: String,
salt: Option<String>,
info: Option<String>,
output_length: usize,
}
#[derive(Deserialize)]
struct Response {
key: String,
}
let resp: Response = self.crypto.post("/kdf/hkdf", &Request {
seed: BASE64.encode(seed),
salt: config.salt.as_ref().map(|s| BASE64.encode(s)),
info: config.info.as_ref().map(|i| BASE64.encode(i)),
output_length: config.output_length,
}).await?;
BASE64.decode(resp.key).map_err(|e| CryptoError::DerivationFailed(e.to_string()))
}
/// Derives a key from a password
pub async fn derive_from_password(
&self,
password: &[u8],
config: &PasswordDerivationConfig,
) -> Result<Vec<u8>, CryptoError> {
#[derive(Serialize)]
struct Request {
password: String,
salt: String,
iterations: u32,
output_length: usize,
}
#[derive(Deserialize)]
struct Response {
key: String,
}
let resp: Response = self.crypto.post("/kdf/pbkdf2", &Request {
password: BASE64.encode(password),
salt: BASE64.encode(&config.salt),
iterations: config.iterations,
output_length: config.output_length,
}).await?;
BASE64.decode(resp.key).map_err(|e| CryptoError::DerivationFailed(e.to_string()))
}
}
// ============================================================================
// Hash Client
// ============================================================================
/// Hashing operations
pub struct HashClient<'a> {
crypto: &'a SynorCrypto,
}
impl<'a> HashClient<'a> {
/// Computes SHA3-256 hash
pub async fn sha3_256(&self, data: &[u8]) -> Result<Hash256, CryptoError> {
#[derive(Serialize)]
struct Request {
data: String,
}
#[derive(Deserialize)]
struct Response {
hash: String,
}
let resp: Response = self.crypto.post("/hash/sha3-256", &Request {
data: BASE64.encode(data),
}).await?;
let bytes = hex::decode(&resp.hash).unwrap_or_default();
Ok(Hash256 { bytes, hex: resp.hash })
}
/// Computes BLAKE3 hash
pub async fn blake3(&self, data: &[u8]) -> Result<Hash256, CryptoError> {
#[derive(Serialize)]
struct Request {
data: String,
}
#[derive(Deserialize)]
struct Response {
hash: String,
}
let resp: Response = self.crypto.post("/hash/blake3", &Request {
data: BASE64.encode(data),
}).await?;
let bytes = hex::decode(&resp.hash).unwrap_or_default();
Ok(Hash256 { bytes, hex: resp.hash })
}
}

View file

@ -0,0 +1,42 @@
//! Synor Crypto SDK for Rust
//!
//! Quantum-resistant cryptographic primitives for the Synor blockchain.
//!
//! # Features
//!
//! - Hybrid Ed25519 + Dilithium3 signatures (quantum-resistant)
//! - BIP-39 mnemonic support (12-24 words)
//! - BIP-44 hierarchical key derivation
//! - Post-quantum algorithms: Falcon, SPHINCS+
//! - Secure key derivation (HKDF, PBKDF2)
//!
//! # Example
//!
//! ```rust,no_run
//! use synor_crypto::{SynorCrypto, CryptoConfig, Network};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let config = CryptoConfig::new("your-api-key");
//! let crypto = SynorCrypto::new(config);
//!
//! // Generate a mnemonic
//! let mnemonic = crypto.mnemonic().generate(24).await?;
//! println!("Backup words: {}", mnemonic.phrase);
//!
//! // Create keypair from mnemonic
//! let keypair = crypto.keypairs().from_mnemonic(&mnemonic.phrase, "").await?;
//! let address = keypair.address(Network::Mainnet);
//!
//! // Sign a message
//! let signature = crypto.signing().sign(&keypair, b"Hello!").await?;
//!
//! Ok(())
//! }
//! ```
mod types;
mod client;
pub use types::*;
pub use client::*;

View file

@ -0,0 +1,537 @@
//! Crypto SDK types for Rust
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use thiserror::Error;
// ============================================================================
// Enumerations
// ============================================================================
/// Network type for address generation
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Network {
Mainnet,
Testnet,
Devnet,
}
impl Default for Network {
fn default() -> Self {
Network::Mainnet
}
}
/// Falcon variant selection
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum FalconVariant {
Falcon512,
Falcon1024,
}
impl Default for FalconVariant {
fn default() -> Self {
FalconVariant::Falcon512
}
}
impl FalconVariant {
/// Returns the signature size for this variant
pub const fn signature_size(&self) -> usize {
match self {
FalconVariant::Falcon512 => 690,
FalconVariant::Falcon1024 => 1330,
}
}
/// Returns the public key size for this variant
pub const fn public_key_size(&self) -> usize {
match self {
FalconVariant::Falcon512 => 897,
FalconVariant::Falcon1024 => 1793,
}
}
/// Returns the security level in bits
pub const fn security_level(&self) -> u16 {
match self {
FalconVariant::Falcon512 => 128,
FalconVariant::Falcon1024 => 256,
}
}
}
/// SPHINCS+ variant selection
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SphincsVariant {
Shake128s,
Shake192s,
Shake256s,
}
impl Default for SphincsVariant {
fn default() -> Self {
SphincsVariant::Shake128s
}
}
impl SphincsVariant {
/// Returns the signature size for this variant
pub const fn signature_size(&self) -> usize {
match self {
SphincsVariant::Shake128s => 7856,
SphincsVariant::Shake192s => 16224,
SphincsVariant::Shake256s => 29792,
}
}
/// Returns the security level in bits
pub const fn security_level(&self) -> u16 {
match self {
SphincsVariant::Shake128s => 128,
SphincsVariant::Shake192s => 192,
SphincsVariant::Shake256s => 256,
}
}
}
/// Post-quantum algorithm selection
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PqAlgorithm {
Dilithium3,
Falcon512,
Falcon1024,
Sphincs128s,
Sphincs192s,
Sphincs256s,
}
/// Algorithm family classification
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AlgorithmFamily {
Classical,
Lattice,
HashBased,
Hybrid,
}
// ============================================================================
// Configuration Types
// ============================================================================
/// Crypto SDK configuration
#[derive(Debug, Clone)]
pub struct CryptoConfig {
pub api_key: String,
pub endpoint: String,
pub timeout_ms: u64,
pub retries: u32,
pub debug: bool,
pub default_network: Network,
}
impl CryptoConfig {
/// Creates a new config with the given API key
pub fn new(api_key: impl Into<String>) -> Self {
Self {
api_key: api_key.into(),
endpoint: "https://crypto.synor.io/v1".to_string(),
timeout_ms: 30000,
retries: 3,
debug: false,
default_network: Network::Mainnet,
}
}
/// Sets the endpoint
pub fn with_endpoint(mut self, endpoint: impl Into<String>) -> Self {
self.endpoint = endpoint.into();
self
}
/// Sets the timeout
pub fn with_timeout(mut self, timeout_ms: u64) -> Self {
self.timeout_ms = timeout_ms;
self
}
}
/// Key derivation configuration
#[derive(Debug, Clone, Default)]
pub struct DerivationConfig {
pub salt: Option<Vec<u8>>,
pub info: Option<Vec<u8>>,
pub output_length: usize,
}
/// Password derivation configuration
#[derive(Debug, Clone)]
pub struct PasswordDerivationConfig {
pub salt: Vec<u8>,
pub iterations: u32,
pub output_length: usize,
}
/// BIP-44 derivation path
#[derive(Debug, Clone, Default)]
pub struct DerivationPath {
pub account: u32,
pub change: u32,
pub index: u32,
}
impl DerivationPath {
/// Synor coin type for BIP-44
pub const COIN_TYPE: u32 = 0x5359;
/// Creates a new derivation path
pub fn new(account: u32, change: u32, index: u32) -> Self {
Self { account, change, index }
}
/// Creates a path for external addresses
pub fn external(account: u32, index: u32) -> Self {
Self { account, change: 0, index }
}
/// Creates a path for internal (change) addresses
pub fn internal(account: u32, index: u32) -> Self {
Self { account, change: 1, index }
}
}
impl std::fmt::Display for DerivationPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"m/44'/{}'/{}'/{}/{}",
Self::COIN_TYPE,
self.account,
self.change,
self.index
)
}
}
// ============================================================================
// Key Types
// ============================================================================
/// Hybrid public key (Ed25519 + Dilithium3)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HybridPublicKey {
/// Ed25519 component (32 bytes)
pub ed25519: Vec<u8>,
/// Dilithium3 component (~1952 bytes)
pub dilithium: Vec<u8>,
}
impl HybridPublicKey {
/// Returns the total size in bytes
pub fn size(&self) -> usize {
self.ed25519.len() + self.dilithium.len()
}
}
/// Secret key (master seed)
#[derive(Debug, Clone)]
pub struct SecretKey {
/// Ed25519 seed (32 bytes)
pub ed25519_seed: Vec<u8>,
/// Master seed (64 bytes)
pub master_seed: Vec<u8>,
}
/// Falcon public key
#[derive(Debug, Clone)]
pub struct FalconPublicKey {
pub variant: FalconVariant,
pub bytes: Vec<u8>,
}
/// Falcon secret key
#[derive(Debug, Clone)]
pub struct FalconSecretKey {
pub variant: FalconVariant,
pub bytes: Vec<u8>,
}
/// SPHINCS+ public key
#[derive(Debug, Clone)]
pub struct SphincsPublicKey {
pub variant: SphincsVariant,
pub bytes: Vec<u8>,
}
/// SPHINCS+ secret key
#[derive(Debug, Clone)]
pub struct SphincsSecretKey {
pub variant: SphincsVariant,
pub bytes: Vec<u8>,
}
// ============================================================================
// Signature Types
// ============================================================================
/// Hybrid signature (Ed25519 + Dilithium3)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HybridSignature {
/// Ed25519 component (64 bytes)
pub ed25519: Vec<u8>,
/// Dilithium3 component (~3293 bytes)
pub dilithium: Vec<u8>,
}
impl HybridSignature {
/// Returns the total size in bytes
pub fn size(&self) -> usize {
self.ed25519.len() + self.dilithium.len()
}
/// Serializes the signature to bytes
pub fn to_bytes(&self) -> Vec<u8> {
let mut result = Vec::with_capacity(self.size());
result.extend_from_slice(&self.ed25519);
result.extend_from_slice(&self.dilithium);
result
}
/// Deserializes a signature from bytes
pub fn from_bytes(data: &[u8]) -> Result<Self, CryptoError> {
if data.len() < 64 {
return Err(CryptoError::InvalidSignature("Too short".to_string()));
}
Ok(Self {
ed25519: data[..64].to_vec(),
dilithium: data[64..].to_vec(),
})
}
}
/// Falcon signature
#[derive(Debug, Clone)]
pub struct FalconSignature {
pub variant: FalconVariant,
pub bytes: Vec<u8>,
}
/// SPHINCS+ signature
#[derive(Debug, Clone)]
pub struct SphincsSignature {
pub variant: SphincsVariant,
pub bytes: Vec<u8>,
}
// ============================================================================
// Keypair Types
// ============================================================================
/// Hybrid keypair (Ed25519 + Dilithium3)
#[derive(Debug, Clone)]
pub struct HybridKeypair {
pub public_key: HybridPublicKey,
pub secret_key: SecretKey,
addresses: HashMap<Network, String>,
}
impl HybridKeypair {
/// Returns the address for a network
pub fn address(&self, network: Network) -> Option<&str> {
self.addresses.get(&network).map(|s| s.as_str())
}
/// Creates a new keypair with addresses
pub fn new(
public_key: HybridPublicKey,
secret_key: SecretKey,
addresses: HashMap<Network, String>,
) -> Self {
Self { public_key, secret_key, addresses }
}
}
/// Falcon keypair
#[derive(Debug, Clone)]
pub struct FalconKeypair {
pub variant: FalconVariant,
pub public_key: FalconPublicKey,
pub secret_key: FalconSecretKey,
}
/// SPHINCS+ keypair
#[derive(Debug, Clone)]
pub struct SphincsKeypair {
pub variant: SphincsVariant,
pub public_key: SphincsPublicKey,
pub secret_key: SphincsSecretKey,
}
// ============================================================================
// Mnemonic Types
// ============================================================================
/// BIP-39 mnemonic phrase
#[derive(Debug, Clone)]
pub struct Mnemonic {
pub phrase: String,
pub words: Vec<String>,
pub word_count: usize,
pub entropy: Vec<u8>,
}
/// Mnemonic validation result
#[derive(Debug, Clone)]
pub struct MnemonicValidation {
pub valid: bool,
pub error: Option<String>,
}
// ============================================================================
// Address Types
// ============================================================================
/// Blockchain address
#[derive(Debug, Clone)]
pub struct Address {
pub address: String,
pub network: Network,
pub pubkey_hash: Vec<u8>,
}
// ============================================================================
// Hash Types
// ============================================================================
/// 256-bit hash
#[derive(Debug, Clone)]
pub struct Hash256 {
pub bytes: Vec<u8>,
pub hex: String,
}
impl Hash256 {
/// Creates a hash from bytes
pub fn new(bytes: Vec<u8>) -> Self {
let hex = hex::encode(&bytes);
Self { bytes, hex }
}
}
// ============================================================================
// Negotiation Types
// ============================================================================
/// Algorithm capabilities for negotiation
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AlgorithmCapabilities {
pub pq_algorithms: Vec<PqAlgorithm>,
pub classical: bool,
pub hybrid: bool,
pub preferred: Option<PqAlgorithm>,
}
/// Negotiation policy
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NegotiationPolicy {
pub min_security_level: u16,
pub prefer_compact: bool,
pub allow_classical: bool,
pub required_families: Vec<AlgorithmFamily>,
}
impl Default for NegotiationPolicy {
fn default() -> Self {
Self {
min_security_level: 128,
prefer_compact: false,
allow_classical: false,
required_families: vec![],
}
}
}
/// Negotiation result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NegotiationResult {
pub algorithm: PqAlgorithm,
pub security_level: u16,
pub family: AlgorithmFamily,
pub hybrid: bool,
}
/// Session parameters after negotiation
#[derive(Debug, Clone)]
pub struct SessionParams {
pub algorithm: PqAlgorithm,
pub session_key: Option<Vec<u8>>,
pub expires_at: Option<i64>,
}
// ============================================================================
// Error Types
// ============================================================================
/// Crypto operation error
#[derive(Debug, Error)]
pub enum CryptoError {
#[error("Invalid mnemonic: {0}")]
InvalidMnemonic(String),
#[error("Invalid key: {0}")]
InvalidKey(String),
#[error("Invalid signature: {0}")]
InvalidSignature(String),
#[error("Verification failed")]
VerificationFailed,
#[error("Derivation failed: {0}")]
DerivationFailed(String),
#[error("Algorithm mismatch")]
AlgorithmMismatch,
#[error("Negotiation failed: {0}")]
NegotiationFailed(String),
#[error("Network error: {0}")]
NetworkError(String),
#[error("API error: {message} (code: {code:?})")]
ApiError { message: String, code: Option<String> },
#[error("Client closed")]
ClientClosed,
}
// ============================================================================
// Constants
// ============================================================================
/// Ed25519 public key size
pub const ED25519_PUBLIC_KEY_SIZE: usize = 32;
/// Ed25519 secret key size
pub const ED25519_SECRET_KEY_SIZE: usize = 32;
/// Ed25519 signature size
pub const ED25519_SIGNATURE_SIZE: usize = 64;
/// Dilithium3 public key size
pub const DILITHIUM3_PUBLIC_KEY_SIZE: usize = 1952;
/// Dilithium3 signature size
pub const DILITHIUM3_SIGNATURE_SIZE: usize = 3293;
/// Hybrid signature size
pub const HYBRID_SIGNATURE_SIZE: usize = ED25519_SIGNATURE_SIZE + DILITHIUM3_SIGNATURE_SIZE;
/// BIP-44 coin type for Synor
pub const COIN_TYPE: u32 = 0x5359;
/// Minimum PBKDF2 iterations
pub const MIN_PBKDF2_ITERATIONS: u32 = 10000;
/// Minimum salt length
pub const MIN_SALT_LENGTH: usize = 8;
/// Default API endpoint
pub const DEFAULT_ENDPOINT: &str = "https://crypto.synor.io/v1";

View file

@ -0,0 +1,347 @@
import Foundation
/// Synor Crypto SDK for Swift
///
/// Quantum-resistant cryptographic primitives for the Synor blockchain.
///
/// ```swift
/// let config = CryptoConfig(apiKey: "your-api-key")
/// let crypto = SynorCrypto(config: config)
///
/// // Generate a mnemonic
/// let mnemonic = try await crypto.mnemonic.generate(wordCount: 24)
/// print("Backup words: \(mnemonic.phrase)")
///
/// // Create keypair from mnemonic
/// let keypair = try await crypto.keypairs.fromMnemonic(phrase: mnemonic.phrase, passphrase: "")
/// let address = keypair.address(for: .mainnet)
///
/// // Sign a message
/// let signature = try await crypto.signing.sign(keypair: keypair, message: "Hello!".data(using: .utf8)!)
/// ```
public class SynorCrypto {
private let config: CryptoConfig
private let session: URLSession
private let encoder: JSONEncoder
private let decoder: JSONDecoder
private var _closed = false
public let mnemonic: MnemonicClient
public let keypairs: KeypairClient
public let signing: SigningClient
public let falcon: FalconClient
public let sphincs: SphincsClient
public let kdf: KdfClient
public let hash: HashClient
public var defaultNetwork: Network { config.defaultNetwork }
public var isClosed: Bool { _closed }
public init(config: CryptoConfig) {
self.config = config
let sessionConfig = URLSessionConfiguration.default
sessionConfig.timeoutIntervalForRequest = config.timeout
self.session = URLSession(configuration: sessionConfig)
self.encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
self.decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
self.mnemonic = MnemonicClient()
self.keypairs = KeypairClient()
self.signing = SigningClient()
self.falcon = FalconClient()
self.sphincs = SphincsClient()
self.kdf = KdfClient()
self.hash = HashClient()
// Set parent references
self.mnemonic.crypto = self
self.keypairs.crypto = self
self.signing.crypto = self
self.falcon.crypto = self
self.sphincs.crypto = self
self.kdf.crypto = self
self.hash.crypto = self
}
public func healthCheck() async -> Bool {
do {
let result: [String: String] = try await get(path: "/health")
return result["status"] == "healthy"
} catch {
return false
}
}
public func getInfo() async throws -> [String: Any] {
try await get(path: "/info")
}
public func close() {
_closed = true
session.invalidateAndCancel()
}
// MARK: - Internal HTTP Methods
func get<T: Decodable>(path: String) async throws -> T {
guard !_closed else {
throw CryptoError(message: "Client has been closed", code: "CLIENT_CLOSED")
}
guard let url = URL(string: config.endpoint + path) else {
throw CryptoError(message: "Invalid URL", code: "INVALID_URL")
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("Bearer \(config.apiKey)", forHTTPHeaderField: "Authorization")
request.setValue("swift/0.1.0", forHTTPHeaderField: "X-SDK-Version")
let (data, response) = try await session.data(for: request)
return try handleResponse(data: data, response: response)
}
func post<T: Decodable>(path: String, body: [String: Any]? = nil) async throws -> T {
guard !_closed else {
throw CryptoError(message: "Client has been closed", code: "CLIENT_CLOSED")
}
guard let url = URL(string: config.endpoint + path) else {
throw CryptoError(message: "Invalid URL", code: "INVALID_URL")
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer \(config.apiKey)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("swift/0.1.0", forHTTPHeaderField: "X-SDK-Version")
if let body = body {
request.httpBody = try JSONSerialization.data(withJSONObject: body)
} else {
request.httpBody = "{}".data(using: .utf8)
}
let (data, response) = try await session.data(for: request)
return try handleResponse(data: data, response: response)
}
private func handleResponse<T: Decodable>(data: Data, response: URLResponse) throws -> T {
guard let httpResponse = response as? HTTPURLResponse else {
throw CryptoError(message: "Invalid response", code: "INVALID_RESPONSE")
}
if httpResponse.statusCode >= 400 {
if let errorDict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
let message = errorDict["message"] as? String ?? "HTTP \(httpResponse.statusCode)"
let code = errorDict["code"] as? String
throw CryptoError(message: message, code: code)
}
throw CryptoError(message: "HTTP \(httpResponse.statusCode)", code: nil)
}
return try decoder.decode(T.self, from: data)
}
// MARK: - Sub-Clients
public class MnemonicClient {
weak var crypto: SynorCrypto?
public func generate(wordCount: Int = 24) async throws -> Mnemonic {
try await crypto!.post(path: "/mnemonic/generate", body: ["word_count": wordCount])
}
public func fromPhrase(phrase: String) async throws -> Mnemonic {
try await crypto!.post(path: "/mnemonic/from-phrase", body: ["phrase": phrase])
}
public func validate(phrase: String) async throws -> MnemonicValidation {
try await crypto!.post(path: "/mnemonic/validate", body: ["phrase": phrase])
}
public func toSeed(phrase: String, passphrase: String = "") async throws -> Data {
struct SeedResponse: Decodable { let seed: String }
let result: SeedResponse = try await crypto!.post(
path: "/mnemonic/to-seed",
body: ["phrase": phrase, "passphrase": passphrase]
)
return Data(base64Encoded: result.seed) ?? Data()
}
public func suggestWords(partial: String, limit: Int = 5) async throws -> [String] {
struct SuggestResponse: Decodable { let suggestions: [String] }
let result: SuggestResponse = try await crypto!.post(
path: "/mnemonic/suggest",
body: ["partial": partial, "limit": limit]
)
return result.suggestions
}
}
public class KeypairClient {
weak var crypto: SynorCrypto?
public func generate() async throws -> HybridKeypair {
try await crypto!.post(path: "/keypair/generate")
}
public func fromMnemonic(phrase: String, passphrase: String = "") async throws -> HybridKeypair {
try await crypto!.post(
path: "/keypair/from-mnemonic",
body: ["phrase": phrase, "passphrase": passphrase]
)
}
public func fromSeed(seed: Data) async throws -> HybridKeypair {
try await crypto!.post(
path: "/keypair/from-seed",
body: ["seed": seed.base64EncodedString()]
)
}
public func getAddress(publicKey: HybridPublicKey, network: Network) async throws -> Address {
try await crypto!.post(
path: "/keypair/address",
body: ["public_key": publicKey.toDict(), "network": network.rawValue]
)
}
}
public class SigningClient {
weak var crypto: SynorCrypto?
public func sign(keypair: HybridKeypair, message: Data) async throws -> HybridSignature {
try await crypto!.post(path: "/sign/hybrid", body: [
"secret_key": keypair.secretKey.toDict(),
"message": message.base64EncodedString()
])
}
public func verify(publicKey: HybridPublicKey, message: Data, signature: HybridSignature) async throws -> Bool {
struct VerifyResponse: Decodable { let valid: Bool }
let result: VerifyResponse = try await crypto!.post(path: "/sign/verify", body: [
"public_key": publicKey.toDict(),
"message": message.base64EncodedString(),
"signature": signature.toDict()
])
return result.valid
}
public func signEd25519(secretKey: Data, message: Data) async throws -> Data {
struct SignResponse: Decodable { let signature: String }
let result: SignResponse = try await crypto!.post(path: "/sign/ed25519", body: [
"secret_key": secretKey.base64EncodedString(),
"message": message.base64EncodedString()
])
return Data(base64Encoded: result.signature) ?? Data()
}
}
public class FalconClient {
weak var crypto: SynorCrypto?
public func generate(variant: FalconVariant = .falcon512) async throws -> FalconKeypair {
try await crypto!.post(path: "/falcon/generate", body: ["variant": variant.rawValue])
}
public func sign(keypair: FalconKeypair, message: Data) async throws -> FalconSignature {
try await crypto!.post(path: "/falcon/sign", body: [
"variant": keypair.variantEnum.rawValue,
"secret_key": keypair.secretKey.keyBytes.base64EncodedString(),
"message": message.base64EncodedString()
])
}
public func verify(publicKey: Data, message: Data, signature: FalconSignature) async throws -> Bool {
struct VerifyResponse: Decodable { let valid: Bool }
let result: VerifyResponse = try await crypto!.post(path: "/falcon/verify", body: [
"variant": signature.variantEnum.rawValue,
"public_key": publicKey.base64EncodedString(),
"message": message.base64EncodedString(),
"signature": signature.signatureBytes.base64EncodedString()
])
return result.valid
}
}
public class SphincsClient {
weak var crypto: SynorCrypto?
public func generate(variant: SphincsVariant = .shake128s) async throws -> SphincsKeypair {
try await crypto!.post(path: "/sphincs/generate", body: ["variant": variant.rawValue])
}
public func sign(keypair: SphincsKeypair, message: Data) async throws -> SphincsSignature {
try await crypto!.post(path: "/sphincs/sign", body: [
"variant": keypair.variantEnum.rawValue,
"secret_key": keypair.secretKey.keyBytes.base64EncodedString(),
"message": message.base64EncodedString()
])
}
public func verify(publicKey: Data, message: Data, signature: SphincsSignature) async throws -> Bool {
struct VerifyResponse: Decodable { let valid: Bool }
let result: VerifyResponse = try await crypto!.post(path: "/sphincs/verify", body: [
"variant": signature.variantEnum.rawValue,
"public_key": publicKey.base64EncodedString(),
"message": message.base64EncodedString(),
"signature": signature.signatureBytes.base64EncodedString()
])
return result.valid
}
}
public class KdfClient {
weak var crypto: SynorCrypto?
public func deriveKey(seed: Data, config: DerivationConfig = DerivationConfig()) async throws -> Data {
var body: [String: Any] = [
"seed": seed.base64EncodedString(),
"output_length": config.outputLength
]
if let salt = config.salt {
body["salt"] = salt.base64EncodedString()
}
if let info = config.info {
body["info"] = info.base64EncodedString()
}
struct KeyResponse: Decodable { let key: String }
let result: KeyResponse = try await crypto!.post(path: "/kdf/hkdf", body: body)
return Data(base64Encoded: result.key) ?? Data()
}
public func deriveFromPassword(password: Data, config: PasswordDerivationConfig) async throws -> Data {
struct KeyResponse: Decodable { let key: String }
let result: KeyResponse = try await crypto!.post(path: "/kdf/pbkdf2", body: [
"password": password.base64EncodedString(),
"salt": config.salt.base64EncodedString(),
"iterations": config.iterations,
"output_length": config.outputLength
])
return Data(base64Encoded: result.key) ?? Data()
}
}
public class HashClient {
weak var crypto: SynorCrypto?
public func sha3_256(data: Data) async throws -> Hash256 {
try await crypto!.post(path: "/hash/sha3-256", body: ["data": data.base64EncodedString()])
}
public func blake3(data: Data) async throws -> Hash256 {
try await crypto!.post(path: "/hash/blake3", body: ["data": data.base64EncodedString()])
}
public func keccak256(data: Data) async throws -> Hash256 {
try await crypto!.post(path: "/hash/keccak256", body: ["data": data.base64EncodedString()])
}
}
}

View file

@ -0,0 +1,499 @@
import Foundation
// MARK: - Enumerations
/// Network type for the Synor blockchain.
public enum Network: String, Codable, CaseIterable {
case mainnet
case testnet
case devnet
}
/// Falcon signature variant.
public enum FalconVariant: String, Codable, CaseIterable {
case falcon512
case falcon1024
public var signatureSize: Int {
switch self {
case .falcon512: return 690
case .falcon1024: return 1330
}
}
public var publicKeySize: Int {
switch self {
case .falcon512: return 897
case .falcon1024: return 1793
}
}
public var securityLevel: Int {
switch self {
case .falcon512: return 128
case .falcon1024: return 256
}
}
}
/// SPHINCS+ signature variant.
public enum SphincsVariant: String, Codable, CaseIterable {
case shake128s
case shake192s
case shake256s
public var signatureSize: Int {
switch self {
case .shake128s: return 7856
case .shake192s: return 16224
case .shake256s: return 29792
}
}
public var securityLevel: Int {
switch self {
case .shake128s: return 128
case .shake192s: return 192
case .shake256s: return 256
}
}
}
/// Post-quantum algorithm types.
public enum PqAlgorithm: String, Codable {
case dilithium3
case falcon512
case falcon1024
case sphincs128s
case sphincs192s
case sphincs256s
}
/// Cryptographic algorithm family.
public enum AlgorithmFamily: String, Codable {
case classical
case lattice
case hashBased = "hash_based"
case hybrid
}
// MARK: - Configuration Types
/// Configuration for the Crypto SDK.
public struct CryptoConfig {
public let apiKey: String
public var endpoint: String
public var timeout: TimeInterval
public var retries: Int
public var debug: Bool
public var defaultNetwork: Network
public init(
apiKey: String,
endpoint: String = "https://crypto.synor.io/v1",
timeout: TimeInterval = 30.0,
retries: Int = 3,
debug: Bool = false,
defaultNetwork: Network = .mainnet
) {
self.apiKey = apiKey
self.endpoint = endpoint
self.timeout = timeout
self.retries = retries
self.debug = debug
self.defaultNetwork = defaultNetwork
}
}
/// Configuration for key derivation.
public struct DerivationConfig {
public var salt: Data?
public var info: Data?
public var outputLength: Int
public init(salt: Data? = nil, info: Data? = nil, outputLength: Int = 32) {
self.salt = salt
self.info = info
self.outputLength = outputLength
}
}
/// Configuration for password-based key derivation.
public struct PasswordDerivationConfig {
public let salt: Data
public var iterations: Int
public var outputLength: Int
public init(salt: Data, iterations: Int = 100000, outputLength: Int = 32) {
self.salt = salt
self.iterations = iterations
self.outputLength = outputLength
}
}
/// BIP-44 derivation path.
public struct DerivationPath: CustomStringConvertible {
public static let coinType = 0x5359
public let account: Int
public let change: Int
public let index: Int
public init(account: Int, change: Int, index: Int) {
self.account = account
self.change = change
self.index = index
}
public static func external(account: Int, index: Int) -> DerivationPath {
DerivationPath(account: account, change: 0, index: index)
}
public static func `internal`(account: Int, index: Int) -> DerivationPath {
DerivationPath(account: account, change: 1, index: index)
}
public var description: String {
"m/44'/\(Self.coinType)'/\(account)'/\(change)/\(index)"
}
public func toDict() -> [String: Int] {
["account": account, "change": change, "index": index]
}
}
// MARK: - Key Types
/// Hybrid public key combining Ed25519 and Dilithium3.
public struct HybridPublicKey: Codable {
public let ed25519: String
public let dilithium: String
public var ed25519Bytes: Data {
Data(base64Encoded: ed25519) ?? Data()
}
public var dilithiumBytes: Data {
Data(base64Encoded: dilithium) ?? Data()
}
public var size: Int {
ed25519Bytes.count + dilithiumBytes.count
}
public func toDict() -> [String: String] {
["ed25519": ed25519, "dilithium": dilithium]
}
}
/// Secret key for hybrid signatures.
public struct SecretKey: Codable {
public let ed25519Seed: String
public let masterSeed: String
enum CodingKeys: String, CodingKey {
case ed25519Seed = "ed25519_seed"
case masterSeed = "master_seed"
}
public var ed25519SeedBytes: Data {
Data(base64Encoded: ed25519Seed) ?? Data()
}
public var masterSeedBytes: Data {
Data(base64Encoded: masterSeed) ?? Data()
}
public func toDict() -> [String: String] {
["ed25519_seed": ed25519Seed, "master_seed": masterSeed]
}
}
/// Falcon public key.
public struct FalconPublicKey: Codable {
public let variant: String
public let bytes: String
public var variantEnum: FalconVariant {
FalconVariant(rawValue: variant) ?? .falcon512
}
public var keyBytes: Data {
Data(base64Encoded: bytes) ?? Data()
}
}
/// Falcon secret key.
public struct FalconSecretKey: Codable {
public let variant: String
public let bytes: String
public var variantEnum: FalconVariant {
FalconVariant(rawValue: variant) ?? .falcon512
}
public var keyBytes: Data {
Data(base64Encoded: bytes) ?? Data()
}
}
/// SPHINCS+ public key.
public struct SphincsPublicKey: Codable {
public let variant: String
public let bytes: String
public var variantEnum: SphincsVariant {
SphincsVariant(rawValue: variant) ?? .shake128s
}
public var keyBytes: Data {
Data(base64Encoded: bytes) ?? Data()
}
}
/// SPHINCS+ secret key.
public struct SphincsSecretKey: Codable {
public let variant: String
public let bytes: String
public var variantEnum: SphincsVariant {
SphincsVariant(rawValue: variant) ?? .shake128s
}
public var keyBytes: Data {
Data(base64Encoded: bytes) ?? Data()
}
}
// MARK: - Signature Types
/// Hybrid signature combining Ed25519 and Dilithium3.
public struct HybridSignature: Codable {
public let ed25519: String
public let dilithium: String
public var ed25519Bytes: Data {
Data(base64Encoded: ed25519) ?? Data()
}
public var dilithiumBytes: Data {
Data(base64Encoded: dilithium) ?? Data()
}
public var size: Int {
ed25519Bytes.count + dilithiumBytes.count
}
public var bytes: Data {
var result = Data()
result.append(ed25519Bytes)
result.append(dilithiumBytes)
return result
}
public func toDict() -> [String: String] {
["ed25519": ed25519, "dilithium": dilithium]
}
}
/// Falcon signature.
public struct FalconSignature: Codable {
public let variant: String
public let signature: String
public var variantEnum: FalconVariant {
FalconVariant(rawValue: variant) ?? .falcon512
}
public var signatureBytes: Data {
Data(base64Encoded: signature) ?? Data()
}
public var size: Int {
signatureBytes.count
}
}
/// SPHINCS+ signature.
public struct SphincsSignature: Codable {
public let variant: String
public let signature: String
public var variantEnum: SphincsVariant {
SphincsVariant(rawValue: variant) ?? .shake128s
}
public var signatureBytes: Data {
Data(base64Encoded: signature) ?? Data()
}
public var size: Int {
signatureBytes.count
}
}
// MARK: - Keypair Types
/// Hybrid keypair for Ed25519 + Dilithium3.
public struct HybridKeypair: Codable {
public let publicKey: HybridPublicKey
public let secretKey: SecretKey
public let addresses: [String: String]
enum CodingKeys: String, CodingKey {
case publicKey = "public_key"
case secretKey = "secret_key"
case addresses
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
publicKey = try container.decode(HybridPublicKey.self, forKey: .publicKey)
secretKey = try container.decode(SecretKey.self, forKey: .secretKey)
addresses = try container.decodeIfPresent([String: String].self, forKey: .addresses) ?? [:]
}
public func address(for network: Network) -> String {
addresses[network.rawValue] ?? ""
}
}
/// Falcon keypair.
public struct FalconKeypair: Codable {
public let variant: String
public let publicKey: FalconPublicKey
public let secretKey: FalconSecretKey
enum CodingKeys: String, CodingKey {
case variant
case publicKey = "public_key"
case secretKey = "secret_key"
}
public var variantEnum: FalconVariant {
FalconVariant(rawValue: variant) ?? .falcon512
}
}
/// SPHINCS+ keypair.
public struct SphincsKeypair: Codable {
public let variant: String
public let publicKey: SphincsPublicKey
public let secretKey: SphincsSecretKey
enum CodingKeys: String, CodingKey {
case variant
case publicKey = "public_key"
case secretKey = "secret_key"
}
public var variantEnum: SphincsVariant {
SphincsVariant(rawValue: variant) ?? .shake128s
}
}
// MARK: - Mnemonic Types
/// BIP-39 mnemonic phrase.
public struct Mnemonic: Codable {
public let phrase: String
public let words: [String]?
public let wordCount: Int?
public let entropy: String?
enum CodingKeys: String, CodingKey {
case phrase
case words
case wordCount = "word_count"
case entropy
}
public var wordList: [String] {
words ?? phrase.split(separator: " ").map(String.init)
}
public var count: Int {
wordCount ?? wordList.count
}
public var entropyBytes: Data {
entropy.flatMap { Data(base64Encoded: $0) } ?? Data()
}
}
/// Mnemonic validation result.
public struct MnemonicValidation: Codable {
public let valid: Bool
public let error: String?
}
// MARK: - Address Types
/// Blockchain address.
public struct Address: Codable {
public let address: String
public let network: String
public let pubkeyHash: String?
enum CodingKeys: String, CodingKey {
case address
case network
case pubkeyHash = "pubkey_hash"
}
public var networkEnum: Network {
Network(rawValue: network) ?? .mainnet
}
public var pubkeyHashBytes: Data {
pubkeyHash.flatMap { Data(base64Encoded: $0) } ?? Data()
}
}
// MARK: - Hash Types
/// 256-bit hash result.
public struct Hash256: Codable {
public let hash: String
public var hex: String { hash }
public var bytes: Data {
var result = Data()
var index = hash.startIndex
while index < hash.endIndex {
let nextIndex = hash.index(index, offsetBy: 2)
if let byte = UInt8(hash[index..<nextIndex], radix: 16) {
result.append(byte)
}
index = nextIndex
}
return result
}
}
// MARK: - Error Types
/// Crypto SDK error.
public struct CryptoError: Error, LocalizedError {
public let message: String
public let code: String?
public var errorDescription: String? { message }
}
// MARK: - Constants
/// Cryptographic constants.
public enum CryptoConstants {
public static let ed25519PublicKeySize = 32
public static let ed25519SecretKeySize = 32
public static let ed25519SignatureSize = 64
public static let dilithium3PublicKeySize = 1952
public static let dilithium3SignatureSize = 3293
public static let hybridSignatureSize = 64 + 3293
public static let coinType = 0x5359
public static let minPbkdf2Iterations = 10000
public static let minSaltLength = 8
public static let defaultEndpoint = "https://crypto.synor.io/v1"
}