diff --git a/server/src/main/kotlin/org/ccoin/utils/CryptoUtils.kt b/server/src/main/kotlin/org/ccoin/utils/CryptoUtils.kt index e69de29..d6578b2 100644 --- a/server/src/main/kotlin/org/ccoin/utils/CryptoUtils.kt +++ b/server/src/main/kotlin/org/ccoin/utils/CryptoUtils.kt @@ -0,0 +1,123 @@ +package org.ccoin.utils + +import java.security.MessageDigest +import java.security.SecureRandom +import kotlin.random.Random + +object CryptoUtils { + private val secureRandom = SecureRandom() + + // Word list for address generation + private val words = listOf( + "phoenix", "dragon", "tiger", "eagle", "wolf", "lion", "bear", "shark", + "falcon", "raven", "cobra", "viper", "panther", "jaguar", "leopard", "cheetah", + "thunder", "lightning", "storm", "blizzard", "tornado", "hurricane", "cyclone", "tempest", + "crystal", "diamond", "emerald", "ruby", "sapphire", "topaz", "amethyst", "opal", + "shadow", "ghost", "phantom", "spirit", "wraith", "specter", "demon", "angel", + "fire", "ice", "earth", "wind", "water", "metal", "wood", "void", + "star", "moon", "sun", "comet", "meteor", "galaxy", "nebula", "cosmos", + "blade", "sword", "arrow", "spear", "shield", "armor", "crown", "throne", + "mountain", "ocean", "forest", "desert", "valley", "river", "lake", "cave", + "knight", "warrior", "mage", "archer", "rogue", "paladin", "wizard", "sage" + ) + + /** + * Generates a wallet address in format: random_word:random_6_digits + * Example: "phoenix:123456", "dragon:654321" + */ + fun generateWalletAddress(): String { + val randomWord = words[secureRandom.nextInt(words.size)] + val randomDigits = String.format("%06d", secureRandom.nextInt(1000000)) + return "$randomWord:$randomDigits" + } + + /** Validates if an address follows the correct format */ + fun isValidAddress(address: String): Boolean { + val parts = address.split(":") + if (parts.size != 2) return false + + val word = parts[0] + val digits = parts[1] + + return word.isNotEmpty() && + word.all { it.isLetter() } && + digits.length == 6 && + digits.all { it.isDigit() } + } + + /** Generates SHA-256 hash of input string */ + fun sha256(input: String): String { + return MessageDigest.getInstance("SHA-256") + .digest(input.toByteArray()) + .joinToString("") { "%02x".format(it) } + } + + /** Generates a transaction hash */ + fun generateTransactionHash( + fromAddress: String?, + toAddress: String, + amount: Double, + timestamp: Long, + nonce: Long = secureRandom.nextLong() + ): String { + val input = "${fromAddress ?: "genesis"}:$toAddress:$amount:$timestamp:$nonce" + return sha256(input) + } + + /** Generates a block hash */ + fun generateBlockHash( + previousHash: String, + merkleRoot: String, + timestamp: Long, + difficulty: Int, + nonce: Long + ): String { + val input = "$previousHash:$merkleRoot:$timestamp:$difficulty:$nonce" + return sha256(input) + } + + /** Validates if a hash meets the mining difficulty requirement */ + fun isValidHash(hash: String, difficulty: Int): Boolean { + val target = "0".repeat(difficulty) + return hash.startsWith(target) + } + + /** Generates a mining job id */ + fun generateJobId(): String = sha256("job:${System.currentTimeMillis()}:${secureRandom.nextLong()}").take(16) + + /** Calculates a merkle root from transaction hashes */ + fun calculateMerkleRoot(transactionHashes: List): String { + if (transactionHashes.isEmpty()) { + return sha256("empty") + } + + if (transactionHashes.size == 1) { + return transactionHashes[0] + } + + var hashes = transactionHashes.toMutableList() + + while (hashes.size > 1) { + val newHashes = mutableListOf() + + for (i in hashes.indices step 2) { + val left = hashes[i] + val right = if (i + 1 < hashes.size) hashes[i + 1] else left + newHashes.add(sha256("$left:$right")) + } + + hashes = newHashes + } + + return hashes[0] + } + + /** Generates a random nonce for mining */ + fun generateNonce(): Long = secureRandom.nextLong() + + /** Validates transaction hash format */ + fun isValidTransactionHash(hash: String): Boolean = hash.length == 64 && hash.all { it.isDigit() || it.lowercaseChar() in 'a'..'f' } + + /** Validates block has format */ + fun isValidBlockHash(hash: String): Boolean = hash.length == 64 && hash.all { it.isDigit() || it.lowercaseChar() in 'a'..'f' } +}