Skip to content

Repository files navigation

bm138x

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.

Install

pip install pyusb libusb-package

On 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.

Use

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 throughput

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.

Things that are not obvious

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.

Task byte order — the trap

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.

A second false signal

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.

Included application: proof-of-work stamps

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 stdio

It 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.

Layout

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

Licence

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.

About

Python drivers for BM1384 / BM1387 USB SHA-256 mining ASICs (GekkoScience NewPac, Compac, 2Pac, TTbit) - direct libusb, no cgminer

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages