Skip to content

Conversation

@perturbing
Copy link
Member

@perturbing perturbing commented Dec 8, 2025

Description

This extends and refactors the work done in #567 by @hjeljeli32.

This PR adds the two variants of the BLS12-381 signature scheme, BLS12381MinVerKeyDSIGN and BLS12381MinSigDSIGN to the already existing DSIGN class. Besides that, it also extends the class module to allow for aggregatable signature schemes, which both BLS variants are. It also includes tests and benchmark additions.

Though both BLS signature schemes work similarly, the difference is that the former signature scheme (MinVerKey) encodes the verification key in the smallest BLS group (G1), while having its signatures encoded in the bigger BLS group (G2). The latter (MinSig) does the reverse. Besides the size impact of the serialized objects, there is also a computational impact for signing/verification operations by this choice.

To play around with it, in a repl

:set -XDataKinds -XTypeApplications -XOverloadedStrings -Wno-incomplete-uni-patterns
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import Data.Proxy (Proxy(..))
import Cardano.Binary
import Cardano.Crypto.DSIGN
import Cardano.Crypto.Seed
import Cardano.Crypto.Util (SignableRepresentation(..), hexBS)

-- Setup
let seedLen = fromIntegral (seedSizeDSIGN (Proxy @BLS12381MinVerKeyDSIGN))
let seedBytes = BS.replicate seedLen 42
let seed = mkSeedFromBytes seedBytes
let skVer = genKeyDSIGN @BLS12381MinVerKeyDSIGN seed
let vkVer = deriveVerKeyDSIGN @BLS12381MinVerKeyDSIGN skVer
let simpleMsg = "Hello World" :: BS.ByteString

-- Basic use of new DSIGN interface
let sigVer = signDSIGN @BLS12381MinVerKeyDSIGN (Nothing, Nothing) simpleMsg skVer
verifyDSIGN @BLS12381MinVerKeyDSIGN (Nothing, Nothing) vkVer simpleMsg sigVer

-- More elaborate usage
let dstMainnet = Just "BLS_DST_CARDANO_V1" :: Maybe BS.ByteString
let augRandom = Just "BLS_AUG_MAINNET_V1" :: Maybe BS.ByteString
let ctxMainnet = (dstMainnet,  augRandom)
let seedsBytes = map (BS.replicate seedLen) [0 .. 255]
let seeds = map mkSeedFromBytes seedsBytes
let sksVer = map (genKeyDSIGN @BLS12381MinVerKeyDSIGN) seeds
let vksVer = map (deriveVerKeyDSIGN @BLS12381MinVerKeyDSIGN) sksVer
let pops = map (proveProofOfPossessionDSIGN @BLS12381MinVerKeyDSIGN ctxMainnet) sksVer
let msg = "some EB hash" :: BS.ByteString
let sigs = map (signDSIGN @BLS12381MinVerKeyDSIGN ctxMainnet msg) sksVer

-- Naive way of verifying without using aggregation property 
-- of signature scheme
-- 
-- 1) check that all vk's have valid PoPs
-- 2) check each signature without aggregation
sequence_ $ map (\(vk,pop) -> verifyProofOfPossessionDSIGN @BLS12381MinVerKeyDSIGN ctxMainnet vk pop) (zip vksVer pops)
sequence_ $ map (\(vk,sig) -> verifyDSIGN @BLS12381MinVerKeyDSIGN ctxMainnet vk msg sig) (zip vksVer sigs)

-- In the context of Leios, EB votes from each spo contain/map to a 
-- signature and verification key pair. Also, note that in this context, 
-- SPO register their bls keys in advance, at which time a PoP 
-- check is done. When constructing an EB certificate, 
-- it is the aggregation below that compresses all these signatures 
-- in one (together with who participated in signing)
let Right aggrSig = aggregateSigDSIGN @BLS12381MinVerKeyDSIGN sigs
-- Then any observer of that certificate can verifying the 
-- group signature against the many signers via
verifyAggregateDSIGNWithoutPoPs ctxMainnet vksVer msg aggrSig

Note that this signature scheme introduces five things that a "normal" DSIGN interface does not have.

  1. The DSIGN class is extended to optionally generate keys with extra key info (KeyGenContext v). This is to comply with the key generation as per this IETF draft. This change is backwards compatible with the other existing DSIGN signature schemes.
ghci> genKeyDSIGN @BLS12381MinVerKeyDSIGN seed == genKeyDSIGNWithKeyInfo @BLS12381MinVerKeyDSIGN (Just "") seed
True
ghci> genKeyDSIGN @BLS12381MinSigDSIGN seed == genKeyDSIGNWithKeyInfo @BLS12381MinSigDSIGN (Just "") seed
True
ghci> genKeyDSIGNWithKeyInfo @Ed25519DSIGN () seed == genKeyDSIGN @Ed25519DSIGN seed
True
  1. This signature scheme has a signing context different from (). More explicitly, for the domain separation tag and augmentation tag, we have that
ghci> let sigVer2 = signDSIGN @BLS12381MinVerDSIGN (Just "", Just "") msg skVer
ghci> sigVer2 == sigVer
True
  1. The rawSerialise{SigDSIGN, VerKeyDSIGN} functions also compress their objects (as per the ZCash standard). That is, e.g.,
