Skip to content

Commit f72593f

Browse files
committed
use Swift Crypto for bitcoin hash testing instead of CryptoKit
1 parent 6f8bcdd commit f72593f

File tree

14 files changed

+2602
-1914
lines changed

14 files changed

+2602
-1914
lines changed

.github/workflows/swift.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444
tar xvvf swift-5.6-RELEASE-ubuntu20.04.tar.gz
4545
env:
4646
EXPECTED_SWIFT_SHASUM: 3f0d926bfc08eea00a69b1d992f2ab5e08155d97476096a3ef959fe7c4cbd58b
47-
- name: Install native Rust toolchain, Valgrind, and build utilitis
47+
- name: Install native Rust toolchain, Valgrind, and build utilities
4848
run: |
4949
sudo apt-get update
5050
sudo apt-get -y dist-upgrade

ci/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#FROM ubuntu:20.04
2-
FROM swift:bionic
2+
FROM swift:5.6-focal
33

44
RUN apt-get -y update
55
RUN apt-get -y dist-upgrade

ci/LDKSwift/Package.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ let package = Package(
1212
targets: ["LDKSwift"]),
1313
// .library(name: "LDKSwift", type: .dynamic, targets: ["LDKSwift"])
1414
],
15-
dependencies: [],
15+
dependencies: [
16+
.package(url: "https://github.com/apple/swift-crypto.git", "1.0.0" ..< "3.0.0")
17+
],
1618
targets: [
1719
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
1820
// Targets can depend on other targets in this package, and on products in packages this package depends on.
@@ -50,7 +52,11 @@ let package = Package(
5052
]),
5153
.testTarget(
5254
name: "LDKSwiftTests",
53-
dependencies: ["LDKSwift", "LDKHeaders"],
55+
dependencies: [
56+
"LDKSwift",
57+
"LDKHeaders",
58+
.product(name: "Crypto", package: "swift-crypto")
59+
],
5460
path: nil,
5561
exclude: [],
5662
// exclude: ["SampleTest.swift"],

ci/LDKSwift/Tests/LDKSwiftTests/HumanObjectPeerTestInstance.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,9 @@ public class HumanObjectPeerTestInstance {
282282
// self.constructor = ChannelManagerConstructor(network: LDKNetwork_Bitcoin, config: UserConfig(), current_blockchain_tip_hash: [UInt8](repeating: 0, count: 32), current_blockchain_tip_height: 0, keys_interface: self.keysInterface, fee_estimator: self.feeEstimator, chain_monitor: self.chainMonitor!, net_graph: nil, tx_broadcaster: self.txBroadcaster, logger: self.logger)
283283

284284
let scoringParams = ProbabilisticScoringParameters()
285-
let probabalisticScorer = ProbabilisticScorer(params: scoringParams.danglingClone(), network_graph: graph)
285+
let probabalisticScorer = ProbabilisticScorer(params: scoringParams, network_graph: graph)
286286
let score = probabalisticScorer.as_Score()
287-
let multiThreadedScorer = MultiThreadedLockableScore(score: score.dangle())
287+
let multiThreadedScorer = MultiThreadedLockableScore(score: score)
288288

289289
self.constructor?.chain_sync_completed(persister: TestChannelManagerPersister(master: self), scorer: multiThreadedScorer)
290290
self.channelManager = self.constructor!.channelManager
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
//
2+
// BTCBlock.swift
3+
// DirectBindingsApp
4+
//
5+
// Created by Arik Sosman on 3/28/22.
6+
//
7+
8+
import LDKSwift
9+
import LDKHeaders
10+
11+
/// serialization:
12+
/// 4 bytes: 0xD9B4BEF9
13+
/// 4 bytes: block size (remaining byte count)
14+
/// 80 bytes: block header
15+
/// VarInt (1-9 bytes): transaction count
16+
/// transactions
17+
18+
class BTCBlock: Equatable {
19+
20+
var version: UInt32 = 2
21+
var previousBlockHash: [UInt8] = []
22+
var merkleRoot: [UInt8]?
23+
var timestamp: UInt32 = 0
24+
var difficultyTarget: UInt32 = 0
25+
var nonce: UInt32 = 0
26+
27+
// each transaction is a uint8 array
28+
var transactions: [BTCTransaction] = []
29+
30+
func calculateMerkleRoot() -> [UInt8] {
31+
// TODO: merkleize the transactions
32+
if let merkleRoot = self.merkleRoot {
33+
return merkleRoot
34+
}
35+
return [UInt8](repeating: 0, count: 32)
36+
}
37+
38+
func calculateHeader() -> [UInt8] {
39+
var header = [UInt8]()
40+
41+
do {
42+
let versionBytes = withUnsafeBytes(of: self.version.littleEndian) { bytes in
43+
Array(bytes)
44+
}
45+
assert(versionBytes.count == 4)
46+
header.append(contentsOf: versionBytes)
47+
}
48+
49+
do {
50+
assert(self.previousBlockHash.count == 32)
51+
header.append(contentsOf: self.previousBlockHash)
52+
}
53+
54+
do {
55+
let merkleRoot = self.calculateMerkleRoot()
56+
assert(merkleRoot.count == 32)
57+
header.append(contentsOf: merkleRoot)
58+
}
59+
60+
do {
61+
let timestampBytes = withUnsafeBytes(of: self.timestamp.littleEndian) { bytes in
62+
Array(bytes)
63+
}
64+
assert(timestampBytes.count == 4)
65+
header.append(contentsOf: timestampBytes)
66+
}
67+
68+
do{
69+
let difficultyTargetBytes = withUnsafeBytes(of: self.difficultyTarget.littleEndian) { bytes in
70+
Array(bytes)
71+
}
72+
assert(difficultyTargetBytes.count == 4)
73+
header.append(contentsOf: difficultyTargetBytes)
74+
}
75+
76+
do {
77+
let nonceBytes = withUnsafeBytes(of: self.nonce.littleEndian) { bytes in
78+
Array(bytes)
79+
}
80+
assert(nonceBytes.count == 4)
81+
header.append(contentsOf: nonceBytes)
82+
}
83+
84+
assert(header.count == 80)
85+
return header
86+
}
87+
88+
/// The double sha256 hash of the block header (note: not the entire block)
89+
/// In a well-mined block, the zeroes should be trailing, as this hash is little-endian-equivalent
90+
func calculateHash() -> [UInt8] {
91+
let blockHeader = self.calculateHeader()
92+
return BTCHashing.doubleSha256(blockHeader)
93+
}
94+
95+
func serialize() -> [UInt8] {
96+
97+
var block = [UInt8]()
98+
99+
// apparently, this only needs to be appended when it's actually part of a block
100+
/*
101+
do {
102+
let magicNumber: UInt32 = 4190024921
103+
let magicNumberBytes = withUnsafeBytes(of: magicNumber.littleEndian) { bytes in
104+
Array(bytes)
105+
}
106+
assert(magicNumberBytes.count == 4)
107+
assert(magicNumberBytes == [0xf9, 0xbe, 0xb4, 0xd9])
108+
109+
block.append(contentsOf: magicNumberBytes)
110+
}
111+
*/
112+
113+
let blockHeader = self.calculateHeader()
114+
let transactionCounter = BTCVarInt(UInt64(self.transactions.count)).serialize()
115+
let transactionData = self.transactions.reduce(into: [UInt8]()) { partialResult, currentValue in
116+
return partialResult.append(contentsOf: currentValue.serialize())
117+
}
118+
119+
/*
120+
do {
121+
let blockSize = blockHeader.count + transactionCounter.count + transactionData.count
122+
let blockSizeBytes = withUnsafeBytes(of: UInt32(blockSize).littleEndian) { bytes in
123+
Array(bytes)
124+
}
125+
assert(blockSizeBytes.count == 4)
126+
block.append(contentsOf: blockSizeBytes)
127+
}
128+
*/
129+
130+
block.append(contentsOf: blockHeader)
131+
block.append(contentsOf: transactionCounter)
132+
block.append(contentsOf: transactionData)
133+
134+
return block
135+
}
136+
137+
static func == (lhs: BTCBlock, rhs: BTCBlock) -> Bool {
138+
return lhs.calculateHash() == rhs.calculateHash()
139+
}
140+
141+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// BTCHashing.swift
3+
// DirectBindingsAppTests
4+
//
5+
// Created by Arik Sosman on 3/29/22.
6+
//
7+
8+
import LDKSwift
9+
import LDKHeaders
10+
import Crypto
11+
12+
class BTCHashing {
13+
14+
public static let SHA_ZERO_HASH = [UInt8](repeating: 0, count: 32)
15+
public static let RIPEMD_ZERO_HASH = [UInt8](repeating: 0, count: 20)
16+
17+
private static func sha256(_ input: [UInt8]) -> [UInt8] {
18+
let hash = Crypto.SHA256.hash(data: input)
19+
let bytes = Array(hash)
20+
assert(bytes.count == 32)
21+
return bytes
22+
}
23+
24+
static func doubleSha256(_ input: [UInt8]) -> [UInt8] {
25+
return sha256(sha256(input))
26+
}
27+
28+
}
29+

0 commit comments

Comments
 (0)