{-# LANGUAGE AllowAmbiguousTypes #-}
module Hydra.Tx.Accumulator (
HydraAccumulator,
unHydraAccumulator,
getAccumulatorHash,
getAccumulatorCommitment,
computeG1CommitmentBytes,
accumulatorSize,
maxAccumulatorSize,
build,
buildFromUTxO,
buildFromSnapshotUTxOs,
applyUTxODelta,
crsG2Points,
crsG1Points,
requiredCRSPointCount,
defaultItems,
createMembershipProof,
createMembershipProofFromUTxO,
createCRSG2Datum,
) where
import Hydra.Prelude hiding (show)
import Accumulator (Accumulator, Element)
import Accumulator qualified
import Bindings (getPolyCommitOverG1)
import Cardano.Api (BabbageEraOnwards (..), TxOutDatum (TxOutDatumInline))
import Cardano.Crypto.EllipticCurve.BLS12_381.Internal (Point1, Point2, blsCompress)
import Cardano.Crypto.Hash (Blake2b_256)
import Cardano.Crypto.Hash.Class (HashAlgorithm (digest))
import Data.Map.Strict qualified as Map
import Hydra.Cardano.Api qualified as HApi
import Hydra.Contract.KZGTrustedSetup qualified as KZG
import Hydra.Tx.IsTx (IsTx (..))
import PlutusTx.Builtins (
BuiltinBLS12_381_G1_Element,
bls12_381_G1_uncompress,
bls12_381_G2_uncompress,
toBuiltin,
)
import Text.Show (Show (..))
data HydraAccumulator = HydraAccumulator
{ HydraAccumulator -> Accumulator
unHydraAccumulator :: Accumulator
, HydraAccumulator -> ByteString
_cachedCommitment :: ByteString
, HydraAccumulator -> ByteString
_cachedHash :: ByteString
}
instance Show HydraAccumulator where
show :: HydraAccumulator -> String
show HydraAccumulator{$sel:unHydraAccumulator:HydraAccumulator :: HydraAccumulator -> Accumulator
unHydraAccumulator = Accumulator
acc} =
String
"HydraAccumulator " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Accumulator -> String
forall a. Show a => a -> String
show Accumulator
acc
instance Eq HydraAccumulator where
HydraAccumulator
a == :: HydraAccumulator -> HydraAccumulator -> Bool
== HydraAccumulator
b = HydraAccumulator -> Accumulator
unHydraAccumulator HydraAccumulator
a Accumulator -> Accumulator -> Bool
forall a. Eq a => a -> a -> Bool
== HydraAccumulator -> Accumulator
unHydraAccumulator HydraAccumulator
b
mkHydraAccumulator :: Accumulator -> HydraAccumulator
mkHydraAccumulator :: Accumulator -> HydraAccumulator
mkHydraAccumulator Accumulator
acc = Accumulator -> ByteString -> ByteString -> HydraAccumulator
HydraAccumulator Accumulator
acc ByteString
cachedCommitment ByteString
cachedHash
where
cachedCommitment :: ByteString
cachedCommitment = Accumulator -> ByteString
computeG1CommitmentBytes Accumulator
acc
cachedHash :: ByteString
cachedHash = Proxy Blake2b_256 -> ByteString -> ByteString
forall h (proxy :: * -> *).
HashAlgorithm h =>
proxy h -> ByteString -> ByteString
forall (proxy :: * -> *).
proxy Blake2b_256 -> ByteString -> ByteString
digest (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @Blake2b_256) ByteString
cachedCommitment
build :: [ByteString] -> HydraAccumulator
build :: [ByteString] -> HydraAccumulator
build = Accumulator -> HydraAccumulator
mkHydraAccumulator (Accumulator -> HydraAccumulator)
-> ([ByteString] -> Accumulator)
-> [ByteString]
-> HydraAccumulator
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> Accumulator
Accumulator.buildAccumulator
buildFromUTxO ::
forall tx.
IsTx tx =>
UTxOType tx ->
HydraAccumulator
buildFromUTxO :: forall tx. IsTx tx => UTxOType tx -> HydraAccumulator
buildFromUTxO UTxOType tx
utxo =
let elements :: [ByteString]
elements = forall tx. IsTx tx => TxOutType tx -> ByteString
utxoToElement @tx (TxOutType tx -> ByteString) -> [TxOutType tx] -> [ByteString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall tx. IsTx tx => UTxOType tx -> [TxOutType tx]
outputsOfUTxO @tx UTxOType tx
utxo
in [ByteString] -> HydraAccumulator
build [ByteString]
elements
buildFromSnapshotUTxOs ::
forall tx.
IsTx tx =>
UTxOType tx ->
Maybe (UTxOType tx) ->
Maybe (UTxOType tx) ->
HydraAccumulator
buildFromSnapshotUTxOs :: forall tx.
IsTx tx =>
UTxOType tx
-> Maybe (UTxOType tx) -> Maybe (UTxOType tx) -> HydraAccumulator
buildFromSnapshotUTxOs UTxOType tx
utxo Maybe (UTxOType tx)
mUtxoToCommit Maybe (UTxOType tx)
mUtxoToDecommit =
forall tx. IsTx tx => UTxOType tx -> HydraAccumulator
buildFromUTxO @tx (UTxOType tx -> HydraAccumulator)
-> UTxOType tx -> HydraAccumulator
forall a b. (a -> b) -> a -> b
$
UTxOType tx
utxo
UTxOType tx -> UTxOType tx -> UTxOType tx
forall a. Semigroup a => a -> a -> a
<> UTxOType tx -> Maybe (UTxOType tx) -> UTxOType tx
forall a. a -> Maybe a -> a
fromMaybe UTxOType tx
forall a. Monoid a => a
mempty Maybe (UTxOType tx)
mUtxoToCommit
UTxOType tx -> UTxOType tx -> UTxOType tx
forall a. Semigroup a => a -> a -> a
<> UTxOType tx -> Maybe (UTxOType tx) -> UTxOType tx
forall a. a -> Maybe a -> a
fromMaybe UTxOType tx
forall a. Monoid a => a
mempty Maybe (UTxOType tx)
mUtxoToDecommit
applyUTxODelta ::
forall tx.
IsTx tx =>
HydraAccumulator ->
UTxOType tx ->
UTxOType tx ->
HydraAccumulator
applyUTxODelta :: forall tx.
IsTx tx =>
HydraAccumulator -> UTxOType tx -> UTxOType tx -> HydraAccumulator
applyUTxODelta HydraAccumulator
prevAcc UTxOType tx
prevUTxO UTxOType tx
nextUTxO
| Bool
removalsCovered =
Accumulator -> HydraAccumulator
mkHydraAccumulator (Accumulator -> HydraAccumulator)
-> Accumulator -> HydraAccumulator
forall a b. (a -> b) -> a -> b
$
(Accumulator -> ByteString -> Accumulator)
-> Accumulator -> [ByteString] -> Accumulator
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' ((ByteString -> Accumulator -> Accumulator)
-> Accumulator -> ByteString -> Accumulator
forall a b c. (a -> b -> c) -> b -> a -> c
flip ByteString -> Accumulator -> Accumulator
Accumulator.removeElement) ((Accumulator -> ByteString -> Accumulator)
-> Accumulator -> [ByteString] -> Accumulator
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Accumulator -> ByteString -> Accumulator
Accumulator.addElement Accumulator
prev [ByteString]
addedEls) [ByteString]
removedEls
| Bool
otherwise = forall tx. IsTx tx => UTxOType tx -> HydraAccumulator
buildFromUTxO @tx UTxOType tx
nextUTxO
where
prev :: Accumulator
prev = HydraAccumulator -> Accumulator
unHydraAccumulator HydraAccumulator
prevAcc
removalsCovered :: Bool
removalsCovered =
(Int -> (ByteString, Int) -> Bool)
-> Map ByteString Int -> Accumulator -> Bool
forall k a b.
Ord k =>
(a -> b -> Bool) -> Map k a -> Map k b -> Bool
Map.isSubmapOfBy (\Int
needed (ByteString
_, Int
held) -> Int
needed Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
held) Map ByteString Int
removedCounts Accumulator
prev
removedCounts :: Map ByteString Int
removedCounts = (Int -> Int -> Int) -> [(ByteString, Int)] -> Map ByteString Int
forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith Int -> Int -> Int
forall a. Num a => a -> a -> a
(+) [(ByteString
el, Int
1 :: Int) | ByteString
el <- [ByteString]
removedEls]
removedEls :: [ByteString]
removedEls = forall tx. IsTx tx => TxOutType tx -> ByteString
utxoToElement @tx (TxOutType tx -> ByteString) -> [TxOutType tx] -> [ByteString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall tx. IsTx tx => UTxOType tx -> [TxOutType tx]
outputsOfUTxO @tx (UTxOType tx
prevUTxO UTxOType tx -> UTxOType tx -> UTxOType tx
forall tx. IsTx tx => UTxOType tx -> UTxOType tx -> UTxOType tx
`withoutUTxO` UTxOType tx
nextUTxO)
addedEls :: [ByteString]
addedEls = forall tx. IsTx tx => TxOutType tx -> ByteString
utxoToElement @tx (TxOutType tx -> ByteString) -> [TxOutType tx] -> [ByteString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall tx. IsTx tx => UTxOType tx -> [TxOutType tx]
outputsOfUTxO @tx (UTxOType tx
nextUTxO UTxOType tx -> UTxOType tx -> UTxOType tx
forall tx. IsTx tx => UTxOType tx -> UTxOType tx -> UTxOType tx
`withoutUTxO` UTxOType tx
prevUTxO)
getAccumulatorHash :: HydraAccumulator -> ByteString
getAccumulatorHash :: HydraAccumulator -> ByteString
getAccumulatorHash = HydraAccumulator -> ByteString
_cachedHash
accumulatorSize :: HydraAccumulator -> Int
accumulatorSize :: HydraAccumulator -> Int
accumulatorSize = [Int] -> Int
forall a (f :: * -> *). (Foldable f, Num a) => f a -> a
sum ([Int] -> Int)
-> (HydraAccumulator -> [Int]) -> HydraAccumulator -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((ByteString, Int) -> Int) -> [(ByteString, Int)] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (ByteString, Int) -> Int
forall a b. (a, b) -> b
snd ([(ByteString, Int)] -> [Int])
-> (HydraAccumulator -> [(ByteString, Int)])
-> HydraAccumulator
-> [Int]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Accumulator -> [(ByteString, Int)]
forall k a. Map k a -> [a]
Map.elems (Accumulator -> [(ByteString, Int)])
-> (HydraAccumulator -> Accumulator)
-> HydraAccumulator
-> [(ByteString, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HydraAccumulator -> Accumulator
unHydraAccumulator
maxAccumulatorSize :: Int
maxAccumulatorSize :: Int
maxAccumulatorSize = Int
KZG.maxAccumulatorSize
fromKZGSetup :: Either KZG.KZGSetupError a -> a
fromKZGSetup :: forall a. Either KZGSetupError a -> a
fromKZGSetup = (KZGSetupError -> a) -> (a -> a) -> Either KZGSetupError a -> a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (\KZGSetupError
e -> Text -> a
forall a t. (HasCallStack, IsText t) => t -> a
error (Text -> a) -> (String -> Text) -> String -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
forall a. ToText a => a -> Text
toText (String -> a) -> String -> a
forall a b. (a -> b) -> a -> b
$ String
"KZG trusted setup invariant violated: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> KZGSetupError -> String
forall a. Show a => a -> String
show KZGSetupError
e) a -> a
forall a. a -> a
id
getAccumulatorCommitment :: HydraAccumulator -> BuiltinBLS12_381_G1_Element
getAccumulatorCommitment :: HydraAccumulator -> BuiltinBLS12_381_G1_Element
getAccumulatorCommitment = BuiltinByteString -> BuiltinBLS12_381_G1_Element
bls12_381_G1_uncompress (BuiltinByteString -> BuiltinBLS12_381_G1_Element)
-> (HydraAccumulator -> BuiltinByteString)
-> HydraAccumulator
-> 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)
-> (HydraAccumulator -> ByteString)
-> HydraAccumulator
-> BuiltinByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HydraAccumulator -> ByteString
_cachedCommitment
computeG1CommitmentBytes :: Accumulator -> ByteString
computeG1CommitmentBytes :: Accumulator -> ByteString
computeG1CommitmentBytes Accumulator
acc
| Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
KZG.maxAccumulatorSize =
Text -> ByteString
forall a t. (HasCallStack, IsText t) => t -> a
error (Text -> ByteString) -> (String -> Text) -> String -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
forall a. ToText a => a -> Text
toText (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ String
"getAccumulatorCommitment: accumulator has " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
n String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" elements, exceeding the G1 CRS limit of " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
KZG.maxAccumulatorSize
| Bool
otherwise =
(String -> ByteString)
-> (Point1 -> ByteString) -> Either String Point1 -> ByteString
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (\String
e -> Text -> ByteString
forall a t. (HasCallStack, IsText t) => t -> a
error (Text -> ByteString) -> Text -> ByteString
forall a b. (a -> b) -> a -> b
$ Text
"computeG1CommitmentBytes: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
forall a. ToText a => a -> Text
toText String
e) Point1 -> ByteString
forall curve. BLS curve => Point curve -> ByteString
blsCompress (Either String Point1 -> ByteString)
-> Either String Point1 -> ByteString
forall a b. (a -> b) -> a -> b
$
[ByteString] -> Accumulator -> [Point1] -> Either String Point1
getPolyCommitOverG1 [] Accumulator
acc (Int -> [Point1]
crsG1Points (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1))
where
n :: Int
n = [Int] -> Int
forall a (f :: * -> *). (Foldable f, Num a) => f a -> a
sum ((ByteString, Int) -> Int
forall a b. (a, b) -> b
snd ((ByteString, Int) -> Int) -> [(ByteString, Int)] -> [Int]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Accumulator -> [(ByteString, Int)]
forall k a. Map k a -> [a]
Map.elems Accumulator
acc)
crsG1Points :: Int -> [Point1]
crsG1Points :: Int -> [Point1]
crsG1Points Int
n = Int -> [Point1] -> [Point1]
forall a. Int -> [a] -> [a]
take Int
n ([Point1] -> [Point1]) -> [Point1] -> [Point1]
forall a b. (a -> b) -> a -> b
$ Either KZGSetupError [Point1] -> [Point1]
forall a. Either KZGSetupError a -> a
fromKZGSetup Either KZGSetupError [Point1]
KZG.g1Points
crsG2Points :: Int -> [Point2]
crsG2Points :: Int -> [Point2]
crsG2Points Int
n = Int -> [Point2] -> [Point2]
forall a. Int -> [a] -> [a]
take Int
n ([Point2] -> [Point2]) -> [Point2] -> [Point2]
forall a b. (a -> b) -> a -> b
$ Either KZGSetupError [Point2] -> [Point2]
forall a. Either KZGSetupError a -> a
fromKZGSetup Either KZGSetupError [Point2]
KZG.g2Points
defaultItems :: Int
defaultItems :: Int
defaultItems = Int
KZG.defaultItems
requiredCRSPointCount :: HydraAccumulator -> Int
requiredCRSPointCount :: HydraAccumulator -> Int
requiredCRSPointCount HydraAccumulator
ha = [Int] -> Int
forall a (f :: * -> *). (Foldable f, Num a) => f a -> a
sum (((ByteString, Int) -> Int) -> [(ByteString, Int)] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (ByteString, Int) -> Int
forall a b. (a, b) -> b
snd ([(ByteString, Int)] -> [Int]) -> [(ByteString, Int)] -> [Int]
forall a b. (a -> b) -> a -> b
$ Accumulator -> [(ByteString, Int)]
forall k a. Map k a -> [a]
Map.elems (Accumulator -> [(ByteString, Int)])
-> Accumulator -> [(ByteString, Int)]
forall a b. (a -> b) -> a -> b
$ HydraAccumulator -> Accumulator
unHydraAccumulator HydraAccumulator
ha) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
createMembershipProof ::
[Element] ->
HydraAccumulator ->
[Point1] ->
Either Text ByteString
createMembershipProof :: [ByteString]
-> HydraAccumulator -> [Point1] -> Either Text ByteString
createMembershipProof [ByteString]
subsetElements HydraAccumulator
fullAcc [Point1]
crs =
(String -> Text)
-> (Point1 -> ByteString)
-> Either String Point1
-> Either Text ByteString
forall a b c d. (a -> b) -> (c -> d) -> Either a c -> Either b d
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap String -> Text
forall a. ToText a => a -> Text
toText Point1 -> ByteString
forall curve. BLS curve => Point curve -> ByteString
blsCompress (Either String Point1 -> Either Text ByteString)
-> Either String Point1 -> Either Text ByteString
forall a b. (a -> b) -> a -> b
$ [ByteString] -> Accumulator -> [Point1] -> Either String Point1
getPolyCommitOverG1 [ByteString]
subsetElements (HydraAccumulator -> Accumulator
unHydraAccumulator HydraAccumulator
fullAcc) [Point1]
crs
createMembershipProofFromUTxO ::
forall tx.
IsTx tx =>
UTxOType tx ->
HydraAccumulator ->
[Point1] ->
Either Text ByteString
createMembershipProofFromUTxO :: forall tx.
IsTx tx =>
UTxOType tx
-> HydraAccumulator -> [Point1] -> Either Text ByteString
createMembershipProofFromUTxO UTxOType tx
subsetUTxO HydraAccumulator
fullAcc [Point1]
crs =
let subsetElements :: [ByteString]
subsetElements = (ByteString -> Bool) -> [ByteString] -> [ByteString]
forall a. (a -> Bool) -> [a] -> [a]
filter (ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
/= ByteString
forall a. Monoid a => a
mempty) ([ByteString] -> [ByteString]) -> [ByteString] -> [ByteString]
forall a b. (a -> b) -> a -> b
$ forall tx. IsTx tx => TxOutType tx -> ByteString
utxoToElement @tx (TxOutType tx -> ByteString) -> [TxOutType tx] -> [ByteString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall tx. IsTx tx => UTxOType tx -> [TxOutType tx]
outputsOfUTxO @tx UTxOType tx
subsetUTxO
in
[ByteString]
-> HydraAccumulator -> [Point1] -> Either Text ByteString
createMembershipProof [ByteString]
subsetElements HydraAccumulator
fullAcc [Point1]
crs
createCRSG2Datum :: Int -> HApi.TxOutDatum ctx
createCRSG2Datum :: forall ctx. Int -> TxOutDatum ctx
createCRSG2Datum Int
n =
BabbageEraOnwards Era -> HashableScriptData -> TxOutDatum ctx Era
forall era ctx.
BabbageEraOnwards era -> HashableScriptData -> TxOutDatum ctx era
TxOutDatumInline BabbageEraOnwards Era
BabbageEraOnwardsConway (HashableScriptData -> TxOutDatum ctx Era)
-> HashableScriptData -> TxOutDatum ctx Era
forall a b. (a -> b) -> a -> b
$
[BuiltinBLS12_381_G2_Element] -> HashableScriptData
forall a. ToScriptData a => a -> HashableScriptData
HApi.toScriptData
(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 (Point2 -> BuiltinBLS12_381_G2_Element)
-> [Point2] -> [BuiltinBLS12_381_G2_Element]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> [Point2]
crsG2Points Int
n)