hydra-tx
Safe HaskellSafe-Inferred
LanguageGHC2021

Hydra.Tx.Accumulator

Synopsis

Documentation

data HydraAccumulator Source #

Instances

Instances details
Show HydraAccumulator Source #

Shows only the element map: the derived instance would force the cached commitment, so showing head state in logs or test output would compute a BLS commitment as a side effect.

Instance details

Defined in Hydra.Tx.Accumulator

Eq HydraAccumulator Source # 
Instance details

Defined in Hydra.Tx.Accumulator

getAccumulatorHash :: HydraAccumulator -> ByteString Source #

Get a blake2b-256 hash of the accumulator commitment (compressed G1 point).

This is a pure function that returns a 32-byte deterministic hash of the compressed G1 accumulator commitment. It is what gets signed by all parties in the multi-signature and stored as accumulatorHash in on-chain datums.

Hashing the compressed G1 point (rather than the serialized map) binds the signed hash to the exact G1 point stored in accumulatorCommitment, allowing the on-chain validator to verify their consistency.

The result is cached inside HydraAccumulator as a lazy thunk and computed at most once per value, regardless of how many times this function is called.

getAccumulatorCommitment :: HydraAccumulator -> BuiltinBLS12_381_G1_Element Source #

computeG1CommitmentBytes :: Accumulator -> ByteString Source #

Compute the compressed G1 commitment for an accumulator through the rust-accumulator FFI (divide-and-conquer FFT polynomial expansion and a Pippenger multi-scalar multiplication), which is orders of magnitude faster than expanding the polynomial in Haskell. Bit-for-bit equal to the PlutusTx reference path; see the equivalence properties and golden values in Hydra.Tx.AccumulatorSpec.

accumulatorSize :: HydraAccumulator -> Int Source #

Number of UTxOs tracked by the accumulator.

maxAccumulatorSize :: Int Source #

Maximum accumulator size, re-exported from KZGTrustedSetup for convenience.

checkAccumulatorSize :: HydraAccumulator -> Either (Int, Int) () Source #

Check an accumulator against the capacity of the embedded G1 CRS, yielding its size and the maximum when it does not fit.

SECURITY: computeG1CommitmentBytes enforces this limit with error, and it is reached through the lazy commitment thunk of HydraAccumulator -- i.e. from wherever that thunk is first forced, which includes 'ToJSON (Snapshot tx)' and getSignableRepresentation. Every path that builds an accumulator from data this node did not produce itself must therefore check the size before the value can be forced, traced or echoed. This check is safe to run on an over-capacity accumulator: like accumulatorSize it only folds the element map and never touches the cached commitment or hash. See validateClientInput (the client API boundary) and HeadLogic (the protocol-logic backstop).

deployedFanoutBatchSize :: Int Source #

Largest subset a single fanout transaction can distribute, re-exported from KZGTrustedSetup for convenience.

buildFromUTxO Source #

Arguments

:: forall tx. IsTx tx 
=> UTxOType tx

The UTxO set to build the accumulator from

-> HydraAccumulator

The resulting accumulator containing one element per TxOut

Build an accumulator from a UTxO by serializing each individual TxOut.

This is the CORRECT way to build an accumulator for partial fanout proofs. Each TxOut becomes a separate element in the accumulator, allowing you to later prove that a subset of TxOuts was part of the original set.

The serialization matches how hashTxOuts works on-chain: Each element = Builtins.serialiseData (toBuiltinData plutusTxOut)

Example usage: > -- Build accumulator from the full UTxO set > let fullAcc = buildFromUTxO Tx utxo > > -- Later, prove a subset exists > let crs = crsG1Points (requiredCRSPointCount fullAcc) > result <- createMembershipProofFromUTxO Tx subsetUTxO fullAcc crs

This approach allows proving that 2 out of 5 UTxOs are part of the original set, which is essential for partial fanout functionality.

buildFromSnapshotUTxOs Source #

Arguments

:: forall tx. IsTx tx 
=> UTxOType tx

The main snapshot UTxO set

-> Maybe (UTxOType tx)

UTxOs to be committed (if any)

-> Maybe (UTxOType tx)

UTxOs to be decommitted (if any)

-> (HydraAccumulator, HydraAccumulator)

The snapshot accumulator and the applied accumulator

Build the two accumulators a snapshot commits to, see Snapshot.

When a snapshot is signed nobody knows yet whether its pending increment or decrement will land on chain before the head is closed, and which outputs the head owes at close time depends on that. So the parties sign a commitment for each of the two futures:

  • the snapshot accumulator, over the head's content while it stays at the snapshot's version: the snapshot UTxO plus a pending decommit (still inside until the decrement lands); a pending commit is not yet inside.
  • the applied accumulator, over the head's content once the pending action has been applied on chain: the snapshot UTxO plus a pending commit (the increment absorbed it); a pending decommit has been paid out.

Close and Contest store the one matching their redeemer kind (Unused/Any and Used respectively, checkClose), so the on-chain commitment always describes exactly the outputs a fanout must distribute. With nothing pending both are the same value and are computed once.

Merging via UTxO union keeps the same canonical TxIn-sorted element order used by every other accumulator call site, so the commitments stored in the snapshot and all downstream proofs are built from the same element sets by construction (the underlying HydraAccumulator is a Map keyed by element bytes, so insertion order does not affect the commitment value).

