Skip to content

Commit 245e63d

Browse files
authored
Merge pull request #5872 from IntersectMBO/ch1bo/cardano-crypto-leios
Add LeiosCert to DijkstraBlockBody
2 parents c50e870 + 7b69ca5 commit 245e63d

17 files changed

Lines changed: 193 additions & 53 deletions

File tree

cabal.project

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ source-repository-package
2828
-- see CONTRIBUTING.md#to-update-the-referenced-agda-ledger-spec
2929
index-state:
3030
, hackage.haskell.org 2026-05-26T19:31:06Z
31-
, cardano-haskell-packages 2026-05-26T09:41:58Z
31+
, cardano-haskell-packages 2026-06-29T12:05:19Z
3232

3333
packages:
3434
-- == Byron era ==

eras/dijkstra/impl/cardano-ledger-dijkstra.cabal

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ library
107107
bytestring,
108108
cardano-base >=0.1.4,
109109
cardano-crypto-class,
110+
cardano-crypto-leios >=0.1,
110111
cardano-data ^>=1.3,
111112
cardano-ledger-allegra,
112113
cardano-ledger-alonzo ^>=1.16,
@@ -178,6 +179,8 @@ library testlib
178179
base,
179180
bytestring,
180181
cardano-base,
182+
cardano-crypto-class,
183+
cardano-crypto-leios:{cardano-crypto-leios, testlib},
181184
cardano-data,
182185
cardano-ledger-allegra:{cardano-ledger-allegra, testlib},
183186
cardano-ledger-alonzo:{cardano-ledger-alonzo, testlib},
@@ -215,6 +218,7 @@ library cddl
215218
build-depends:
216219
antigen,
217220
base,
221+
cardano-crypto-leios:{cardano-crypto-leios, testlib},
218222
cardano-ledger-conway:cddl,
219223
cardano-ledger-core:cddl,
220224
cardano-ledger-dijkstra,

eras/dijkstra/impl/cddl/data/dijkstra.cddl

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ major_protocol_version = 0 .. 13
9797
block_body =
9898
[ invalid_transactions : invalid_transactions/ nil
9999
, transactions : [* transaction]
100-
, peras_certificate : peras_certificate
100+
, leios_certificate : leios_certificate/ nil
101+
, peras_certificate : peras_certificate/ nil
101102
]
102103

103104
invalid_transactions = nonempty_set<transaction_index>
@@ -888,5 +889,12 @@ auxiliary_data_map =
888889
}
889890
)
890891

891-
peras_certificate = bytes/ nil
892+
leios_certificate =
893+
[ signers : bytes ;bitfield
894+
, aggregated_signature : leios_signature
895+
]
896+
897+
leios_signature = bytes .size 48
898+
899+
peras_certificate = bytes
892900

eras/dijkstra/impl/cddl/lib/Cardano/Ledger/Dijkstra/HuddleSpec.hs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ module Cardano.Ledger.Dijkstra.HuddleSpec (
3232
auxiliaryDataMapRule,
3333
) where
3434

35+
import Cardano.Crypto.Leios (leiosSignatureSize, leiosSignatureToBytes)
3536
import Cardano.Ledger.Conway.HuddleSpec hiding ()
3637
import Cardano.Ledger.Dijkstra (DijkstraEra)
3738
import Cardano.Ledger.Huddle.Gen (
@@ -54,13 +55,15 @@ import Cardano.Ledger.Huddle.Gen qualified as Gen
5455
import Codec.CBOR.Term (Term (..))
5556
import Control.Monad (unless, zipWithM)
5657
import Data.Foldable (traverse_)
58+
import Data.Function ((&))
5759
import Data.List (nub)
5860
import Data.Maybe (mapMaybe)
5961
import Data.Proxy (Proxy (..))
6062
import Data.Text ()
6163
import Data.Text qualified as T
6264
import Data.Word (Word16, Word64)
6365
import Test.AntiGen (withAnnotation, (|!))
66+
import Test.Cardano.Crypto.Leios.Gen (genLeiosSignature)
6467
import Text.Heredoc
6568
import Prelude hiding ((/))
6669

@@ -956,7 +959,24 @@ instance HuddleRule "block" DijkstraEra where
956959
]
957960

