Scaffold an initial cardano-crypto-leios package#670
Conversation
d85df0c to
aa227fa
Compare
bf92c7d to
780e347
Compare
1102098 to
25e16ac
Compare
Roundtrip and golden tests for LeiosCert
These are the only means to create and verify leios certificates about a certain message (a leios vote). Committee selection was deliberately kept out of scope
The golden test compares 'cardano-crypto-leios/test/golden/LeiosCert' byte-for-byte against the hex-dump output of 'encodeWithIndex'. Without this attribute, the default Windows 'core.autocrlf=true' translates LF to CRLF on checkout and the comparison fails, even though the file is committed with LF endings.
These were needed/useful in the cardano-ledger-dijkstra integration
73d303e to
745de18
Compare
This avoids redundant import warnings on newer GHC versions
745de18 to
38a3b98
Compare
lehins
left a comment
There was a problem hiding this comment.
Consistency is one of the most important parts in software development. It is important to use consistent dependencies as the rest of the project, in this case cardano-base repo being that project.
| -- skip per-key PoP checks (they use 'uncheckedAggregateVerKeysDSIGN' / | ||
| -- 'aggregateSigsDSIGN' under the hood). Passing in unchecked keys defeats | ||
| -- the security of the aggregate signature. | ||
| newtype Committee = Committee {committeeVoters :: Vector (Weight, LeiosVerificationKey)} |
There was a problem hiding this comment.
Vector is lazy, which will easily lead to space leaks.
Having a lazy tuple as an element will exacerbate this issue.
At the very least I suggest creating a proper data type for the vector element, instead of using a tuple and be really diligent in forcing elements of a vector. Something like that:
| newtype Committee = Committee {committeeVoters :: Vector (Weight, LeiosVerificationKey)} | |
| newtype Committee = Committee {committeeVoters :: Vector LeiosVoter} |
data LeiosVoter = LeiosVoter
{ leiosVoterWeight :: !Weight
, leiosVoterVerKey :: !LeiosVerificationKey
}| = -- | A voter index in the contributions is past the committee bound. | ||
| VoterIdOutOfBounds !VoterId | ||
| | -- | BLS signature aggregation failed (e.g. malformed input signature). | ||
| BLSAggregationFailed !String |
There was a problem hiding this comment.
List is lazy. Making it strict in WHNF is not very useful. Therefore it is best to switch to Text
| BLSAggregationFailed !String | |
| BLSAggregationFailed !Text |
|
|
||
| -- | Plain CBOR decoder for 'LeiosCert', matching the CDDL in 'LeiosCert'. | ||
| decodeLeiosCert :: Decoder s LeiosCert | ||
| decodeLeiosCert = do |
There was a problem hiding this comment.
This decoder will be unusable in ledger, since it doesn't support indefinite length encoding
| aggregateLeiosCert committee contributions = do | ||
| let n = committeeSize committee | ||
| entries = Map.toAscList contributions | ||
| case [v | (v, _) <- entries, fromIntegral (voterIndex v) >= n] of |
There was a problem hiding this comment.
Creating a separate binding entries will cause that list to be allocated. However if we use Map directly in both places where it is used then we will tap into list fusion and avoid that list being allocated. Also we need to make sure all fromIntegral in this repo are type annotated
| case [v | (v, _) <- entries, fromIntegral (voterIndex v) >= n] of | |
| case [v | v <- Map.keys contributions, fromIntegral @Word32 @Int (voterIndex v) >= n] of |
| v : _ -> Left (VoterIdOutOfBounds v) | ||
| [] -> pure () | ||
| aggSig <- | ||
| case aggregateSigsDSIGN (map snd entries) of |
There was a problem hiding this comment.
| case aggregateSigsDSIGN (map snd entries) of | |
| case aggregateSigsDSIGN (Map.elems contributions) of |
| { signers :: !BitField | ||
| , aggregatedSignature :: !LeiosSignature |
There was a problem hiding this comment.
This is a pretty terrible naming, since signers can easily be a local binding anywhere in the cardano-node codebase. I suggest something more descriptive like:
| { signers :: !BitField | |
| , aggregatedSignature :: !LeiosSignature | |
| { leisCertSigners :: !BitField | |
| , leisCertSignature :: !LeiosSignature | |
| -- ^ Aggregated BLS signature |
| where | ||
| -- The bitfield decoder already enforced @i < n@; if the committee is | ||
| -- shorter than the decoder's idea of @n@ we treat it as a malformed cert. | ||
| accumSigner voters (w, ks) i = case voters V.!? i of |
There was a problem hiding this comment.
We should avoid space leaks as much as we can!
| accumSigner voters (w, ks) i = case voters V.!? i of | |
| accumSigner voters (!w, !ks) i = case voters V.!? i of |
Adds a new package for leios cryptographic types and operations. This was done in course of IntersectMBO/ouroboros-consensus#2068, I'm currently integrating this with the
cardano-ledgermasterand expect a follow-up PR there.The digital signature scheme is BLS12-381 and fixed in the module. Contrary to the CIP-164, the certificate does not contain a slot or
EbHashanymore. This makes definition incardano-basea lot easier and in the current block structure design, the "message" against which the certificate is signed would be available from the (block) context in which the certificate is used.Most importantly, this module contains encoders/decoders for the
LeiosCerttype including roundtrip and golden tests. This should be enough for thecardano-ledgerto use this type confidently inDijkstraera blocks.There are also property tests about aggregating and verifying certificates. The
Committeeis part of this package, but how it is selected is deliberately kept out of scope.