• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bernardladenthin / BitcoinAddressFinder / #307

26 Apr 2025 08:18PM UTC coverage: 68.832% (+0.4%) from 68.475%
#307

push

bernardladenthin
Rewrite OpenCL result parsing (X/Y split), add clean shutdown, optimize runtime key validation

16 of 29 new or added lines in 5 files covered. (55.17%)

1 existing line in 1 file now uncovered.

1208 of 1755 relevant lines covered (68.83%)

0.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/main/java/net/ladenthin/bitcoinaddressfinder/OpenClTask.java
1
// @formatter:off
2
/**
3
 * Copyright 2020 Bernard Ladenthin bernard.ladenthin@gmail.com
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *    http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
// @formatter:on
19
package net.ladenthin.bitcoinaddressfinder;
20

21
import com.google.common.annotations.VisibleForTesting;
22
import java.math.BigInteger;
23
import java.nio.ByteBuffer;
24
import net.ladenthin.bitcoinaddressfinder.configuration.CProducer;
25
import static org.jocl.CL.CL_MEM_READ_ONLY;
26
import static org.jocl.CL.CL_MEM_USE_HOST_PTR;
27
import static org.jocl.CL.CL_MEM_WRITE_ONLY;
28
import static org.jocl.CL.CL_TRUE;
29
import static org.jocl.CL.clCreateBuffer;
30
import static org.jocl.CL.clEnqueueNDRangeKernel;
31
import static org.jocl.CL.clEnqueueReadBuffer;
32
import static org.jocl.CL.clEnqueueWriteBuffer;
33
import static org.jocl.CL.clFinish;
34
import static org.jocl.CL.clReleaseMemObject;
35
import static org.jocl.CL.clSetKernelArg;
36
import org.jocl.Pointer;
37
import org.jocl.Sizeof;
38
import org.jocl.cl_command_queue;
39
import org.jocl.cl_context;
40
import org.jocl.cl_kernel;
41
import org.jocl.cl_mem;
42
import org.slf4j.Logger;
43
import org.slf4j.LoggerFactory;
44

45
public class OpenClTask {
46

47
    protected Logger logger = LoggerFactory.getLogger(this.getClass());
×
48
    
49
    /**
50
     * I din't know which is better.
51
     */
52
    private static final boolean USE_HOST_PTR = false;
53
    
54
    private final CProducer cProducer;
55

56
    private final cl_context context;
57
    private final ByteBuffer srcByteBuffer;
58
    private final Pointer srcPointer;
59

60
    private final cl_mem srcMem;
61
    private final BitHelper bitHelper;
62
    private final ByteBufferUtility byteBufferUtility;
63
    private final BigInteger maxPrivateKeyForBatchSize;
64

65
    // Only available after init
66
    public OpenClTask(cl_context context, CProducer cProducer, BitHelper bitHelper, ByteBufferUtility byteBufferUtility) {
×
67
        this.context = context;
×
68
        this.cProducer = cProducer;
×
69
        this.bitHelper = bitHelper;
×
70
        this.byteBufferUtility = byteBufferUtility;
×
71

72
        int srcSizeInBytes = getSrcSizeInBytes();
×
73
        maxPrivateKeyForBatchSize = KeyUtility.getMaxPrivateKeyForBatchSize(cProducer.batchSizeInBits);
×
74
        srcByteBuffer = ByteBuffer.allocateDirect(srcSizeInBytes);
×
75
        srcPointer = Pointer.to(srcByteBuffer);
×
76
        srcMem = clCreateBuffer(
×
77
                context,
78
                CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,
79
                srcSizeInBytes,
80
                srcPointer,
81
                null
82
        );
83
    }
×
84

85
    public int getSrcSizeInBytes() {
86
        return PublicKeyBytes.PRIVATE_KEY_MAX_NUM_BYTES;
×
87
    }
88

89
    public long getDstSizeInBytes() {
90
        return (long) PublicKeyBytes.TWO_COORDINATES_NUM_BYTES * bitHelper.convertBitsToSize(cProducer.batchSizeInBits);
×
91
    }
92

93
    public void setSrcPrivateKeyChunk(BigInteger privateKeyBase) {
94
        if (KeyUtility.isInvalidWithBatchSize(privateKeyBase, maxPrivateKeyForBatchSize)) {
×
95
            throw new PrivateKeyTooLargeException(privateKeyBase, maxPrivateKeyForBatchSize, cProducer.batchSizeInBits);
×
96
        }
97

98
        byte[] byteArray = byteBufferUtility.bigIntegerToBytes(privateKeyBase);
×
99
        // MSB to LSB: From Java to OpenCL
NEW
100
        byteBufferUtility.reverse(byteArray);
×
NEW
101
        byteBufferUtility.putToByteBuffer(srcByteBuffer, byteArray);
×
UNCOV
102
    }
×
103
    
104
    @VisibleForTesting
105
    public ByteBuffer getSrcByteBuffer() {
106
        return srcByteBuffer;
×
107
    }
108

109
    public ByteBuffer executeKernel(cl_kernel kernel, cl_command_queue commandQueue) {
110
        final long dstSizeInBytes = getDstSizeInBytes();
×
111
        // allocate a new dst buffer that a clone afterwards is not necessary
112
        final ByteBuffer dstByteBuffer = ByteBuffer.allocateDirect(ByteBufferUtility.ensureByteBufferCapacityFitsInt(dstSizeInBytes));
×
113
        final Pointer dstPointer = Pointer.to(dstByteBuffer);
×
114
        final cl_mem dstMem;
115
        if (USE_HOST_PTR) {
116
            dstMem = clCreateBuffer(context,
117
                    CL_MEM_USE_HOST_PTR, dstSizeInBytes,
118
                    dstPointer,
119
                    null
120
            );
121
        } else {
122
            dstMem = clCreateBuffer(context,
×
123
                    CL_MEM_WRITE_ONLY, dstSizeInBytes,
124
                    null,
125
                    null
126
            );
127
        }
128

129
        // Set the arguments for the kernel
130
        clSetKernelArg(kernel, 0, Sizeof.cl_mem, Pointer.to(dstMem));
×
131
        clSetKernelArg(kernel, 1, Sizeof.cl_mem, Pointer.to(srcMem));
×
132

133
        // Set the work-item dimensions
134
        long global_work_size[] = new long[]{bitHelper.convertBitsToSize(cProducer.batchSizeInBits)};
×
135
        long localWorkSize[] = null; // new long[]{1}; // enabling the system to choose the work-group size.
×
136
        int workDim = 1;
×
137

138
        {
139
            // write src buffer
140
            clEnqueueWriteBuffer(
×
141
                    commandQueue,
142
                    srcMem,
143
                    CL_TRUE,
144
                    0,
145
                    getSrcSizeInBytes(),
×
146
                    srcPointer,
147
                    0,
148
                    null,
149
                    null
150
            );
151
            clFinish(commandQueue);
×
152
        }
153
        {
154
            // execute the kernel
155
            long beforeExecute = System.currentTimeMillis();
×
156
            clEnqueueNDRangeKernel(
×
157
                    commandQueue,
158
                    kernel,
159
                    workDim,
160
                    null,
161
                    global_work_size,
162
                    localWorkSize,
163
                    0,
164
                    null,
165
                    null
166
            );
167
            clFinish(commandQueue);
×
168

169
            long afterExecute = System.currentTimeMillis();
×
170
            
171
            if (logger.isTraceEnabled()) {
×
172
                logger.trace("Executed OpenCL kernel in " + (afterExecute - beforeExecute) + "ms");
×
173
            }
174
        }
175
        {
176
            // read the dst buffer
177
            long beforeRead = System.currentTimeMillis();
×
178

179
            clEnqueueReadBuffer(commandQueue,
×
180
                    dstMem,
181
                    CL_TRUE,
182
                    0,
183
                    dstSizeInBytes,
184
                    dstPointer,
185
                    0,
186
                    null,
187
                    null
188
            );
189
            clFinish(commandQueue);
×
190
            clReleaseMemObject(dstMem);
×
191

192
            long afterRead = System.currentTimeMillis();
×
193
            if (logger.isTraceEnabled()) {
×
194
                logger.trace("Read OpenCL data "+((dstSizeInBytes / 1024) / 1024) + "Mb in " + (afterRead - beforeRead) + "ms");
×
195
            }
196
        }
197
        return dstByteBuffer;
×
198
    }
199

200
    public void releaseCl() {
201
        clReleaseMemObject(srcMem);
×
202
    }
×
203

204
    /**
205
     * https://stackoverflow.com/questions/3366925/deep-copy-duplicate-of-javas-bytebuffer/4074089
206
     */
207
    private static ByteBuffer cloneByteBuffer(final ByteBuffer original) {
208
        // Create clone with same capacity as original.
209
        final ByteBuffer clone = (original.isDirect())
×
210
                ? ByteBuffer.allocateDirect(original.capacity())
×
211
                : ByteBuffer.allocate(original.capacity());
×
212

213
        // Create a read-only copy of the original.
214
        // This allows reading from the original without modifying it.
215
        final ByteBuffer readOnlyCopy = original.asReadOnlyBuffer();
×
216

217
        // Flip and read from the original.
218
        readOnlyCopy.flip();
×
219
        clone.put(readOnlyCopy);
×
220

221
        return clone;
×
222
    }
223

224
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc