{-# LANGUAGE TemplateHaskell #-}

-- | KZG trusted setup parameters for Hydra's accumulator-based partial fanout.
--
-- = Background
--
-- Hydra's partial fanout uses KZG polynomial commitments to prove on-chain that
-- a distributed batch of UTxOs is a genuine subset of the UTxOs committed in the
-- Closed head datum. The accumulator polynomial encodes all snapshot UTxOs as roots:
--
-- > A(X) = ∏ (X − sᵢ)   where sᵢ = hash(TxOutᵢ)
--
-- The __accumulator commitment__ is @A(τ)·G1@ — a single G1 point (48 bytes) stored
-- in the Closed datum. The __membership proof__ for a distributed subset @S@ is the
-- quotient @Q(X) = A(X) / P_S(X)@ committed as @Q(τ)·G1@. The on-chain validator
-- verifies the pairing identity:
--
-- > e(A(τ)·G1, G2) = e(Q(τ)·G1, P_S(τ)·G2)
--
-- where @P_S(τ)·G2@ is computed on-chain via a G2 MSM using the on-chain G2 CRS.
--
-- = The Trusted Setup
--
-- Computing @A(τ)·G1@ and @Q(τ)·G1@ off-chain, and @P_S(τ)·G2@ on-chain, all
-- require the same secret @τ@ (powers of tau). We embed the __EIP-4844 KZG
-- trusted setup__ produced by the Ethereum KZG ceremony (2023):
--
--   * Source: <https://github.com/ethereum/kzg-ceremony-verifier/tree/master/output_setups>
--   * Ceremony: <https://ceremony.ethereum.org/>
--   * ~140,000 independent participants; secure as long as one destroyed their secret
--   * We use the @g1_monomial@ and @g2_monomial@ keys (not @g1_lagrange@, which is
--     for Ethereum blob commitments and is unsuitable here)
--
-- The setup provides:
--
--   * 4096 G1 points @[G1, τ·G1, ..., τ^4095·G1]@ — used off-chain to build the
--     accumulator commitment and membership proofs
--   * 65 G2 points  @[G2, τ·G2, ..., τ^64·G2]@   — used as the on-chain
--     verification CRS (G2 MSM to evaluate @P_S(τ)·G2@)
--
-- = Accumulator size limit
--
-- The accumulator polynomial has degree n (one root per UTxO). Computing @A(τ)·G1@
-- off-chain needs n+1 G1 points. EIP-4844 provides 4096 G1 points, so a head can
-- hold up to __4095 UTxOs__. This is enforced by 'maxAccumulatorSize'.
-- The on-chain G2 CRS only needs batch-size-many points per partial fanout step,
-- so the 65 G2 points do not constrain the accumulator size.
module Hydra.Contract.KZGTrustedSetup (
  KZGSetupError (..),
  warmup,
  g1Points,
  g2Points,
  g1BuiltinPoints,
  g2BuiltinPoints,
  maxAccumulatorSize,
  maxFanoutBatchSize,
  defaultItems,
  canonicalG2Points,
) where

import Hydra.Prelude hiding (filter, foldMap, isJust, map, (<$>), (==))

import Cardano.Crypto.EllipticCurve.BLS12_381.Internal (Point1, Point2, blsCompress, blsUncompress)
import Cardano.Crypto.Hash (SHA256)
import Cardano.Crypto.Hash.Class (HashAlgorithm (digest))
import Data.Aeson qualified as Aeson
import Data.Aeson.Types (Parser, parseEither, withObject, (.:))
import Data.ByteString.Base16 qualified as Base16
import Data.FileEmbed (embedFile, makeRelativeToProject)
import Data.Text qualified as T
import PlutusTx.Builtins (BuiltinBLS12_381_G1_Element, BuiltinBLS12_381_G2_Element, bls12_381_G1_uncompress, bls12_381_G2_uncompress, toBuiltin)

-- | Errors that can occur when loading the embedded KZG trusted setup.
--
-- In practice these should never occur — the trusted setup JSON is embedded at
-- compile time and its integrity is validated by the test suite. A 'Left' here
-- would indicate binary tampering ('IntegrityCheckFailed') or a corrupted
-- build artefact.
data KZGSetupError
  = -- | SHA-256 digest of the embedded file does not match the known-good value.
    IntegrityCheckFailed
      { KZGSetupError -> Text
expectedHash :: Text
      , KZGSetupError -> Text
actualHash :: Text
      }
  | -- | The embedded bytes could not be decoded as JSON at all.
    JsonDecodeFailed
  | -- | The JSON decoded but failed the structural parser (missing keys etc.).
    JsonParseFailed {KZGSetupError -> Text
parseError :: Text}
  | -- | A G1 point hex string could not be hex-decoded or BLS-decompressed.
    InvalidG1Point {KZGSetupError -> Text
hexPoint :: Text}
  | -- | A G2 point hex string could not be hex-decoded or BLS-decompressed.
    InvalidG2Point {hexPoint :: Text}
  deriving stock (Int -> KZGSetupError -> ShowS
[KZGSetupError] -> ShowS
KZGSetupError -> String
(Int -> KZGSetupError -> ShowS)
-> (KZGSetupError -> String)
-> ([KZGSetupError] -> ShowS)
-> Show KZGSetupError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> KZGSetupError -> ShowS
showsPrec :: Int -> KZGSetupError -> ShowS
$cshow :: KZGSetupError -> String
show :: KZGSetupError -> String
$cshowList :: [KZGSetupError] -> ShowS
showList :: [KZGSetupError] -> ShowS
Show, KZGSetupError -> KZGSetupError -> Bool
(KZGSetupError -> KZGSetupError -> Bool)
-> (KZGSetupError -> KZGSetupError -> Bool) -> Eq KZGSetupError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: KZGSetupError -> KZGSetupError -> Bool
== :: KZGSetupError -> KZGSetupError -> Bool
$c/= :: KZGSetupError -> KZGSetupError -> Bool
/= :: KZGSetupError -> KZGSetupError -> Bool
Eq, (forall x. KZGSetupError -> Rep KZGSetupError x)
-> (forall x. Rep KZGSetupError x -> KZGSetupError)
-> Generic KZGSetupError
forall x. Rep KZGSetupError x -> KZGSetupError
forall x. KZGSetupError -> Rep KZGSetupError x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. KZGSetupError -> Rep KZGSetupError x
from :: forall x. KZGSetupError -> Rep KZGSetupError x
$cto :: forall x. Rep KZGSetupError x -> KZGSetupError
to :: forall x. Rep KZGSetupError x -> KZGSetupError
Generic)

-- | Maximum accumulator element count supported by the currently embedded G1 CRS.
-- The EIP-4844 setup provides exactly 4096 G1 monomial points [G1, τ·G1, ..., τ^4095·G1],
-- so the accumulator supports up to 4095 elements (n elements need n+1 G1 points).
maxAccumulatorSize :: Int
maxAccumulatorSize :: Int
maxAccumulatorSize = Int
4095

-- | Theoretical upper bound on partial fanout batch size, derived from the
-- embedded EIP-4844 trusted setup: 65 G2 monomial points give room for a
-- polynomial of degree 64 (one (X - sᵢ) factor per fanned-out element).
--
-- NOTE: this is the __ceiling__ implied by the trusted-setup file, not the
-- __deployed__ cap. The on-chain CRS UTxO only embeds the first
-- 'Hydra.Tx.Accumulator.defaultItems' G2 points, so the production batch
-- limit is currently @defaultItems - 1@. Raising the deployed cap requires
-- re-publishing the CRS UTxO with more G2 points (bounded above by this
-- value).
maxFanoutBatchSize :: Int
maxFanoutBatchSize :: Int
maxFanoutBatchSize = Int
64

-- | Expected SHA-256 of trusted_setup.json, from the EIP-4844 ceremony output.
-- Verify independently with: sha256sum hydra-tx/trusted_setup.json
-- Source: https://github.com/ethereum/kzg-ceremony-verifier/tree/master/output_setups
trustedSetupExpectedSHA256 :: Text
trustedSetupExpectedSHA256 :: Text
trustedSetupExpectedSHA256 = Text
"9a8dcad9eaba191842f57d23d14674cbdea4b3cf7912fcc477821264dfe0c042"

-- We use @g1_monomial@ (not @g1_lagrange@): the monomial form @[G1, τ·G1, ...]@ is required
-- for KZG polynomial commitments. The @g1_lagrange@ form (used by Ethereum clients for blob
-- commitments) is NOT suitable for the accumulator scheme here.
embeddedSetup :: Either KZGSetupError ([Text], [Text])
embeddedSetup :: Either KZGSetupError ([Text], [Text])
embeddedSetup = do
  let rawBytes :: ByteString
rawBytes = $(makeRelativeToProject "trusted_setup.json" >>= embedFile)
      actualHex :: Text
actualHex = ByteString -> Text
forall a b. ConvertUtf8 a b => b -> a
decodeUtf8 (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
Base16.encode (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ Proxy SHA256 -> ByteString -> ByteString
forall h (proxy :: * -> *).
HashAlgorithm h =>
proxy h -> ByteString -> ByteString
forall (proxy :: * -> *). proxy SHA256 -> ByteString -> ByteString
digest (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @SHA256) ByteString
rawBytes
  Bool -> Either KZGSetupError () -> Either KZGSetupError ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Text
actualHex Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
/= Text
trustedSetupExpectedSHA256) (Either KZGSetupError () -> Either KZGSetupError ())
-> Either KZGSetupError () -> Either KZGSetupError ()
forall a b. (a -> b) -> a -> b
$
    KZGSetupError -> Either KZGSetupError ()
forall a b. a -> Either a b
Left IntegrityCheckFailed{expectedHash :: Text
expectedHash = Text
trustedSetupExpectedSHA256, actualHash :: Text
actualHash = Text
actualHex}
  Value
v <- Either KZGSetupError Value
-> (Value -> Either KZGSetupError Value)
-> Maybe Value
-> Either KZGSetupError Value
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (KZGSetupError -> Either KZGSetupError Value
forall a b. a -> Either a b
Left KZGSetupError
JsonDecodeFailed) Value -> Either KZGSetupError Value
forall a b. b -> Either a b
Right (ByteString -> Maybe Value
forall a. FromJSON a => ByteString -> Maybe a
Aeson.decodeStrict ByteString
rawBytes)
  (String -> KZGSetupError)
-> Either String ([Text], [Text])
-> Either KZGSetupError ([Text], [Text])
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (Text -> KZGSetupError
JsonParseFailed (Text -> KZGSetupError)
-> (String -> Text) -> String -> KZGSetupError
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
forall a. ToText a => a -> Text
toText) (Either String ([Text], [Text])
 -> Either KZGSetupError ([Text], [Text]))
-> Either String ([Text], [Text])
-> Either KZGSetupError ([Text], [Text])
forall a b. (a -> b) -> a -> b
$
    (Value -> Parser ([Text], [Text]))
-> Value -> Either String ([Text], [Text])
forall a b. (a -> Parser b) -> a -> Either String b
parseEither (String
-> (Object -> Parser ([Text], [Text]))
-> Value
-> Parser ([Text], [Text])
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"TrustedSetup" Object -> Parser ([Text], [Text])
parse) Value
v
 where
  parse :: Aeson.Object -> Parser ([Text], [Text])
  parse :: Object -> Parser ([Text], [Text])
parse Object
obj = ([Text] -> [Text] -> ([Text], [Text]))
-> Parser [Text] -> Parser ([Text] -> ([Text], [Text]))
forall a b. (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (,) (Object
obj Object -> Key -> Parser [Text]
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"g1_monomial") Parser ([Text] -> ([Text], [Text]))
-> Parser [Text] -> Parser ([Text], [Text])
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
obj Object -> Key -> Parser [Text]
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"g2_monomial"

decodeHexPoint :: Text -> Either String ByteString
decodeHexPoint :: Text -> Either String ByteString
decodeHexPoint Text
t = ByteString -> Either String ByteString
Base16.decode (ByteString -> Either String ByteString)
-> ByteString -> Either String ByteString
forall a b. (a -> b) -> a -> b
$ Text -> ByteString
forall a b. ConvertUtf8 a b => a -> b
encodeUtf8 (Text -> ByteString) -> Text -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
t (Text -> Text -> Maybe Text
T.stripPrefix Text
"0x" Text
t)

-- | Force the whole embedded trusted setup into memory, yielding the number of
-- G1 points loaded.
--
-- Both halves are forced: the G1 CRS the off-chain commitment path consumes,
-- and the G2 CRS behind 'canonicalG2Points', which the head validator binds.
-- A caller gets a corrupt setup as a 'Left' here rather than as the 'error'
-- those two would otherwise raise from pure code, mid-session.
--
-- The forcing lives in this module on purpose. 'g1Points' currently
-- decompresses every point just to decide between 'Left' and 'Right', so any
-- 'WHNF' happens to do the work — but that is a property of the
-- representation, not a promise. Should either list become a lazy structure,
-- this is the one place obliged to keep forcing, rather than a caller's
-- 'length' silently degenerating into a spine walk.
warmup :: Either KZGSetupError Int
warmup :: Either KZGSetupError Int
warmup = do
  [Point1]
g1 <- Either KZGSetupError [Point1]
g1Points
  [Point2]
g2 <- Either KZGSetupError [Point2]
g2Points
  let !numG1 :: Int
numG1 = [Point1] -> Int
forall a. [a] -> Int
countForced [Point1]
g1
      !numG2 :: Int
numG2 = [Point2] -> Int
forall a. [a] -> Int
countForced [Point2]
g2
  Int
numG2 Int -> Either KZGSetupError Int -> Either KZGSetupError Int
forall a b. a -> b -> b
`seq` Int -> Either KZGSetupError Int
forall a b. b -> Either a b
Right Int
numG1
 where
  countForced :: [a] -> Int
  countForced :: forall a. [a] -> Int
countForced = (Int -> a -> Int) -> Int -> [a] -> Int
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (\Int
n a
x -> a
x a -> Int -> Int
forall a b. a -> b -> b
`seq` Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
0

-- | G1 powers of tau [G1, τ·G1, ..., τ^4095·G1] from the EIP-4844 ceremony (monomial form).
-- 4096 points; used off-chain to build accumulator commitments and membership proofs.
g1Points :: Either KZGSetupError [Point1]
g1Points :: Either KZGSetupError [Point1]
g1Points = (Text -> Either KZGSetupError Point1)
-> [Text] -> Either KZGSetupError [Point1]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Text -> Either KZGSetupError Point1
parseG1 ([Text] -> Either KZGSetupError [Point1])
-> (([Text], [Text]) -> [Text])
-> ([Text], [Text])
-> Either KZGSetupError [Point1]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Text], [Text]) -> [Text]
forall a b. (a, b) -> a
fst (([Text], [Text]) -> Either KZGSetupError [Point1])
-> Either KZGSetupError ([Text], [Text])
-> Either KZGSetupError [Point1]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Either KZGSetupError ([Text], [Text])
embeddedSetup
 where
  parseG1 :: Text -> Either KZGSetupError Point1
  parseG1 :: Text -> Either KZGSetupError Point1
parseG1 Text
hex = do
    ByteString
bs <- (String -> KZGSetupError)
-> Either String ByteString -> Either KZGSetupError ByteString
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (KZGSetupError -> String -> KZGSetupError
forall a b. a -> b -> a
const (Text -> KZGSetupError
InvalidG1Point Text
hex)) (Text -> Either String ByteString
decodeHexPoint Text
hex)
    (BLSTError -> KZGSetupError)
-> Either BLSTError Point1 -> Either KZGSetupError Point1
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (KZGSetupError -> BLSTError -> KZGSetupError
forall a b. a -> b -> a
const (Text -> KZGSetupError
InvalidG1Point Text
hex)) (ByteString -> Either BLSTError Point1
forall curve.
BLS curve =>
ByteString -> Either BLSTError (Point curve)
blsUncompress ByteString
bs)

-- | G2 powers of tau [G2, τ·G2, ..., τ^64·G2] from the EIP-4844 ceremony (monomial form).
-- 65 points; used as the on-chain verification CRS (G2 MSM to evaluate @P_S(τ)·G2@).
g2Points :: Either KZGSetupError [Point2]
g2Points :: Either KZGSetupError [Point2]
g2Points = (Text -> Either KZGSetupError Point2)
-> [Text] -> Either KZGSetupError [Point2]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Text -> Either KZGSetupError Point2
parseG2 ([Text] -> Either KZGSetupError [Point2])
-> (([Text], [Text]) -> [Text])
-> ([Text], [Text])
-> Either KZGSetupError [Point2]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Text], [Text]) -> [Text]
forall a b. (a, b) -> b
snd (([Text], [Text]) -> Either KZGSetupError [Point2])
-> Either KZGSetupError ([Text], [Text])
-> Either KZGSetupError [Point2]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Either KZGSetupError ([Text], [Text])
embeddedSetup
 where
  parseG2 :: Text -> Either KZGSetupError Point2
  parseG2 :: Text -> Either KZGSetupError Point2
parseG2 Text
hex = do
    ByteString
bs <- (String -> KZGSetupError)
-> Either String ByteString -> Either KZGSetupError ByteString
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (KZGSetupError -> String -> KZGSetupError
forall a b. a -> b -> a
const (Text -> KZGSetupError
InvalidG2Point Text
hex)) (Text -> Either String ByteString
decodeHexPoint Text
hex)
    (BLSTError -> KZGSetupError)
-> Either BLSTError Point2 -> Either KZGSetupError Point2
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (KZGSetupError -> BLSTError -> KZGSetupError
forall a b. a -> b -> a
const (Text -> KZGSetupError
InvalidG2Point Text
hex)) (ByteString -> Either BLSTError Point2
forall curve.
BLS curve =>
ByteString -> Either BLSTError (Point curve)
blsUncompress ByteString
bs)

-- | G1 points as Plutus built-in type, for use in off-chain accumulator commitment.
-- Derived from 'g1Points' by re-compressing to bytes; shares the same parsed data.
g1BuiltinPoints :: Either KZGSetupError [BuiltinBLS12_381_G1_Element]
g1BuiltinPoints :: Either KZGSetupError [BuiltinBLS12_381_G1_Element]
g1BuiltinPoints = ([Point1] -> [BuiltinBLS12_381_G1_Element])
-> Either KZGSetupError [Point1]
-> Either KZGSetupError [BuiltinBLS12_381_G1_Element]
forall a b.
(a -> b) -> Either KZGSetupError a -> Either KZGSetupError b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Point1 -> BuiltinBLS12_381_G1_Element)
-> [Point1] -> [BuiltinBLS12_381_G1_Element]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (BuiltinByteString -> BuiltinBLS12_381_G1_Element
bls12_381_G1_uncompress (BuiltinByteString -> BuiltinBLS12_381_G1_Element)
-> (Point1 -> BuiltinByteString)
-> Point1
-> BuiltinBLS12_381_G1_Element
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> BuiltinByteString
ByteString -> ToBuiltin ByteString
forall a. HasToBuiltin a => a -> ToBuiltin a
toBuiltin (ByteString -> BuiltinByteString)
-> (Point1 -> ByteString) -> Point1 -> BuiltinByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Point1 -> ByteString
forall curve. BLS curve => Point curve -> ByteString
blsCompress)) Either KZGSetupError [Point1]
g1Points

-- | G2 points as Plutus built-in type, for use in on-chain verification CRS.
-- Derived from 'g2Points' by re-compressing to bytes; shares the same parsed data.
g2BuiltinPoints :: Either KZGSetupError [BuiltinBLS12_381_G2_Element]
g2BuiltinPoints :: Either KZGSetupError [BuiltinBLS12_381_G2_Element]
g2BuiltinPoints = ([Point2] -> [BuiltinBLS12_381_G2_Element])
-> Either KZGSetupError [Point2]
-> Either KZGSetupError [BuiltinBLS12_381_G2_Element]
forall a b.
(a -> b) -> Either KZGSetupError a -> Either KZGSetupError b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Point2 -> BuiltinBLS12_381_G2_Element)
-> [Point2] -> [BuiltinBLS12_381_G2_Element]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (BuiltinByteString -> BuiltinBLS12_381_G2_Element
bls12_381_G2_uncompress (BuiltinByteString -> BuiltinBLS12_381_G2_Element)
-> (Point2 -> BuiltinByteString)
-> Point2
-> BuiltinBLS12_381_G2_Element
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> BuiltinByteString
ByteString -> ToBuiltin ByteString
forall a. HasToBuiltin a => a -> ToBuiltin a
toBuiltin (ByteString -> BuiltinByteString)
-> (Point2 -> ByteString) -> Point2 -> BuiltinByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Point2 -> ByteString
forall curve. BLS curve => Point curve -> ByteString
blsCompress)) Either KZGSetupError [Point2]
g2Points

-- | Number of G2 monomial points published in the on-chain CRS reference UTxO
-- (see 'Hydra.Tx.Accumulator.createCRSG2Datum'), hence the size of the canonical CRS
-- datum the head validator binds. Bounded above by 'maxFanoutBatchSize' + 1; raising
-- it requires re-publishing the CRS UTxO.
defaultItems :: Int
defaultItems :: Int
defaultItems = Int
30

-- | The canonical on-chain CRS datum: the first 'defaultItems' G2 monomial points of
-- the embedded EIP-4844 setup, as the on-chain builtin element type. This is exactly
-- what 'Hydra.Tx.Accumulator.createCRSG2Datum' publishes and what the head validator
-- binds via its baked datum hash. Errors only if the embedded setup is corrupt.
canonicalG2Points :: [BuiltinBLS12_381_G2_Element]
canonicalG2Points :: [BuiltinBLS12_381_G2_Element]
canonicalG2Points =
  Int
-> [BuiltinBLS12_381_G2_Element] -> [BuiltinBLS12_381_G2_Element]
forall a. Int -> [a] -> [a]
take Int
defaultItems ([BuiltinBLS12_381_G2_Element] -> [BuiltinBLS12_381_G2_Element])
-> [BuiltinBLS12_381_G2_Element] -> [BuiltinBLS12_381_G2_Element]
forall a b. (a -> b) -> a -> b
$
    (KZGSetupError -> [BuiltinBLS12_381_G2_Element])
-> ([BuiltinBLS12_381_G2_Element] -> [BuiltinBLS12_381_G2_Element])
-> Either KZGSetupError [BuiltinBLS12_381_G2_Element]
-> [BuiltinBLS12_381_G2_Element]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (\KZGSetupError
e -> Text -> [BuiltinBLS12_381_G2_Element]
forall a t. (HasCallStack, IsText t) => t -> a
error (Text -> [BuiltinBLS12_381_G2_Element])
-> Text -> [BuiltinBLS12_381_G2_Element]
forall a b. (a -> b) -> a -> b
$ Text
"KZG trusted setup invariant violated: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> KZGSetupError -> Text
forall b a. (Show a, IsString b) => a -> b
show KZGSetupError
e) [BuiltinBLS12_381_G2_Element] -> [BuiltinBLS12_381_G2_Element]
forall a. a -> a
id Either KZGSetupError [BuiltinBLS12_381_G2_Element]
g2BuiltinPoints