|
|
@ -5,47 +5,43 @@ private extension UInt64 {
|
|
|
|
init(_ decimal: Decimal) {
|
|
|
|
init(_ decimal: Decimal) {
|
|
|
|
self.init(truncating: decimal as NSDecimalNumber)
|
|
|
|
self.init(truncating: decimal as NSDecimalNumber)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// UInt8 Array specific stuff we need
|
|
|
|
|
|
|
|
private extension Array where Element == UInt8 {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Convert a UInt64 into an array of size 8
|
|
|
|
// Convert a UInt8 array to a UInt64
|
|
|
|
init(_ uint64: UInt64) {
|
|
|
|
init(_ bytes: [UInt8]) {
|
|
|
|
let array = stride(from: 0, to: 64, by: 8).reversed().map {
|
|
|
|
precondition(bytes.count <= MemoryLayout<UInt64>.size)
|
|
|
|
UInt8(uint64 >> $0 & 0x000000FF)
|
|
|
|
var value: UInt64 = 0
|
|
|
|
|
|
|
|
for byte in bytes {
|
|
|
|
|
|
|
|
value <<= 8
|
|
|
|
|
|
|
|
value |= UInt64(byte)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.init(array)
|
|
|
|
self.init(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static func > (lhs: [UInt8], rhs: [UInt8]) -> Bool {
|
|
|
|
private extension MutableCollection where Element == UInt8, Index == Int {
|
|
|
|
guard lhs.count == rhs.count else { return false }
|
|
|
|
|
|
|
|
guard let (lhsElement, rhsElement) = zip(lhs, rhs).first(where: { $0 != $1 }) else { return false }
|
|
|
|
|
|
|
|
return lhsElement > rhsElement
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Increment the UInt8 array by a given amount
|
|
|
|
/// Increment every element by the given amount
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// - Parameter amount: The amount to increment by
|
|
|
|
/// - Parameter amount: The amount to increment by
|
|
|
|
/// - Returns: The incrememnted array
|
|
|
|
/// - Returns: The incremented collection
|
|
|
|
func increment(by amount: Int) -> [UInt8] {
|
|
|
|
func increment(by amount: Int) -> Self {
|
|
|
|
var newNonce = self
|
|
|
|
var result = self
|
|
|
|
var increment = amount
|
|
|
|
var increment = amount
|
|
|
|
for i in (0..<newNonce.count).reversed() {
|
|
|
|
for i in (0..<result.count).reversed() {
|
|
|
|
guard increment > 0 else { break }
|
|
|
|
guard increment > 0 else { break }
|
|
|
|
let sum = Int(newNonce[i]) + increment
|
|
|
|
let sum = Int(result[i]) + increment
|
|
|
|
newNonce[i] = UInt8(sum % 256)
|
|
|
|
result[i] = UInt8(sum % 256)
|
|
|
|
increment = sum / 256
|
|
|
|
increment = sum / 256
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return newNonce
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* The main logic which handles proof of work.
|
|
|
|
* The main proof of work logic.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* This was copied from the messenger desktop.
|
|
|
|
* This was copied from the desktop messenger.
|
|
|
|
* Ref: libloki/proof-of-work.js
|
|
|
|
* Ref: libloki/proof-of-work.js
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public enum ProofOfWork {
|
|
|
|
public enum ProofOfWork {
|
|
|
|
|
|
|
|
|
|
|
@ -59,7 +55,7 @@ public enum ProofOfWork {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
|
|
struct Configuration {
|
|
|
|
public struct Configuration {
|
|
|
|
var pubKey: String
|
|
|
|
var pubKey: String
|
|
|
|
var data: String
|
|
|
|
var data: String
|
|
|
|
var timestamp: Date
|
|
|
|
var timestamp: Date
|
|
|
@ -71,21 +67,27 @@ public enum ProofOfWork {
|
|
|
|
let payloadString = timestampString + ttlString + pubKey + data
|
|
|
|
let payloadString = timestampString + ttlString + pubKey + data
|
|
|
|
return payloadString.bytes
|
|
|
|
return payloadString.bytes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public init(pubKey: String, data: String, timestamp: Date, ttl: Int) {
|
|
|
|
|
|
|
|
self.pubKey = pubKey
|
|
|
|
|
|
|
|
self.data = data
|
|
|
|
|
|
|
|
self.timestamp = timestamp
|
|
|
|
|
|
|
|
self.ttl = ttl
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Calculate a proof of work for the given configuration
|
|
|
|
/// Calculate a proof of work with the given configuration
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// Ref: https://bitmessage.org/wiki/Proof_of_work
|
|
|
|
/// Ref: https://bitmessage.org/wiki/Proof_of_work
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// - Parameter config: The configuration data
|
|
|
|
/// - Parameter config: The configuration
|
|
|
|
/// - Returns: A nonce string or nil if it failed
|
|
|
|
/// - Returns: A nonce string or nil if it failed
|
|
|
|
static func calculate(with config: Configuration) -> String? {
|
|
|
|
public static func calculate(with config: Configuration) -> String? {
|
|
|
|
let payload = config.payload
|
|
|
|
let payload = config.payload
|
|
|
|
let target = calcTarget(ttl: config.ttl, payloadLength: payload.count, nonceTrials: nonceTrialCount)
|
|
|
|
let target = calcTarget(ttl: config.ttl, payloadLength: payload.count, nonceTrials: nonceTrialCount)
|
|
|
|
|
|
|
|
|
|
|
|
// Start with most the max value we can
|
|
|
|
// Start with the max value
|
|
|
|
var trialValue = [UInt8](repeating: UInt8.max, count: nonceLength)
|
|
|
|
var trialValue = UInt64.max
|
|
|
|
|
|
|
|
|
|
|
|
let initialHash = payload.sha512()
|
|
|
|
let initialHash = payload.sha512()
|
|
|
|
var nonce = [UInt8](repeating: 0, count: nonceLength)
|
|
|
|
var nonce = [UInt8](repeating: 0, count: nonceLength)
|
|
|
@ -93,17 +95,18 @@ public enum ProofOfWork {
|
|
|
|
while trialValue > target {
|
|
|
|
while trialValue > target {
|
|
|
|
nonce = nonce.increment(by: 1)
|
|
|
|
nonce = nonce.increment(by: 1)
|
|
|
|
|
|
|
|
|
|
|
|
// This is different to the bitmessage pow
|
|
|
|
// This is different to the bitmessage POW
|
|
|
|
// resultHash = hash(nonce + hash(data)) ==> hash(nonce + initialHash)
|
|
|
|
// resultHash = hash(nonce + hash(data)) ==> hash(nonce + initialHash)
|
|
|
|
let resultHash = (nonce + initialHash).sha512()
|
|
|
|
let resultHash = (nonce + initialHash).sha512()
|
|
|
|
trialValue = Array(resultHash[0..<8])
|
|
|
|
let trialValueArray = Array(resultHash[0..<8])
|
|
|
|
|
|
|
|
trialValue = UInt64(trialValueArray)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nonce.toBase64()
|
|
|
|
return nonce.toBase64()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Calculate the UInt8 target we need to reach
|
|
|
|
/// Calculate the target we need to reach
|
|
|
|
private static func calcTarget(ttl: Int, payloadLength: Int, nonceTrials: Int) -> [UInt8] {
|
|
|
|
private static func calcTarget(ttl: Int, payloadLength: Int, nonceTrials: Int) -> UInt64 {
|
|
|
|
let two16 = UInt64(pow(2, 16) - 1)
|
|
|
|
let two16 = UInt64(pow(2, 16) - 1)
|
|
|
|
let two64 = UInt64(pow(2, 64) - 1)
|
|
|
|
let two64 = UInt64(pow(2, 64) - 1)
|
|
|
|
|
|
|
|
|
|
|
@ -118,8 +121,7 @@ public enum ProofOfWork {
|
|
|
|
let innerFrac = ttlMult / two16
|
|
|
|
let innerFrac = ttlMult / two16
|
|
|
|
let lenPlusInnerFrac = totalLength + innerFrac
|
|
|
|
let lenPlusInnerFrac = totalLength + innerFrac
|
|
|
|
let denominator = UInt64(nonceTrials) * lenPlusInnerFrac
|
|
|
|
let denominator = UInt64(nonceTrials) * lenPlusInnerFrac
|
|
|
|
let targetNum = two64 / denominator
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return [UInt8](targetNum)
|
|
|
|
return two64 / denominator
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|