session-ios/SessionMessagingKit/Utilities/ProofOfWork.swift

37 lines
1.5 KiB
Swift

import SessionSnodeKit
import SessionUtilitiesKit
enum ProofOfWork {
/// A modified version of [Bitmessage's Proof of Work Implementation](https://bitmessage.org/wiki/Proof_of_work).
static func calculate(ttl: UInt64, publicKey: String, data: String) -> (timestamp: UInt64, base64EncodedNonce: String)? {
let nonceSize = MemoryLayout<UInt64>.size
// Get millisecond timestamp
let timestamp = NSDate.millisecondTimestamp()
// Construct payload
let payloadAsString = String(timestamp) + String(ttl) + publicKey + data
let payload = payloadAsString.bytes
// Calculate target
let numerator = UInt64.max
let difficulty = UInt64(1)
let totalSize = UInt64(payload.count + nonceSize)
let ttlInSeconds = ttl / 1000
let denominator = difficulty * (totalSize + (ttlInSeconds * totalSize) / UInt64(UInt16.max))
let target = numerator / denominator
// Calculate proof of work
var value = UInt64.max
let payloadHash = payload.sha512()
var nonce = UInt64(0)
while value > target {
nonce = nonce &+ 1
let hash = (nonce.bigEndianBytes + payloadHash).sha512()
guard let newValue = UInt64(fromBigEndianBytes: [UInt8](hash[0..<nonceSize])) else { return nil }
value = newValue
}
// Encode as base 64
let base64EncodedNonce = nonce.bigEndianBytes.toBase64()!
// Return
return (timestamp, base64EncodedNonce)
}
}