Skip to content

Commit b674e7d

Browse files
committed
Rename to Leios{Committee,VoterId}
This should avoid conflicts with existing or currently being created types (Peras)
1 parent f7b17ef commit b674e7d

4 files changed

Lines changed: 85 additions & 83 deletions

File tree

cardano-crypto-leios/src/Cardano/Crypto/Leios.hs

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ module Cardano.Crypto.Leios (
2525

2626
-- * Voting committee
2727
Weight,
28-
VoterId (..),
29-
encodeVoterId,
30-
decodeVoterId,
28+
LeiosVoterId (..),
29+
encodeLeiosVoterId,
30+
decodeLeiosVoterId,
3131
LeiosVoter (..),
32-
Committee (..),
33-
committeeSize,
34-
resolveVoter,
35-
getVoterId,
32+
LeiosCommittee (..),
33+
leiosCommitteeSize,
34+
resolveLeiosVoter,
35+
getLeiosVoterId,
3636

3737
-- * Leios certificates
3838
LeiosCert (..),
@@ -130,19 +130,19 @@ type Weight = Rational
130130
-- 'committeeVoters' and determines its bit in the 'LeiosCert' @signers@
131131
-- bitfield (MSB-first within each byte, so voter @i@ ↔ bit @7-(i mod 8)@ of
132132
-- byte @i \`div\` 8@).
133-
newtype VoterId = VoterId {voterIndex :: Word16}
133+
newtype LeiosVoterId = LeiosVoterId {voterIndex :: Word16}
134134
deriving stock (Eq, Ord, Show, Generic)
135135
deriving anyclass (NFData, NoThunks)
136136

137-
-- | Plain CBOR encoder for 'VoterId'.
138-
encodeVoterId :: VoterId -> Encoding
139-
encodeVoterId (VoterId idx) = encodeWord16 idx
137+
-- | Plain CBOR encoder for 'LeiosVoterId'.
138+
encodeLeiosVoterId :: LeiosVoterId -> Encoding
139+
encodeLeiosVoterId (LeiosVoterId idx) = encodeWord16 idx
140140

141-
-- | Plain CBOR decoder for 'VoterId'.
142-
decodeVoterId :: Decoder s VoterId
143-
decodeVoterId = VoterId <$> decodeWord16
141+
-- | Plain CBOR decoder for 'LeiosVoterId'.
142+
decodeLeiosVoterId :: Decoder s LeiosVoterId
143+
decodeLeiosVoterId = LeiosVoterId <$> decodeWord16
144144

145-
-- | A single seat in a 'Committee': a voter's normalised weight paired with
145+
-- | A single seat in a 'LeiosCommittee': a voter's normalised weight paired with
146146
-- its BLS verification key.
147147
data LeiosVoter = LeiosVoter
148148
{ voterWeight :: !Weight
@@ -154,49 +154,49 @@ data LeiosVoter = LeiosVoter
154154
-- | The voting committee for a Leios epoch: an ordered vector of
155155
-- 'LeiosVoter' seats.
156156
--
157-
-- Ixition determines the voter's 'VoterId' and its bit in the certificate's
157+
-- Ixition determines the voter's 'LeiosVoterId' and its bit in the certificate's
158158
-- bitfield, so callers must keep the order stable between construction and
159159
-- verification of any cert.
160160
--
161161
-- This package intentionally does not provide committee selection — sampling
162162
-- voters from the active stake distribution lives in consensus/ledger.
163163
-- However, callers are responsible for ensuring that every voter's BLS
164-
-- proof-of-possession has been verified before a 'Committee' value is built;
164+
-- proof-of-possession has been verified before a 'LeiosCommittee' value is built;
165165
-- 'verifyLeiosCert' and 'aggregateLeiosCert' both rely on this invariant to
166166
-- skip per-key PoP checks (they use 'uncheckedAggregateVerKeysDSIGN' /
167167
-- 'aggregateSigsDSIGN' under the hood). Passing in unchecked keys defeats
168168
-- the security of the aggregate signature.
169-
newtype Committee = Committee {committeeVoters :: Vector LeiosVoter}
169+
newtype LeiosCommittee = LeiosCommittee {committeeVoters :: Vector LeiosVoter}
170170
deriving stock (Show, Eq, Generic)
171171
deriving anyclass (NFData)
172172
-- 'nothunks' ships no instance for 'Data.Vector.Strict.Vector' and we don't
173173
-- want to add an orphan. A WHNF-only check on the wrapper is sufficient here:
174174
-- the strict 'Vector' forces every cell to WHNF, and a WHNF 'LeiosVoter'
175-
-- forces both of its strict fields, so "Committee in WHNF" structurally
175+
-- forces both of its strict fields, so "LeiosCommittee in WHNF" structurally
176176
-- implies no thunks anywhere inside.
177-
deriving (NoThunks) via OnlyCheckWhnfNamed "Committee" Committee
177+
deriving (NoThunks) via OnlyCheckWhnfNamed "LeiosCommittee" LeiosCommittee
178178

179179
-- | Number of seats in the committee.
180-
committeeSize :: Committee -> Int
181-
committeeSize Committee {committeeVoters} = length committeeVoters
180+
leiosCommitteeSize :: LeiosCommittee -> Int
181+
leiosCommitteeSize LeiosCommittee {committeeVoters} = length committeeVoters
182182

183-
-- | Resolve a 'VoterId' to its 'LeiosVoter' on the 'Committee', or 'Nothing'
183+
-- | Resolve a 'LeiosVoterId' to its 'LeiosVoter' on the 'LeiosCommittee', or 'Nothing'
184184
-- if the index is past the committee bound.
185-
resolveVoter :: Committee -> VoterId -> Maybe LeiosVoter
186-
resolveVoter committee voterId =
185+
resolveLeiosVoter :: LeiosCommittee -> LeiosVoterId -> Maybe LeiosVoter
186+
resolveLeiosVoter committee voterId =
187187
committee.committeeVoters V.!? idx
188188
where
189189
idx = fromIntegral @Word16 @Int voterId.voterIndex
190190

191-
-- | Find a voter's 'VoterId' on the 'Committee' by its
191+
-- | Find a voter's 'LeiosVoterId' on the 'LeiosCommittee' by its
192192
-- 'LeiosVerificationKey', or 'Nothing' if the key is not on the committee.
193193
--
194194
-- If the committee carries duplicate verification keys, returns the smallest
195195
-- index matching @vk@ (committee selection is expected to deduplicate, but
196196
-- this module does not enforce it).
197-
getVoterId :: LeiosVerificationKey -> Committee -> Maybe VoterId
198-
getVoterId vk committee =
199-
VoterId . fromIntegral @Int @Word16
197+
getLeiosVoterId :: LeiosVerificationKey -> LeiosCommittee -> Maybe LeiosVoterId
198+
getLeiosVoterId vk committee =
199+
LeiosVoterId . fromIntegral @Int @Word16
200200
<$> V.findIndex ((== vk) . voterVKey) committee.committeeVoters
201201

202202
-- | A Leios certificate over an endorser block, as specified in CIP-164:
@@ -256,7 +256,7 @@ decodeLeiosCert = do
256256

257257
data AggregationError
258258
= -- | One or more voter indices in the sigs are past the committee bound.
259-
VoterIdsOutOfBounds (NonEmpty VoterId)
259+
VoterIdsOutOfBounds (NonEmpty LeiosVoterId)
260260
| -- | BLS signature aggregation failed (e.g. malformed input signature).
261261
BLSAggregationFailed Text
262262
deriving stock (Eq, Show, Generic)
@@ -274,15 +274,15 @@ data AggregationError
274274
--
275275
-- == What this function does
276276
--
277-
-- * Range-checks each 'VoterId' against the committee.
277+
-- * Range-checks each 'LeiosVoterId' against the committee.
278278
-- * Encodes the bitfield over the committee and aggregates the input
279279
-- signatures.
280280
--
281281
-- This is the only way to construct a 'LeiosCert' from outside the package;
282282
-- the bitfield layout is an internal wire-format detail.
283283
aggregateLeiosCert ::
284-
Committee ->
285-
Map VoterId LeiosSignature ->
284+
LeiosCommittee ->
285+
Map LeiosVoterId LeiosSignature ->
286286
Either AggregationError LeiosCert
287287
aggregateLeiosCert committee sigs = do
288288
case nonEmpty outOfBoundsVoterIds of
@@ -294,14 +294,14 @@ aggregateLeiosCert committee sigs = do
294294
pure LeiosCert {signers, aggregatedSignature}
295295
where
296296
outOfBoundsVoterIds =
297-
[vid | vid <- Map.keys sigs, isNothing $ resolveVoter committee vid]
297+
[vid | vid <- Map.keys sigs, isNothing $ resolveLeiosVoter committee vid]
298298

299299
-- Builds directly into a mutable 'ByteArray' via a single allocation and
300300
-- writes one bit per member of the input set.
301301
signers = BitField $ runByteArray $ do
302302
mba <- newByteArray len
303303
fillByteArray mba 0 len 0
304-
forM_ (Map.keys sigs) $ \(VoterId i) -> do
304+
forM_ (Map.keys sigs) $ \(LeiosVoterId i) -> do
305305
let idx = fromIntegral @Word16 @Int i
306306
when (idx < n) $ do
307307
let byteIx = idx `shiftR` 3
@@ -310,12 +310,12 @@ aggregateLeiosCert committee sigs = do
310310
writeByteArray mba byteIx (b `setBit` bitIx)
311311
pure mba
312312

313-
n = committeeSize committee
313+
n = leiosCommitteeSize committee
314314

315315
len = (n + 7) `div` 8
316316

317317
data VerificationError
318-
= -- | 'signers' bitfield is longer than @⌈committeeSize/8⌉@ bytes.
318+
= -- | 'signers' bitfield is longer than @⌈leiosCommitteeSize/8⌉@ bytes.
319319
MalformedSigners
320320
| -- | The aggregate-BLS verification failed (wrong message, tampered
321321
-- signature, or a bitfield/aggregate mismatch).
@@ -325,12 +325,12 @@ data VerificationError
325325
deriving stock (Eq, Show, Generic)
326326
deriving anyclass (NFData)
327327

328-
-- | Verify a 'LeiosCert' against a 'Committee', a weight threshold, and the
328+
-- | Verify a 'LeiosCert' against a 'LeiosCommittee', a weight threshold, and the
329329
-- message the signers were supposed to have signed.
330330
--
331331
-- == Caller obligations
332332
--
333-
-- Every voter in the 'Committee' must have had its BLS proof-of-possession
333+
-- Every voter in the 'LeiosCommittee' must have had its BLS proof-of-possession
334334
-- verified beforehand (when the committee was selected). 'verifyLeiosCert'
335335
-- uses 'uncheckedAggregateVerKeysDSIGN' and does not re-check PoPs; passing
336336
-- in an unchecked committee breaks the security of the aggregate signature.
@@ -348,7 +348,7 @@ data VerificationError
348348
-- @msg@.
349349
verifyLeiosCert ::
350350
SignableRepresentation msg =>
351-
Committee ->
351+
LeiosCommittee ->
352352
-- | Minimum signer weight required to accept the cert.
353353
Weight ->
354354
-- | The message the signers signed.
@@ -372,15 +372,15 @@ verifyLeiosCert committee weightRequired msg cert = do
372372
& first (const InvalidSignature)
373373
pure weightReceived
374374
where
375-
n = committeeSize committee
375+
n = leiosCommitteeSize committee
376376

377377
accumSigner vid (!w, !ks) =
378-
case resolveVoter committee vid of
378+
case resolveLeiosVoter committee vid of
379379
Nothing -> Left MalformedSigners
380380
Just (LeiosVoter w' vk) -> Right (w + w', vk : ks)
381381

382382
bitFieldMembers (BitField ba) =
383-
[ VoterId (fromIntegral @Int @Word16 globalIx)
383+
[ LeiosVoterId (fromIntegral @Int @Word16 globalIx)
384384
| byteIx <- [0 .. sizeofByteArray ba - 1]
385385
, let byte = indexByteArray ba byteIx :: Word8
386386
, bitIx <- [0 .. 7]
@@ -389,7 +389,7 @@ verifyLeiosCert committee weightRequired msg cert = do
389389
, testBit byte (7 - bitIx)
390390
]
391391

392-
-- | The @signers@ bitfield of a 'LeiosCert': a @⌈committeeSize\/8⌉@-byte
392+
-- | The @signers@ bitfield of a 'LeiosCert': a @⌈leiosCommitteeSize\/8⌉@-byte
393393
-- MSB-first packed-bits representation of which committee voters contributed
394394
-- to the aggregate signature.
395395
--

cardano-crypto-leios/test/Test/Cardano/Crypto/Leios.hs

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,24 @@ import Cardano.Crypto.DSIGN (
1515
)
1616
import Cardano.Crypto.Leios (
1717
AggregationError (..),
18-
Committee (..),
1918
LeiosCert (..),
19+
LeiosCommittee (..),
2020
LeiosDSIGN,
2121
LeiosSignature,
2222
LeiosSigningKey,
2323
LeiosVoter (..),
24+
LeiosVoterId (..),
2425
VerificationError (..),
25-
VoterId (..),
2626
Weight,
2727
aggregateLeiosCert,
2828
decodeLeiosCert,
29-
decodeVoterId,
29+
decodeLeiosVoterId,
3030
encodeBitField,
3131
encodeLeiosCert,
32-
encodeVoterId,
33-
getVoterId,
32+
encodeLeiosVoterId,
33+
getLeiosVoterId,
3434
leiosSignContext,
35-
resolveVoter,
35+
resolveLeiosVoter,
3636
verifyLeiosCert,
3737
)
3838
import Cardano.Crypto.Seed (mkSeedFromBytes)
@@ -71,7 +71,7 @@ spec = do
7171
goldenEncoding "test/golden/LeiosCert" encodeLeiosCert exampleCert
7272

7373
describe "aggregateLeiosCert" $ do
74-
prop "rejects an out-of-range VoterId" prop_aggregateLeiosCert_rejects_out_of_range
74+
prop "rejects an out-of-range LeiosVoterId" prop_aggregateLeiosCert_rejects_out_of_range
7575
prop "rejects empty contributions" prop_aggregateLeiosCert_rejects_empty
7676

7777
describe "verifyLeiosCert" $ do
@@ -84,14 +84,16 @@ spec = do
8484
prop "rejects a bitfield wider than the committee" prop_verifyLeiosCert_rejects_oversized_signers
8585
prop "rejects a tampered bitfield" prop_verifyLeiosCert_rejects_tampered_bitfield
8686

87-
describe "VoterId" $ do
87+
describe "LeiosVoterId" $ do
8888
prop "round-trips through CBOR" prop_roundtrip_VoterId
8989
it "matches golden encoding" $
90-
goldenEncoding "test/golden/VoterId" encodeVoterId exampleVoterId
90+
goldenEncoding "test/golden/LeiosVoterId" encodeLeiosVoterId exampleVoterId
9191

92-
describe "Committee" $ do
93-
prop "getVoterId and resolveVoter agree on verification keys" prop_resolveVoter_getVoterId_inverse
94-
prop "getVoterId returns the first matching index" prop_getVoterId_returns_first_index
92+
describe "LeiosCommittee" $ do
93+
prop
94+
"getLeiosVoterId and resolveLeiosVoter agree on verification keys"
95+
prop_resolveVoter_getVoterId_inverse
96+
prop "getLeiosVoterId returns the first matching index" prop_getVoterId_returns_first_index
9597

9698
-- * CBOR roundtrip / golden
9799

@@ -137,18 +139,18 @@ exampleCert = case aggregateLeiosCert committee contributions of
137139
msg = "leios-golden-message" :: BS.ByteString
138140
contributions = signContribs msg (zip [0 ..] (toList sks))
139141

140-
-- * VoterId CBOR / committee lookup
142+
-- * LeiosVoterId CBOR / committee lookup
141143

142144
prop_roundtrip_VoterId :: Property
143-
prop_roundtrip_VoterId = forAll (VoterId <$> QC.arbitrary) $ \vid ->
144-
let bs = CBOR.serialize (encodeVoterId vid)
145-
in CBOR.decodeFullDecoder "VoterId" decodeVoterId bs === Right vid
145+
prop_roundtrip_VoterId = forAll (LeiosVoterId <$> QC.arbitrary) $ \vid ->
146+
let bs = CBOR.serialize (encodeLeiosVoterId vid)
147+
in CBOR.decodeFullDecoder "LeiosVoterId" decodeLeiosVoterId bs === Right vid
146148

147-
exampleVoterId :: VoterId
148-
exampleVoterId = VoterId 0xABCD
149+
exampleVoterId :: LeiosVoterId
150+
exampleVoterId = LeiosVoterId 0xABCD
149151

150-
-- | 'getVoterId' and 'resolveVoter' are mutual inverses on the verification
151-
-- key projection: for any voter in the committee, looking up its 'VoterId'
152+
-- | 'getLeiosVoterId' and 'resolveLeiosVoter' are mutual inverses on the verification
153+
-- key projection: for any voter in the committee, looking up its 'LeiosVoterId'
152154
-- via its key and resolving back to a 'LeiosVoter' yields the same key.
153155
prop_resolveVoter_getVoterId_inverse :: Property
154156
prop_resolveVoter_getVoterId_inverse =
@@ -157,16 +159,16 @@ prop_resolveVoter_getVoterId_inverse =
157159
voters = V.toList committee.committeeVoters
158160
in QC.conjoin
159161
[ counterexample ("voter index " <> show i) $
160-
case getVoterId (voterVKey voter) committee of
162+
case getLeiosVoterId (voterVKey voter) committee of
161163
Nothing -> QC.property False
162164
Just vid ->
163-
case resolveVoter committee vid of
165+
case resolveLeiosVoter committee vid of
164166
Nothing -> QC.property False
165167
Just voter' -> voterVKey voter' === voterVKey voter
166168
| (i :: Int, voter) <- zip [0 ..] voters
167169
]
168170

169-
-- | When the committee carries duplicate verification keys, 'getVoterId'
171+
-- | When the committee carries duplicate verification keys, 'getLeiosVoterId'
170172
-- returns the smallest matching index. We don't deduplicate committees
171173
-- internally; downstream selection is expected to.
172174
prop_getVoterId_returns_first_index :: Property
@@ -176,10 +178,10 @@ prop_getVoterId_returns_first_index =
176178
voters = V.toList committee.committeeVoters
177179
in QC.conjoin
178180
[ counterexample ("first occurrence at " <> show i) $
179-
getVoterId (voterVKey voter) duped
180-
=== Just (VoterId (fromIntegral i))
181+
getLeiosVoterId (voterVKey voter) duped
182+
=== Just (LeiosVoterId (fromIntegral i))
181183
| let duped =
182-
Committee
184+
LeiosCommittee
183185
(committee.committeeVoters <> committee.committeeVoters)
184186
, (i :: Int, voter) <- zip [0 ..] voters
185187
]
@@ -190,10 +192,10 @@ prop_getVoterId_returns_first_index =
190192
-- Returns the signing keys alongside the committee so tests can produce
191193
-- contributions. The 'NonEmpty' return reflects the @n ≥ 1@ precondition and
192194
-- gives tests a total 'head' for "any-one-signer" cases.
193-
fixedCommittee :: Int -> (NonEmpty LeiosSigningKey, Committee)
195+
fixedCommittee :: Int -> (NonEmpty LeiosSigningKey, LeiosCommittee)
194196
fixedCommittee n =
195197
( sks
196-
, Committee
198+
, LeiosCommittee
197199
( V.fromList
198200
[LeiosVoter (1 / fromIntegral @Int @Weight n) (deriveVerKeyDSIGN sk) | sk <- toList sks]
199201
)
@@ -216,16 +218,16 @@ genMsg :: QC.Gen BS.ByteString
216218
genMsg = chooseInt (0, 64) >>= genByteString
217219

218220
-- | Sign @msg@ with each of the given keys and pack them into a 'Map' keyed
219-
-- by 'VoterId', matching the input shape of 'aggregateLeiosCert'.
220-
signContribs :: BS.ByteString -> [(Int, LeiosSigningKey)] -> Map VoterId LeiosSignature
221+
-- by 'LeiosVoterId', matching the input shape of 'aggregateLeiosCert'.
222+
signContribs :: BS.ByteString -> [(Int, LeiosSigningKey)] -> Map LeiosVoterId LeiosSignature
221223
signContribs msg pairs =
222224
Map.fromList
223-
[(VoterId (fromIntegral @Int @Word16 i), signDSIGN leiosSignContext msg sk) | (i, sk) <- pairs]
225+
[(LeiosVoterId (fromIntegral @Int @Word16 i), signDSIGN leiosSignContext msg sk) | (i, sk) <- pairs]
224226

225227
-- | Aggregate or fail the property with the error.
226228
aggregateOrFail ::
227-
Committee ->
228-
Map VoterId LeiosSignature ->
229+
LeiosCommittee ->
230+
Map LeiosVoterId LeiosSignature ->
229231
(LeiosCert -> Property) ->
230232
Property
231233
aggregateOrFail committee contributions k = case aggregateLeiosCert committee contributions of
@@ -315,13 +317,13 @@ prop_verifyLeiosCert_rejects_tampered_bitfield = forAll (chooseInt (2, 16)) $ \n
315317
verifyLeiosCert committee (1 / fromIntegral @Int @Weight n) msg tampered
316318
=== Left InvalidSignature
317319

318-
-- | A 'VoterId' past the committee bound is rejected at aggregation time.
320+
-- | A 'LeiosVoterId' past the committee bound is rejected at aggregation time.
319321
prop_aggregateLeiosCert_rejects_out_of_range :: Property
320322
prop_aggregateLeiosCert_rejects_out_of_range = forAll genN $ \n ->
321323
forAll (chooseInt (n, n + 100)) $ \badIdx ->
322324
let (sk0 :| _, committee) = fixedCommittee n
323325
msg = "x" :: BS.ByteString
324-
bad = VoterId (fromIntegral @Int @Word16 badIdx)
326+
bad = LeiosVoterId (fromIntegral @Int @Word16 badIdx)
325327
contributions = Map.singleton bad (signDSIGN leiosSignContext msg sk0)
326328
in aggregateLeiosCert committee contributions === Left (VoterIdsOutOfBounds (bad :| []))
327329

File renamed without changes.

0 commit comments

Comments
 (0)