ghci> vkVer 
VerKeyBLS12381 "5326f72f278230d9c89c1d2fc5f0027af4fd3b354c1c33429c729b1c41c02009e139b96c47e909d4cd160fc6218d3518aa6d098550dbec14b9383fa642dd58b4c046238ebef93ba5b8c4c3963a66f450f2dba5a19f5a98d0f51fc754b9a35315fdff02000000097602000cc40b00f4ebba58c7535798485f455752705358ce776dec56a2971a075c93e480fac35ef615"
ghci> BS.length $ rawSerialiseVerKeyDSIGN @BLS12381MinVerKeyDSIGN vkVer
48
ghci> hexBS $ BL.toStrict $ serialize vkVer 
"0x58308ae7e5822ba97ab07877ea318e747499da648b27302414f9d0b9bb7e3646d248be90c9fdaddfdb93485a6e9334f01093 (length 50)"
  1. The rawDeserialise{SigDSIGN, SignKeyDSIGN VerKeyDSIGN} also performs a check on whether the curve points (for a VerKeyDSIGN and SigDSIGN) and the raw scalar input (for the SignKeyDSIGN) are non-zero and reduces it to the field (for the safety of the other FFI calls that might follow on it). E.g.,
ghci> let skBsZeros = BS.replicate 32 0
ghci> let skBsOnes = BS.replicate 32 255
ghci> rawDeserialiseSignKeyDSIGN @BLS12381MinVerKeyDSIGN skBsZeros
Nothing
ghci> rawDeserialiseSignKeyDSIGN @BLS12381MinVerKeyDSIGN skBsOnes 
Just (SignKeyBLS12381 "fdffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418")
  1. This PR extends the DSIGNAlgorithm v interface with DSIGNAggregatable v, which allows for the utility functions that relate to aggregatable signature schemes like aggregated signature verification and the creation and verification of Proof of Possessions (PoP) of verification keys.

For others interested in this work and that want to run the benchmarks

 cabal run cardano-crypto-class:bench --  --match pattern BLS12381

Integrator-facing documentation (proposal)

I couldn’t find a concise integrator-facing documentation for DSIGN + BLS. BLS has a few “extra moving parts” compared to other DSIGN schemes: two variants (min-sig vs min-verkey) with different artifact sizes/perf tradeoffs, PoP + aggregation workflows, and a signing context via (DST, AUG).

Proposal: add a short “BLS DSIGN Integrator Guide” section under cardano-crypto-class/README.md (or a more appropriate location), covering:

  • Variant choice: BLS12381MinSigDSIGN vs BLS12381MinVerKeyDSIGN (sizes + typical tradeoff).
  • ContextDSIGN: what DST/AUG mean, and recommended usage pattern.
  • PoP/aggregation: expected flow for registrars/aggregators/validators.
  • Minimal code snippet for major operations (sign/verify, aggregate/verify, etc) and key/sig/PoP compressed sizes + serialization/deserialization failure notes.

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

@perturbing perturbing force-pushed the perturbing/leios-bls-DSIGN branch from 51c3bbb to 8797dba Compare December 8, 2025 16:24
@perturbing perturbing force-pushed the perturbing/leios-bls-DSIGN branch 5 times, most recently from 10c9712 to 529c0f9 Compare December 9, 2025 16:30
@perturbing perturbing force-pushed the perturbing/leios-bls-DSIGN branch 7 times, most recently from 2c1e9ed to 03e6c3e Compare December 11, 2025 14:17
@perturbing perturbing force-pushed the perturbing/leios-bls-DSIGN branch 6 times, most recently from 5299ffc to 1921b7f Compare December 12, 2025 14:43
Base automatically changed from perturbing/bls-psb to master December 12, 2025 23:08
@perturbing perturbing force-pushed the perturbing/leios-bls-DSIGN branch 6 times, most recently from 638cbee to a8b303e Compare December 16, 2025 14:57
@perturbing perturbing requested review from a team, erikd and nfrisby as code owners December 18, 2025 11:24
@perturbing perturbing changed the base branch from master to nm/remove-cardano-crypto-tests December 18, 2025 12:37
@ch1bo ch1bo changed the title Add bls signature scheme to DSIGN interface Add BLS signature scheme to DSIGN interface Dec 18, 2025
@neilmayhew neilmayhew force-pushed the nm/remove-cardano-crypto-tests branch from 63783e4 to 5abd42b Compare December 22, 2025 21:32
@lehins
Copy link
Collaborator

lehins commented Dec 22, 2025

@perturbing Could you please rebase it on master and drop all of the commits that have already landed on master. It's a bit hard to review with changes that are unrelated to this PR.

@lehins
Copy link
Collaborator

lehins commented Dec 22, 2025

PR description has some very nice repl examples.
I believe it would be nice to add them as doctest examples directly in the haddock at the top of Cardano.Crypto.DSIGN.BLS12381 module

@neilmayhew neilmayhew force-pushed the nm/remove-cardano-crypto-tests branch 3 times, most recently from ce8b425 to 6bd5c25 Compare December 23, 2025 01:06
Base automatically changed from nm/remove-cardano-crypto-tests to master December 23, 2025 01:27
@perturbing perturbing force-pushed the perturbing/leios-bls-DSIGN branch 3 times, most recently from e2acec9 to 421f40f Compare December 23, 2025 21:18
@perturbing perturbing force-pushed the perturbing/leios-bls-DSIGN branch from 421f40f to 430fdfa Compare December 23, 2025 22:08
@hjeljeli32
Copy link
Collaborator

Dear @perturbing and @curiecrypt I added in the description a section about the integrator-facing documentation that I think it is worth to add. I proposed a structure of what we can include in such documentation. Please feel free to modify/add things to it.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add BLS signature support to cardano-base

4 participants