958961
instance HuddleRule "peras_certificate" DijkstraEra where
959-
huddleRuleNamed pname _era = pname =.= VBytes / VNil
962+
huddleRuleNamed pname _era = pname =.= VBytes
963+
964+
instance HuddleRule "leios_certificate" DijkstraEra where
965+
huddleRuleNamed pname era =
966+
pname
967+
=.= arr
968+
[ "signers" ==> VBytes & comment "bitfield"
969+
, "aggregated_signature" ==> huddleRule @"leios_signature" era
970+
]
971+
972+
instance HuddleRule "leios_signature" DijkstraEra where
973+
huddleRuleNamed pname _era =
974+
withCBORGen leiosSignatureGen $
975+
pname =.= VBytes `sized` leiosSignatureSize
976+
where
977+
leiosSignatureGen = do
978+
sig <- liftGen genLeiosSignature
979+
pure $ SingleTerm $ TBytes (leiosSignatureToBytes sig)
960980

961981
instance HuddleRule "invalid_transactions" DijkstraEra where
962982
huddleRuleNamed pname era = pname =.= huddleRule1 @"nonempty_set" era (huddleRule @"transaction_index" era)
@@ -971,7 +991,8 @@ instance HuddleRule "block_body" DijkstraEra where
971991
=.= arr
972992
[ "invalid_transactions" ==> huddleRule @"invalid_transactions" era / VNil
973993
, "transactions" ==> arr [0 <+ a (huddleRule @"transaction" era)]
974-
, "peras_certificate" ==> huddleRule @"peras_certificate" era
994+
, "leios_certificate" ==> huddleRule @"leios_certificate" era / VNil
995+
, "peras_certificate" ==> huddleRule @"peras_certificate" era / VNil
975996
]
976997

977998
blockBodyGen :: CBORGen RuleTerm
@@ -1008,8 +1029,11 @@ blockBodyGen = do
10081029
then pure TNull
10091030
else genArrayTerm $ TInteger . toInteger <$> invalidIxIxs
10101031
txsTerm <- withAntiGen (withAnnotation "transactions") $ genArrayTerm txs
1032+
-- NOTE: This would not be a valid block because txs are not allowed when a
1033+
-- leios cert is also included
1034+
leiosCertTerm <- generateFromName "leios_certificate"
10111035
perasCertTerm <- generateFromName "peras_certificate"
1012-
SingleTerm <$> genArrayTerm [invalidTxIxsTerm, txsTerm, perasCertTerm]
1036+
SingleTerm <$> genArrayTerm [invalidTxIxsTerm, txsTerm, leiosCertTerm, perasCertTerm]
10131037

10141038
instance HuddleRule "auxiliary_scripts" DijkstraEra where
10151039
huddleRuleNamed = auxiliaryScriptsRule

