Fix #45: measure whole bytes of entropy instead of zero-padding the last one - #90
Open
corgab wants to merge 2 commits into
Open
Fix #45: measure whole bytes of entropy instead of zero-padding the last one#90corgab wants to merge 2 commits into
corgab wants to merge 2 commits into
Conversation
generateEntropy() sized the shots for the exact bit count requested, and bitstringToBytes() turned a final chunk shorter than 8 bits into a byte whose high bits were always zero, so generate(12) returned a second byte that could never exceed 15. The driver now rounds the request up to whole bytes before computing shots and requires the device to return that many bits, so every returned byte is fully measured; bitstringToBytes() rejects a bit string that is not a multiple of 8 binary digits instead of padding it silently. Closes #45
…rd strict Non-binary output from entropy.py is now rejected by the driver as a malformed response, so it surfaces as a QuantumExecutionException with the script name rather than as the bridge's argument error. The bridge guard anchors its pattern with /D so a trailing newline cannot slip through, drops the redundant empty-string clause and keeps the 0xFF mask that types the chr() argument. The QuantumDevice contract now documents the whole-byte guarantee, and the README no longer states a measured count that depends on entropy_qubits.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
EntropyGenerator::generate($bits)accepts any positive bit count, butAbstractQuantumDriver::generateEntropy()sized the device request for exactly$bitsandPythonBridge::bitstringToBytes()split the result into 8-bit chunks withstr_split(). When$bitswas not a multiple of 8 the final chunk was shorter,bindec()left-padded it with zeros, and the last returned byte had deterministic high bits:generate(12)produced a second byte that could never exceed 15, silently, for exactly the security-sensitive uses the README advertises.Plan
Option (a) from the issue: round the request up to whole bytes inside the driver, so the device measures the extra bits and every returned byte is fully random, and make the bit-to-byte conversion refuse input that would need padding, so the bug cannot come back through another caller.
Changes
AbstractQuantumDriver::generateEntropy():$bitsToFetch = ceil($bits / 8) * 8; shots are computed from that, the response must contain only0/1digits and at least that many of them (both reported asQuantumExecutionException::malformedResponse('entropy.py', ...)), and exactly that many are handed tobitstringToBytes(). TheEntropyGeneratedevent still reports the requested$bits. Callers getceil($bits / 8)bytes as before, now all measured.PythonBridge::bitstringToBytes(): throwsInvalidArgumentExceptionfor a non-binary character or a length that is not a multiple of 8, instead of padding; the pattern is anchored with/Dso a trailing newline cannot pass. ThePythonExecutorandQuantumDevicecontracts document the precondition and the whole-byte guarantee.EntropyGenerator::generate()docblock states the byte count and the rounding. README "Entropy Generation" adds one paragraph with thegenerate(12)example; CLAUDE.md gains one conventions bullet.No config change, no new dependencies, no change for bit counts that are multiples of 8.
Tests
AbstractQuantumDriverTest: dataset proving the shot count and the fetched length for 12 bits on 16 qubits (1 shot, 16 bits), 9 bits on 4 qubits (4 shots, not 3), 17 bits on 16 qubits (2 shots, 24 bits) and the unchanged 16-on-16 case, asserting the exact bit string handed to the bridge; a device returning only the requested 12 bits is rejected withexpected at least 16 bits; non-binary output is rejected as a malformed response.PythonBridgeTest:bitstringToBytes()rejects a 12-bit string, an empty string, a non-binary digit and a trailing newline.main(3 shots and 12 bits were accepted) and pass here.Local: pint passed, pest 801 tests passed.
Closes #45