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

bernardladenthin / BitcoinAddressFinder / #305

19 Apr 2025 11:43PM UTC coverage: 68.442% (+0.9%) from 67.58%
#305

push

bernardladenthin
Refactor private key validation and serialization; extract logic to KeyUtility and ByteBufferUtility, improve tests

51 of 65 new or added lines in 9 files covered. (78.46%)

2 existing lines in 2 files now uncovered.

1195 of 1746 relevant lines covered (68.44%)

0.68 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
NEW
66
    public OpenClTask(cl_context context, CProducer cProducer, BitHelper bitHelper, ByteBufferUtility byteBufferUtility) {
×
67
        this.context = context;
×
68
        this.cProducer = cProducer;
×
69
        this.bitHelper = bitHelper;
×
NEW
70
        this.byteBufferUtility = byteBufferUtility;
×
71

72
        int srcSizeInBytes = getSrcSizeInBytes();
×
NEW
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) {
NEW
94
        if (KeyUtility.isInvalidWithBatchSize(privateKeyBase, maxPrivateKeyForBatchSize)) {
×
NEW
95
            throw new PrivateKeyTooLargeException(privateKeyBase, maxPrivateKeyForBatchSize, cProducer.batchSizeInBits);
×
96
        }
97

NEW
98
        byte[] byteArray = byteBufferUtility.bigIntegerToBytes(privateKeyBase);
×
NEW
99
        byteBufferUtility.putToByteBufferAsMSBtoLSB(srcByteBuffer, byteArray);
×
UNCOV
100
    }
×
101
    
102
    @VisibleForTesting
103
    public ByteBuffer getSrcByteBuffer() {
NEW
104
        return srcByteBuffer;
×
105
    }
106

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

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

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

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

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

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

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

198
    public void releaseCl() {
199
        clReleaseMemObject(srcMem);
×
200
    }
×
201

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

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

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

219
        return clone;
×
220
    }
221

222
}
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