Python drivers for USB SHA-256 mining ASICs — driven directly over libusb, with no cgminer and no COM port.
| Chip | Boards | Bridge |
|---|---|---|
| BM1384 | GekkoScience Compac / 2Pac, TTbit | Silicon Labs CP2102 |
| BM1387 | GekkoScience NewPac | FTDI FT231X |
Both drivers are verified against a known-answer test: they are tasked with
Bitcoin block 125552, whose correct nonce (42a14695, 67 zero bits) is
public. That turns "is this driver right?" into a yes/no question with a
published answer.
$ python selftest_bm1387.py
task encoding round-trip: OK
initialising NewPac:
chips found: 2
frequency -> 200.00 MHz (45.6 GH/s nominal across 2 chips)
open cores -> 4 known-core nonces
[ 0.05s] nonce 42a14695 -> 67 zero bits *** BLOCK 125552 NONCE ***
PASS - NewPac recovered the block 125552 nonce.
pip install pyusb libusb-packageOn Windows, bind WinUSB to the device with Zadig. This is required, not optional — see Reset needs CBUS below. The device's COM port disappears, which is expected; cgminer needs the same thing.
from bm138x import bm1387
from bm138x.ftdi import Ftdi
with Ftdi() as port:
chip = bm1387.NewPac(port, frequency=200.0)
chip.init() # reset, baud, chip count, PLL, ramp cores
chip.send_work(header80) # 80-byte Bitcoin-style header
for rec in chip.read_records(1.0):
if not bm1387.is_cmd_response(rec):
nonce_bytes = rec[0:4] # drops straight into header[76:80]The BM1384 is the same shape:
from bm138x import bm1384
from bm138x.cp210x import Cp210x
with Cp210x() as port:
chip = bm1384.Bm1384(port, frequency=100.0)
chip.init()
port.write(bm1384.build_task(header80, chip.ticket_mask, chip.hcn, job_id=1))Measured honestly, by counting reported nonces: each is difficulty * 2^32
hashes in expectation, where difficulty = ticket_mask + 1. Timing your own
assumed sweep length just reproduces the number you assumed.
| Device | measured | nominal |
|---|---|---|
| NewPac, 2x BM1387 @ 100 MHz | 23.8 GH/s | 22.8 |
| 2Pac-style, 2x BM1384 @ 100 MHz | 7.6–11 GH/s | 11.0 |
| same, forced to 1 chip | 4.0–6.0 GH/s | 5.5 |
Caveats worth stating: at 40–60 nonce samples the relative error is ~15%, and delivered rate sits below nominal because re-tasking discards in-flight work. The robust figure is the ratio — configuring 2 chips instead of 1 gives ~1.9x, confirming both chips contribute.
Each of these cost real debugging time.
Reset needs CBUS (BM1387). The ASIC's nRST line hangs off FTDI CBUS pin CB1, so resetting it means CBUS bitbang mode. A COM port cannot do this, which is why WinUSB is mandatory.
Strip the FTDI status bytes. Every bulk-IN packet is prefixed with 2 modem status bytes that are not part of the data stream.
GATEBLK is byte 6, not 7. gateblk[6] = 0x80 | bauddiv. GATEBLK enables
hashing, so misplacing it looks exactly like "chip answers every command but
never mines".
Cores must be ramped open. Both chips ship with cores closed; ~56 (BM1384) or ~116 (BM1387) ramp tasks open them.
Re-feed work continuously. One task sweeps 2^32 and then the chip idles — about 190 ms at 22 GH/s.
Command CRC framing differs by chip. BM1384 uses 8*len - 5 CRC bits,
BM1387 uses 8*len - 8. Both OR the CRC into the buffer's last byte.
Adopt the detected chip count before addressing. Chip addresses are
(0x100 / chips) * i. A stale count of 1 leaves the second chip on a two-chip
stick unaddressed and idle — worth ~half your hashrate.
The ticket mask changes what "a nonce" means. It is derived from hashrate,
so a two-chip stick may report at difficulty 2 (>=33 zero bits) rather than 1.
Any hashrate estimate must multiply by ticket_mask + 1.
Both chips read a task back the same way, though the field offsets differ:
midstate = unpack('<8I', <midstate field>[::-1]) # little-endian words
tail = flip_words(<tail field>)[::-1] # word-swap, then reverse
| midstate field | tail field | |
|---|---|---|
| BM1387 | task[20:52] |
task[8:20] |
| BM1384 | task[0:32] |
task[52:64] |
Why this is a trap. Each chip's core-opening ramp task is built from
symmetric data — all-0xff on the BM1387, all-zeros on the BM1384. Both are
palindromic, so they hash identically under every byte order. The ramp
passes cleanly while byte-order bugs sit undetected, which makes the encoding
look exonerated and sends you chasing power and baud-rate theories instead.
Pinning it down took a probe task with deliberately asymmetric data: of 16 candidate arrangements exactly one produced nonces that validated.
A self-test built from symmetric data proves far less than it appears to.
cgminer logs two "open core nonces" (7203EA83, E16BF809) during the ramp.
Those are answers to the BM1387's 0xff work. Against the BM1384's
all-zero ramp they score 0 and 1 zero bits, so they can never appear. cgminer
only logs them and advances on ramp count instead — but treating them as a
health check makes a perfectly good BM1384 look dead.
The only trustworthy proof that either chip mines is a known-answer test on real work.
bm138x.pow is an example of what the drivers are good for: Hashcash-style
stamps for AI agents, exposed over MCP. An agent asks for a stamp at
difficulty N bound to a payload and gets an 80-byte token proving work was
burned for that payload and identity — usable for rate-limiting or sybil
resistance on an endpoint that cannot require accounts.
python test_mint.py # CPU mint + verify
python test_mcp.py # drive the MCP server over stdioIt pools every ASIC it finds (nonce_hi starts 2^20 apart so devices never
duplicate work) and falls back to CPU. A 40-bit stamp takes ~43 s pooled
against ~23 hours on an 11-worker CPU pool.
Honest limits: nothing in the agent ecosystem verifies these stamps today, so this is a proposal and a demo rather than infrastructure. And the hardware cannot accelerate existing gates such as Anubis — those use a single SHA-256 over a variable-length string, while these chips do double-SHA256 over exactly 80 bytes with the nonce at a fixed offset.
bm138x/sha256d.py SHA-256 compression + midstate (self-checks vs hashlib)
bm138x/cp210x.py CP2102 transport
bm138x/ftdi.py FT231X transport: CBUS reset, 1.5 Mbps, status stripping
bm138x/bm1384.py BM1384 driver
bm138x/bm1387.py BM1387 driver
bm138x/pow/ proof-of-work stamp application
mcp_server.py MCP stdio server (stdlib only)
selftest_bm1384.py known-answer test, BM1384
selftest_bm1387.py known-answer test, BM1387
GPL-3.0-or-later. The BM1384 and BM1387 protocol implementations are ports
of driver-gekko.c from cgminer and are
derived works of it — the command sequences, the 5-bit CRC, the PLL encodings,
the initialisation order and the task layouts all come from there. cgminer is
GPL-3.0, so this cannot be relicensed under permissive terms.
See NOTICE for full attribution.