eras/dijkstra/impl/src/Cardano/Ledger/Dijkstra/BlockBody/Internal.hs

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
88
{-# LANGUAGE OverloadedStrings #-}
99
{-# LANGUAGE PatternSynonyms #-}
10-
{-# LANGUAGE RecordWildCards #-}
1110
{-# LANGUAGE ScopedTypeVariables #-}
1211
{-# LANGUAGE StandaloneDeriving #-}
1312
{-# LANGUAGE TypeApplications #-}
@@ -38,8 +37,9 @@ module Cardano.Ledger.Dijkstra.BlockBody.Internal (
3837
validatePerasCert,
3938
) where
4039

40+
import Cardano.Crypto.Leios (LeiosCert)
4141
import Cardano.Ledger.Alonzo.Tx (AlonzoEraTx (..), IsValid (..))
42-
import Cardano.Ledger.BaseTypes (Nonce, ProtVer (..), maybeToStrictMaybe)
42+
import Cardano.Ledger.BaseTypes (Nonce, ProtVer (..))
4343
import Cardano.Ledger.Binary (
4444
Annotator (..),
4545
DecCBOR (..),
@@ -52,9 +52,11 @@ import Cardano.Ledger.Binary (
5252
decodeSeq,
5353
encCBOR,
5454
encodeListLen,
55+
encodeNullMaybe,
5556
encodeNullStrictMaybe,
5657
serialize',
5758
)
59+
import Cardano.Ledger.Binary.Crypto (decodeLeiosCert, encodeLeiosCert)
5860
import Cardano.Ledger.Core
5961
import Cardano.Ledger.Dijkstra.Era
6062
import Cardano.Ledger.Dijkstra.Tx (DijkstraTx, Tx (..), decodeDijkstraTopTx)
@@ -100,12 +102,16 @@ import NoThunks.Class (NoThunks)
100102

101103
data DijkstraBlockBodyRaw era = DijkstraBlockBodyRaw
102104
{ dbbrTxs :: !(StrictSeq (Tx TopTx era))
105+
, dbbrLeiosCert :: !(StrictMaybe LeiosCert)
106+
-- ^ Optional Leios certificate
103107
, dbbrPerasCert :: !(StrictMaybe PerasCert)
104108
-- ^ Optional Peras certificate
105109
}
106110
deriving (Generic)
107111

108-
instance (NFData (Tx TopTx era), NFData PerasCert) => NFData (DijkstraBlockBodyRaw era)
112+
instance
113+
(NFData (Tx TopTx era), NFData LeiosCert, NFData PerasCert) =>
114+
NFData (DijkstraBlockBodyRaw era)
109115

110116
type instance MemoHashIndex (DijkstraBlockBodyRaw era) = EraIndependentBlockBody
111117

@@ -118,15 +124,22 @@ instance EraBlockBody DijkstraEra where
118124
blockBodySize (ProtVer v _) = BS.length . serialize' v . encCBOR
119125

120126
mkBasicBlockBodyDijkstra :: forall era. AlonzoEraTx era => DijkstraBlockBody era
121-
mkBasicBlockBodyDijkstra = mkMemoized (eraProtVerLow @era) $ DijkstraBlockBodyRaw mempty SNothing
127+
mkBasicBlockBodyDijkstra =
128+
mkMemoized (eraProtVerLow @era) $
129+
DijkstraBlockBodyRaw mempty SNothing SNothing
122130
{-# INLINEABLE mkBasicBlockBodyDijkstra #-}
123131

124132
-- | Dijkstra-specific extensions to 'EraBlockBody'
125133
class EraBlockBody era => DijkstraEraBlockBody era where
134+
leiosCertBlockBodyL :: Lens' (BlockBody era) (StrictMaybe LeiosCert)
135+
-- ^ Lens to access the optional Leios certificate in the block body
136+
126137
perasCertBlockBodyL :: Lens' (BlockBody era) (StrictMaybe PerasCert)
127138
-- ^ Lens to access the optional Peras certificate in the block body
128139

129140
instance DijkstraEraBlockBody DijkstraEra where
141+
leiosCertBlockBodyL = lensMemoRawType @DijkstraEra dbbrLeiosCert (\bb c -> bb {dbbrLeiosCert = c})
142+
130143
perasCertBlockBodyL = lensMemoRawType @DijkstraEra dbbrPerasCert (\bb c -> bb {dbbrPerasCert = c})
131144

132145
deriving instance (Typeable era, NoThunks (Tx TopTx era)) => NoThunks (DijkstraBlockBodyRaw era)
@@ -153,13 +166,17 @@ instance Memoized (DijkstraBlockBody era) where
153166
pattern DijkstraBlockBody ::
154167
AlonzoEraTx era =>
155168
StrictSeq (Tx TopTx era) ->
169+
StrictMaybe LeiosCert ->
156170
StrictMaybe PerasCert ->
157171
DijkstraBlockBody era
158-
pattern DijkstraBlockBody txs perasCert <- (getMemoRawType -> DijkstraBlockBodyRaw txs perasCert)
172+
pattern DijkstraBlockBody txs mbLeiosCert mbPerasCert <-
173+
( getMemoRawType ->
174+
DijkstraBlockBodyRaw txs mbLeiosCert mbPerasCert
175+
)
159176
where
160-
DijkstraBlockBody txs perasCert =
177+
DijkstraBlockBody txs leiosCert perasCert =
161178
mkMemoizedEra @DijkstraEra $
162-
DijkstraBlockBodyRaw txs perasCert
179+
DijkstraBlockBodyRaw txs leiosCert perasCert
163180

164181
{-# COMPLETE DijkstraBlockBody #-}
165182

@@ -173,14 +190,15 @@ instance
173190
) =>
174191
EncCBOR (DijkstraBlockBodyRaw era)
175192
where
176-
encCBOR (DijkstraBlockBodyRaw txs perasCert) =
177-
encodeListLen 3
178-
<> encodeNullStrictMaybe encCBOR invalidIndices
193+
encCBOR (DijkstraBlockBodyRaw txs mbLeiosCert mbPerasCert) =
194+
encodeListLen 4
195+
<> encodeNullMaybe encCBOR invalidIndices
179196
<> encCBOR txs
180-
<> encodeNullStrictMaybe encCBOR perasCert
197+
<> encodeNullStrictMaybe encodeLeiosCert mbLeiosCert
198+
<> encodeNullStrictMaybe encCBOR mbPerasCert
181199
where
182200
invalidIndices =
183-
maybeToStrictMaybe . NonEmptySet.fromFoldable $
201+
NonEmptySet.fromFoldable $
184202
StrictSeq.findIndicesL (\tx -> tx ^. isValidTxL == IsValid False) txs
185203

186204
instance
@@ -192,16 +210,19 @@ instance
192210
) =>
193211
DecCBOR (Annotator (DijkstraBlockBodyRaw era))
194212
where
195-
decCBOR = decodeRecordNamed "DijkstraBlockBodyRaw" (const 3) $ do
213+
decCBOR = decodeRecordNamed "DijkstraBlockBodyRaw" (const 4) $ do
196214
let
197215
decodeInvalidTxs =
198216
decodeNonEmptySetLikeEnforceNoDuplicates
199217
(IntSet.insert . fromIntegral @Word16 @Int)
200218
(\x -> (IntSet.size x, x))
201219
(decCBOR @Word16)
220+
202221
invalidTxs :: IntSet <- fold <$> decodeNullMaybe decodeInvalidTxs
203222
txs <- decodeSeq (decodeDijkstraTopTx @era False)
204-
perasCert <- decodeNullStrictMaybe decCBOR
223+
mbLeiosCert <- decodeNullStrictMaybe decodeLeiosCert
224+
mbPerasCert <- decodeNullStrictMaybe decCBOR
225+
205226
let txsLength = Seq.length txs
206227
inRange x = 0 <= x && x < txsLength
207228
forM_ (IntSet.toList invalidTxs) $ \i ->
@@ -214,7 +235,8 @@ instance
214235
pure $
215236
DijkstraBlockBodyRaw
216237
<$> sequenceA (StrictSeq.forceToStrict txsWithIsValid)
217-
<*> pure perasCert
238+
<*> pure mbLeiosCert
239+
<*> pure mbPerasCert
218240

219241
deriving via
220242
Mem (DijkstraBlockBodyRaw era)
@@ -228,8 +250,16 @@ deriving via
228250
DecCBOR (Annotator (DijkstraBlockBody era))
229251

230252
instance (AlonzoEraTx era, EncCBOR (Tx TopTx era)) => EncCBORGroup (DijkstraBlockBody era) where
231-
encCBORGroup (DijkstraBlockBody txs perasCert) = do
232-
encodeListLen 2 <> encCBOR txs <> encCBOR perasCert
253+
encCBORGroup (DijkstraBlockBody txs mbLeiosCert mbPerasCert) = do
254+
encodeListLen 4
255+
<> encodeNullMaybe encCBOR invalidIndices
256+
<> encCBOR txs
257+
<> encodeNullStrictMaybe encodeLeiosCert mbLeiosCert
258+
<> encodeNullStrictMaybe encCBOR mbPerasCert
259+
where
260+
invalidIndices =
261+
NonEmptySet.fromFoldable $
262+
StrictSeq.findIndicesL (\tx -> tx ^. isValidTxL == IsValid False) txs
233263
listLen _ = 1
234264

235265
--------------------------------------------------------------------------------

eras/dijkstra/impl/test/Test/Cardano/Ledger/Dijkstra/Binary/CddlSpec.hs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ import Test.Cardano.Ledger.Core.Binary (
3737
)
3838
import Test.Cardano.Ledger.Dijkstra.Arbitrary (
3939
genNonEmptyAccountBalanceIntervals,
40-
genSmallDijkstraBlockBody,
40+
genSmallDijkstraCertBlockBody,
41+
genSmallDijkstraTxsBlockBody,
4142
)
4243
import Test.Cardano.Ledger.Dijkstra.Binary.Annotator ()
4344

@@ -46,7 +47,10 @@ spec = do
4647
describe "CDDL" $ do
4748
let v = eraProtVerHigh @DijkstraEra
4849
describe "Huddle" $ specWithHuddle dijkstraCDDL . noTwiddle $ do
49-
fullAnnGenCddlSpec @(BlockBody DijkstraEra) genSmallDijkstraBlockBody v "block_body"
50+
describe "TxsRB" $
51+
fullAnnGenCddlSpec @(BlockBody DijkstraEra) genSmallDijkstraTxsBlockBody v "block_body"
52+
describe "CertRB" $
53+
fullAnnGenCddlSpec @(BlockBody DijkstraEra) genSmallDijkstraCertBlockBody v "block_body"
5054
fullCddlSpec @(AccountBalanceInterval DijkstraEra) v "account_balance_interval"
5155
fullGenCddlSpec @(AccountBalanceIntervals DijkstraEra)
5256
genNonEmptyAccountBalanceIntervals

0 commit comments

Comments
 (0)