applyUTxODelta Source #

Arguments

:: forall tx. IsTx tx 
=> HydraAccumulator

Accumulator built from the previous combined UTxO set

-> UTxOType tx

The previous combined UTxO set

-> UTxOType tx

The new combined UTxO set

-> HydraAccumulator 

Update an accumulator from one snapshot's combined UTxO set to the next by adding and removing only the changed outputs, avoiding the per-output serialization and hashing of a full rebuild. Extensionally equal to buildFromUTxO on the new set (see the property in Hydra.Tx.AccumulatorSpec): the underlying map tracks element multiplicity and the TxIn-keyed set difference removes exactly one occurrence per consumed input. Falls back to a full rebuild if a removed element is missing or has lower multiplicity than the removals require, which would indicate the given accumulator was not built from the given previous UTxO set.

removeOutputs Source #

Arguments

:: forall tx. IsTx tx 
=> HydraAccumulator

Accumulator to remove from

-> UTxOType tx

Outputs to remove, one occurrence each

-> HydraAccumulator 

Remove one occurrence of each given output from an accumulator.

Unlike applyUTxODelta the outputs to remove are given directly, so the result does not depend on which TxIn holds them. That matters wherever the two sets are related by content rather than by TxIn: partial fanout accepts a user selection as a sub-multiset of outputs (see isSubMultisetOf), so the same TxIn can carry a different TxOut on each side and a TxIn-keyed difference would then remove the wrong element, or none at all.

Removing exactly the distributed outputs is also what makes the on-chain split identity A = P_K * A' hold by construction, for the A that was verified against the head datum.

removeElement no-ops once an element's count is exhausted, so an output that is not in the accumulator leaves a commitment that does not bind the intended set; the on-chain identity then fails and the transaction is rejected, exactly as a fresh build over an inconsistent set would be.

CRS (Common Reference String)

crsG2Points :: Int -> [Point2] Source #

Returns the first n G2 powers of tau from the EIP-4844 trusted setup. Used as the on-chain CRS for verifying membership proofs: [G2, τ·G2, ..., τ^(n-1)·G2].

crsG1Points :: Int -> [Point1] Source #

Returns the first n G1 powers of tau from the EIP-4844 trusted setup. Used as the off-chain CRS for building accumulator commitments and membership proofs: [G1, τ·G1, ..., τ^(n-1)·G1].

requiredCRSPointCount :: HydraAccumulator -> Int Source #

Returns the number of G1 CRS points required for this accumulator. An n-element accumulator polynomial has degree n, so needs n+1 G1 points [G1, τ·G1, ..., τⁿ·G1] to compute the commitment A(τ)·G1 and proofs. n is the total element count including duplicates (sum of all counts).

defaultItems :: Int Source #

Number of G2 points published in the on-chain CRS UTxO datum.

This is the deployed G2 CRS length. It directly caps the largest subset that can be verified in a single fanout / partial-fanout pairing check: a subset of N elements yields a polynomial of degree N (one (X - sᵢ) factor per element), and the on-chain MSM to evaluate P_S(τ)·G2 needs N+1 G2 points, so the deployed batch limit is deployedFanoutBatchSize.

The trusted-setup file embeds 65 G2 points (see maxFanoutBatchSize); only the first defaultItems are written into the CRS UTxO at script-registry publication time (see buildScriptPublishingTxs). The head validator is compiled against the hash of that CRS datum and rejects any other one, so raising defaultItems means re-publishing the CRS UTxO and recompiling the scripts. It is bounded above by KZGTrustedSetup.maxFanoutBatchSize + 1.

Membership proofs for partial fanout

createMembershipProof Source #

Arguments

:: [Element]

The subset of elements to prove membership of (e.g., UTxOs being fanned out)

-> HydraAccumulator

The full accumulator from the confirmed snapshot

-> [Point1]

Common Reference String (CRS) for the cryptographic proof

-> Either Text ByteString

Returns the compressed proof point, or an error if elements are missing or CRS is too short

Create a membership proof for a subset of UTxO elements.

This function uses getPolyCommitOverG1 from haskell-accumulator's Bindings module: https://github.com/cardano-scaling/haskell-accumulator/blob/main/haskell-accumulator/lib/Bindings.hs

Given a subset of elements and the full accumulator, it: 1. Removes the subset elements from the accumulator 2. Computes a polynomial commitment over G1 for the remaining elements 3. Returns the proof as a compressed G1 point

createMembershipProofFromUTxO Source #

Arguments

:: forall tx. IsTx tx 
=> UTxOType tx

The subset of UTxO to prove membership of (e.g., UTxOs being fanned out)

-> HydraAccumulator

The full accumulator from the confirmed snapshot (built with buildFromUTxO)

-> [Point1]

Common Reference String (CRS) for the cryptographic proof

-> Either Text ByteString

Returns the compressed proof point, or an error if elements are missing or CRS is too short

Create a membership proof from a UTxO subset.

This function extracts individual TxOut elements from the subset UTxO and proves they exist in the full accumulator. The full accumulator must be built using buildFromUTxO for this to work correctly.

The proof is verified on-chain via e(commitment_G1, G2) = e(proof_G1, P_S(τ)·G2).

createCRSG2Datum :: Int -> TxOutDatum ctx Source #