Skip to content

cardano-strict-containers: add Data.Bitmap - #700

Open
gdeest wants to merge 7 commits into
IntersectMBO:masterfrom
gdeest:gdeest/data-bitmap
Open

gdeest wants to merge 7 commits into
IntersectMBO:masterfrom
gdeest:gdeest/data-bitmap

Conversation

@gdeest

@gdeest gdeest commented Sep 24, 2026 •

Copy link
Copy Markdown

Adds Data.Bitmap to cardano-strict-containers (moved from Ouroboros.Consensus.Util.Bitmap).

Now uses MSB-encoding so that it can be easily re-used by Leios BitField requirements.

Used by #701 .

Checklist

  • Commit sequence broadly makes sense and commits have useful messages
  • New tests are added if needed and existing tests are updated
  • All visible changes are prepended to the latest section of a CHANGELOG.md for the affected packages.
    New section is never added with the code changes. (See RELEASING.md)
  • When applicable, versions are updated in .cabal and CHANGELOG.md files according to the
    versioning process.
  • The version bounds in .cabal files for all affected packages are updated.
    If you change the bounds in a cabal file, that package itself must have a version increase. (See RELEASING.md)
  • Self-reviewed the diff

@agustinmista agustinmista left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good! Just some small nits.

@gdeest
gdeest force-pushed the gdeest/data-bitmap branch from fd59e15 to 7f29c17 Compare October 7, 2026 07:51
@gdeest
gdeest marked this pull request as ready for review October 7, 2026 08:06
@gdeest
gdeest requested review from a team and lehins as code owners October 7, 2026 08:06
@gdeest gdeest mentioned this pull request Oct 7, 2026
6 tasks done

@agustinmista agustinmista left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! Thanks for expanding the previous test suite 🧪

It looks like cabal-format is complaining in CI, though.

@ch1bo

ch1bo commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Now uses MSB-encoding so that it can be easily re-used by Leios BitField requirements.

I think you should be doing this in this PR to prove that claim and so we end up with the same number of bitfield implementations.


-- | A compact bitmap representation using serialisation-ready ByteStrings.
--
-- Adapted from @Cardano.Leios.BitMapPV@ in the @leios-wfa-ls-demo@ package.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a proof of concept. You should instead base your implementation on the production grade version introduced in cardano-crypto-leios

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 7e63c40.


-- | A bitmap over a number of indexes known to its users: @⌈n/8⌉@ bytes,
-- MSB-first, bit @i@ set iff index @i@ is set.
newtype Bitmap = Bitmap {bitmapBytes :: ByteString}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a strict container if at its core is a lazy bytestring. Should be a strict bytestring or a ByteArray

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was actually a strict ByteString, but now uses a ByteArray as the cardano-crypto-leios impl anyway.

@gdeest
gdeest force-pushed the gdeest/data-bitmap branch from e4bb2dd to d2ff278 Compare November 4, 2026 08:52
@gdeest

gdeest commented Nov 4, 2026

Copy link
Copy Markdown
Author

I think you should be doing this in this PR to prove that claim and so we end up with the same number of bitfield implementations.

@ch1bo I have modified the implementation essentially the same as what was in current cardano-crypto-leios and modified the latter to use the Bitmap through a newtype.

One remark about well-formedness: verifyLeiosCert ignores bits set after the last seat, while Bitmap.wellFormed rejects those. To keep cardano-crypto-leios unchanged, it does not use wellFormed (while Peras does / will).

@tbagrel1 tbagrel1 added the peras label Nov 9, 2026
gdeest added a commit to gdeest/cardano-base that referenced this pull request Nov 13, 2026

@bladyjoker bladyjoker left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @gdeest !

I have one topic to discuss, and that is to make a safe constructor for the Bitmap that checks its properties and hide the data constructor.

Since that data constructor would be given an Int denoting the cardinality/size, we can strip this argument from the rest of the API and be explicit with what this Bitmap is (ie. wellFormed).

In short

bitmapFromByteArray :: Int -> ByteArray -> Either String Bitmap

data Bitmap = Bitmap { bitmapBytes :: ByteArray, bitmapSize :: Int }

deriving (NoThunks) via OnlyCheckWhnfNamed "Bitmap" Bitmap

-- | The number of indexes set (flipped to 1) in the bitmap.
numSetBits :: Bitmap -> Int

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what that function is intended to do, atm it can count set padding bit as valid indices which is probably incorrect. I think we either need n here as well, otherwise when enforced a zero padding this can then also work.

-- | A 'LeiosCert' signers bitfield: @⌈leiosCommitteeSize\/8⌉@ bytes, MSB-first,
-- bit @i@ set iff seat @i@ signed. Newtype so it isn't confused with raw bytes.
newtype BitField = BitField {bitFieldBytes :: ByteArray}
newtype BitField = BitField {bitFieldBitmap :: Bitmap}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm considering that we should leave this a ByteArray (as in, we don't know much about this) and then use a a safe bitmapFromByteArray :: Int -> Either String Bitmap constructor?

, testBit w (7 - bitIx)
]

-- | Whether a bitmap is well-formed over the given number of indexes: it has

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit under commented, can you expand on the invariants it checks for?

Consider wellFormed :: Int -> Bitmap -> Either String () and have a description of what went wrong.

Left (MalformedCommittee n)
-- Bitfield length is fixed at ⌈committee/8⌉ bytes; anything else is malformed.
when (sizeofByteArray (bitFieldBytes cert.leiosCertSigners) /= (n + 7) `div` 8) $
when (Bitmap.sizeInBytes cert.leiosCertSigners.bitFieldBitmap /= Bitmap.numBytes n) $

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please introduce a wellFormed check here rather.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants