diff --git a/README.md b/README.md index 2524db7..2c3a7bc 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,9 @@ try to focus on simplicity. - [ ] Parsing from Plonky's custom binary serialization - [x] Generating verifier challenges - [ ] Recursive circuit subtle details (like [this](https://github.com/0xPolygonZero/plonky2/blob/356aefb6863ac881fb71f9bf851582c915428458/plonky2/src/fri/challenges.rs#L55-L64])) -- [ ] Constraints check +- [x] Constraints check - [ ] FRI check +- [ ] Support lookup tables - [ ] Documenting Plonky2 internals and the verifier algorithm Supported gates: diff --git a/src/Algebra/Goldilocks.hs b/src/Algebra/Goldilocks.hs index e3e88ad..3f04fb1 100644 --- a/src/Algebra/Goldilocks.hs +++ b/src/Algebra/Goldilocks.hs @@ -147,6 +147,9 @@ div a b = mul a (inv b) -------------------------------------------------------------------------------- +pow_ :: Goldilocks -> Int -> Goldilocks +pow_ x e = pow x (fromIntegral e) + pow :: Goldilocks -> Integer -> Goldilocks pow x e | e == 0 = 1 diff --git a/src/Algebra/GoldilocksExt.hs b/src/Algebra/GoldilocksExt.hs index 1dee91c..e86ecac 100644 --- a/src/Algebra/GoldilocksExt.hs +++ b/src/Algebra/GoldilocksExt.hs @@ -63,6 +63,9 @@ instance Fractional FExt where -------------------------------------------------------------------------------- +scaleExt :: F -> FExt -> FExt +scaleExt s (MkExt a b) = MkExt (s*a) (s*b) + sqrExt :: FExt -> FExt sqrExt x = x*x @@ -77,6 +80,9 @@ divExt u v = u * invExt v -------------------------------------------------------------------------------- +powExt_ :: GoldilocksExt -> Int -> GoldilocksExt +powExt_ x e = powExt x (fromIntegral e) + powExt :: GoldilocksExt -> Integer -> GoldilocksExt powExt x e | e == 0 = 1 diff --git a/src/Gate/Constraints.hs b/src/Gate/Constraints.hs index ed593ef..18f6429 100644 --- a/src/Gate/Constraints.hs +++ b/src/Gate/Constraints.hs @@ -5,19 +5,14 @@ -- of constraints. -- -{-# LANGUAGE StrictData, DeriveFunctor, GADTs, RecordWildCards #-} +{-# LANGUAGE StrictData, RecordWildCards #-} module Gate.Constraints where -------------------------------------------------------------------------------- -import Prelude hiding ( (^) ) - +import Prelude hiding ( (^) ) import Data.Array hiding (range) import Data.Char -import Text.Show - -import Data.IntMap (IntMap) -import qualified Data.IntMap as IntMap import Algebra.Goldilocks import Algebra.GoldilocksExt @@ -28,6 +23,8 @@ import Gate.Vars import Gate.Computation import Gate.Poseidon +import Misc.Aux + -------------------------------------------------------------------------------- -- * Gate constraints @@ -87,7 +84,7 @@ gateComputation gate = -- equality with "hardcoded" hash components PublicInputGate - -> commitList [ hash i - wire i | i <- range 4 ] + -> commitList [ wire i - hash i | i <- range 4 ] PoseidonGate hash_width -> case hash_width of 12 -> poseidonGateConstraints diff --git a/src/Gate/Poseidon.hs b/src/Gate/Poseidon.hs index 9bb60c4..0fc4351 100644 --- a/src/Gate/Poseidon.hs +++ b/src/Gate/Poseidon.hs @@ -21,6 +21,8 @@ import Gate.Vars import Gate.Computation import Hash.Constants +import Misc.Aux + -------------------------------------------------------------------------------- sbox :: Expr Var_ -> Compute (Expr Var_) @@ -49,7 +51,7 @@ poseidonGateConstraints = do -- merkle swap let input_lhs i = input i let input_rhs i = input (i+4) - commit $ (1 - swap_flag) * swap_flag + commit $ swap_flag * (swap_flag - 1) commitList [ swap_flag * (input_rhs i - input_lhs i) - delta i | i <- range 4 ] -- swapped inputs diff --git a/src/Gate/Selector.hs b/src/Gate/Selector.hs new file mode 100644 index 0000000..d07b4b2 --- /dev/null +++ b/src/Gate/Selector.hs @@ -0,0 +1,45 @@ + +-- | Selector polynomials + +{-# LANGUAGE StrictData, RecordWildCards #-} +module Gate.Selector where + +-------------------------------------------------------------------------------- + +import Data.Array hiding (range) + +import Algebra.Goldilocks +import Algebra.GoldilocksExt +import Algebra.Expr + +import Gate.Base +import Gate.Vars + +import Types +import Misc.Aux + +-------------------------------------------------------------------------------- + +-- | Given an evaluation point @x@ and a gate index @k@, we compute +-- the evaluation of the corresponding selector polynomial +-- +-- Note: In the actual protocol, we have @x = S_g(zeta)@ +-- +evalSelectorPoly :: SelectorsInfo -> FExt -> Int -> FExt +evalSelectorPoly (MkSelectorsInfo{..}) x k = value where + group_idx = selector_indices !! k + range = selector_groups !! group_idx + initial = if length selector_groups > 1 then unused - x else 1 + value = initial * product [ fromIntegral j - x | j <- enumerateRange range , j /= k ] + unused = (2^32 - 1) :: FExt + +-- | Given the evaluations of the selector column polynomials, we evaluate +-- all the gate selectors +evalSelectors :: SelectorsInfo -> [FExt] -> [FExt] +evalSelectors selInfo@(MkSelectorsInfo{..}) xs = values where + values = [ evalSelectorPoly selInfo (xs!!grp) i | (i,grp) <- zip [0..] selector_indices ] + +numSelectorColumns :: SelectorsInfo -> Int +numSelectorColumns selInfo = length (selector_groups selInfo) + +-------------------------------------------------------------------------------- diff --git a/src/Gate/Vars.hs b/src/Gate/Vars.hs index c4070df..6325fe8 100644 --- a/src/Gate/Vars.hs +++ b/src/Gate/Vars.hs @@ -44,9 +44,6 @@ instance Pretty v => Pretty (Var v) where -------------------------------------------------------------------------------- -- * Convenience -range :: Int -> [Int] -range k = [0..k-1] - wire, cnst, hash :: Int -> Expr (Var PlonkyVar) wire i = VarE $ ProofVar $ WireV i -- witness variable cnst i = VarE $ ProofVar $ ConstV i -- constant variable diff --git a/src/Hash/Constants.hs b/src/Hash/Constants.hs index 4921303..1e20df7 100644 --- a/src/Hash/Constants.hs +++ b/src/Hash/Constants.hs @@ -10,6 +10,7 @@ module Hash.Constants where import Data.Array import Algebra.Goldilocks +import Misc.Aux -------------------------------------------------------------------------------- @@ -111,13 +112,8 @@ fast_PARTIAL_ROUND_INITIAL_MATRIX = listArray ((0,0),(10,10)) $ concat partialMdsMatrixCoeff :: Int -> Int -> F partialMdsMatrixCoeff i j = fast_PARTIAL_ROUND_INITIAL_MATRIX ! (j,i) -partition12 :: [a] -> [[a]] -partition12 = go where - go [] = [] - go xs = take 12 xs : go (drop 12 xs) - all_ROUND_CONSTANTS :: Array Int (Array Int F) -all_ROUND_CONSTANTS = listArray (0,29) $ map (listArray (0,11)) $ partition12 +all_ROUND_CONSTANTS = listArray (0,29) $ map (listArray (0,11)) $ partition 12 [ 0xb585f766f2144405 , 0x7746a55f43921ad7 , 0xb2fb0d31cee799b4 , 0x0f6760a4803427d7 , 0xe10d666650f4e012 , 0x8cae14cb07d09bf1 , 0xd438539c95f63e9f , 0xef781c7ce35b4c3d , 0xcdc4a239b0c44426 , 0x277fa208bf337bff , 0xe17653a29da578a1 , 0xc54302f225db2c76 diff --git a/src/Misc/Aux.hs b/src/Misc/Aux.hs new file mode 100644 index 0000000..2dbaef8 --- /dev/null +++ b/src/Misc/Aux.hs @@ -0,0 +1,76 @@ + +-- | Misc helper functions + +{-# LANGUAGE StrictData, DeriveGeneric, DeriveAnyClass #-} +module Misc.Aux where + +-------------------------------------------------------------------------------- + +import Data.Array +import Data.List + +import Data.Aeson hiding ( Array , pairs ) +import GHC.Generics + +-------------------------------------------------------------------------------- + +range :: Int -> [Int] +range k = [0..k-1] + +range' :: Int -> Int -> [Int] +range' a b = [a..b-1] + +-------------------------------------------------------------------------------- + +-- | Consecutive pairs of a list +pairs :: [a] -> [(a,a)] +pairs [] = [] +pairs [_] = [] +pairs (x:rest@(y:_)) = (x,y) : pairs rest + +safeZip :: [a] -> [b] -> [(a,b)] +safeZip = safeZipWith (,) + +safeZipWith :: (a -> b -> c) -> [a] -> [b] -> [c] +safeZipWith f = go where + go (x:xs) (y:ys) = f x y : go xs ys + go [] [] = [] + go _ _ = error "safeZipWith: different input lengths" + +longZipWith :: a -> b -> (a -> b -> c) -> [a] -> [b] -> [c] +longZipWith x0 y0 f = go where + go [] [] = [] + go [] ys = map (x0 `f`) ys + go xs [] = map (`f` y0) xs + go (x:xs) (y:ys) = f x y : go xs ys + +-- | Partition into equal sized chunks +partition :: Int -> [a] -> [[a]] +partition k = go where + go [] = [] + go xs = take k xs : go (drop k xs) + +-------------------------------------------------------------------------------- + +listToArray :: [a] -> Array Int a +listToArray xs = listArray (0, length xs - 1) xs + +arrayLength :: Array Int a -> Int +arrayLength arr = let (a,b) = bounds arr in b-a+1 + +-------------------------------------------------------------------------------- + +-- | The interval @[a,b)@ (inclusive on the left, exclusive on the right) +data Range = MkRange + { range_start :: !Int + , range_end :: !Int + } + deriving (Eq,Show,Generic) + +enumerateRange :: Range -> [Int] +enumerateRange (MkRange a b) = [a..b-1] + +instance FromJSON Range where parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = drop 6 } +instance ToJSON Range where toJSON = genericToJSON defaultOptions { fieldLabelModifier = drop 6 } + +-------------------------------------------------------------------------------- diff --git a/src/Plonk/Vanishing.hs b/src/Plonk/Vanishing.hs new file mode 100644 index 0000000..b0db24e --- /dev/null +++ b/src/Plonk/Vanishing.hs @@ -0,0 +1,144 @@ + +-- | Evaluate all the Plonk constraints. +-- +-- The following constraints are combined via powers of alpha: +-- +-- * boundary value constraints for the permutation running products (1 per challenge round) +-- +-- * running product consistency constraints (10 per challenge round, where @10 = #routed wires / max_degree@) +-- +-- * all lookup terms (many per challenge round) +-- +-- * combined gate constraints (123 by default as the Poseidon gate is the largest) +-- +-- This is done as many times as there are rounds, with different alphas (chosen from the base field). +-- + +{-# LANGUAGE RecordWildCards #-} +module Plonk.Vanishing where + +-------------------------------------------------------------------------------- + +import Data.Array +import Data.List ( foldl' , zipWith4 ) + +import Algebra.Goldilocks +import Algebra.GoldilocksExt + +import Challenge.Verifier + +import Hash.Digest +import Hash.Sponge + +import Gate.Computation +import Gate.Constraints +import Gate.Selector + +import Types +import Misc.Aux + +-------------------------------------------------------------------------------- + +-- | Evaluate the Lagrange polynomial @L_0(x)@ of a subgroup of size @N@ +evalLagrange0 :: Int -> FExt -> FExt +evalLagrange0 nn zeta + | zeta == 1 = 1 + | otherwise = (powExt_ zeta nn - 1) / (fromIntegral nn * (zeta - 1)) + +-------------------------------------------------------------------------------- + +-- | We combine the same things with all the challenge round alphas... +-- (Plonky2 is full with very strange design decisions...) +-- +evalCombinedPlonkConstraints :: CommonCircuitData -> ProofWithPublicInputs -> ProofChallenges -> [FExt] +evalCombinedPlonkConstraints common proof challenges = final where + constraints = evalAllPlonkConstraints common proof challenges + final = [ combineWithPowersOfAlpha alpha constraints | alpha <- plonk_alphas challenges ] + +-- | @sum [ alpha^k * x_k ]@ +combineWithPowersOfAlpha :: F -> [FExt] -> FExt +combineWithPowersOfAlpha alpha xs = foldl' f 0 (reverse xs) where + f !acc !x = x + scaleExt alpha acc + +-------------------------------------------------------------------------------- + +evalAllPlonkConstraints :: CommonCircuitData -> ProofWithPublicInputs -> ProofChallenges -> [FExt] +evalAllPlonkConstraints + (MkCommonCircuitData{..}) + (MkProofWithPublicInputs{..}) + (MkProofChallenges{..}) = finals + where + + finals = concat + [ zs1 + , concat pp_checks + , lookup_checks + , gates + ] + + lookup_checks = [] -- TODO + + MkProof{..} = the_proof + MkOpeningSet{..} = openings + + nselectors = numSelectorColumns circuit_selectors_info + opening_selectors = take nselectors opening_constants + + nn = fri_nrows circuit_fri_params + maxdeg = circuit_quotient_degree_factor + pi_hash = sponge public_inputs + + -- gate constraints + eval_vars = toEvaluationVars pi_hash circuit_selectors_info openings + gate_prgs = map gateProgram circuit_gates + sel_values = evalSelectors circuit_selectors_info opening_selectors + unfiltered = map (runStraightLine eval_vars) gate_prgs + filtered = zipWith (\s cons -> map (*s) cons) sel_values unfiltered + gates = combineFilteredGateConstraints filtered + + -- permutation constraints + zs1 = [ evalLagrange0 nn plonk_zeta * (z-1) | z <- opening_plonk_zs ] + pp_chunks = partition circuit_num_partial_products opening_partial_products + pp_checks = zipWith4 evalPartialProducts + opening_plonk_zs + opening_plonk_zs_next + (zip plonk_betas plonk_gammas) + pp_chunks + + evalPartialProducts :: FExt -> FExt -> (F,F) -> [FExt] -> [FExt] + evalPartialProducts z znext (beta,gamma) pp_chunk = zipWith3 f (pairs current) numers denoms where + numers = partition maxdeg $ zipWith (\koset w -> w + scaleExt (beta*koset) plonk_zeta + fromBase gamma) circuit_k_is opening_wires + denoms = partition maxdeg $ zipWith (\sigma w -> w + scaleExt beta sigma + fromBase gamma) opening_plonk_sigmas opening_wires + current = [z] ++ pp_chunk ++ [znext] + f :: (FExt,FExt) -> [FExt] -> [FExt] -> FExt + f (prev,next) numer denom = prev * product numer - next * product denom + +-------------------------------------------------------------------------------- + +-- | Each gate has some number of constrains (depending on which gate it is). +-- These are combined \"verticaly\" by simple addition, so that each term in the +-- resulting list of summed constraints is a sum of constraints from distinct gates, +-- at most 1 per gate. +-- +-- This look suspicious at first glance: normally we never just add together constraints! +-- However this looks safe in this case, because the selectors ensure that when evaluating +-- at a particular row of the witness, each such sum can have at most 1 nonzero summand + +combineFilteredGateConstraints :: [[FExt]] -> [FExt] +combineFilteredGateConstraints = foldl1 (longZipWith 0 0 (+)) + +-------------------------------------------------------------------------------- + +toEvaluationVars :: Digest -> SelectorsInfo -> OpeningSet -> EvaluationVars FExt +toEvaluationVars pi_hash selinfo (MkOpeningSet{..}) = + MkEvaluationVars + { local_selectors = listToArray (take nsels opening_constants) + , local_constants = listToArray (drop nsels opening_constants) + , local_wires = listToArray opening_wires + , public_inputs_hash = digestToList pi_hash + } + where + nsels = numSelectorColumns selinfo + +-------------------------------------------------------------------------------- + diff --git a/src/Plonk/Verifier.hs b/src/Plonk/Verifier.hs new file mode 100644 index 0000000..5b8f993 --- /dev/null +++ b/src/Plonk/Verifier.hs @@ -0,0 +1,62 @@ + +-- | Check the combined Plonk equation @Q_alpha(zeta) * Z_X(zeta) = C_alpha(zeta)@ +-- +-- Note: there are @num_challenge_rounds@ number of these (usually 2 or 3); +-- they are the same except with different combining @alpha@ coefficients. +-- + +{-# LANGUAGE RecordWildCards #-} +module Plonk.Verifier where + +-------------------------------------------------------------------------------- + +import Data.Array +import Data.List ( foldl' , zipWith4 ) + +import Algebra.Goldilocks +import Algebra.GoldilocksExt + +import Challenge.Verifier +import Plonk.Vanishing + +import Hash.Digest + +import Types +import Misc.Aux + +-------------------------------------------------------------------------------- + +{- +-- | Evaluate the zero polynomial @Z_H(x)@ +evalZeroPoly :: Int -> FExt -> FExt +evalZeroPoly nn zeta = powExt_ zeta nn - 1 +-} + +-------------------------------------------------------------------------------- + +-- | Assuming valid FRI openings, this function checks the combined Plonk equations +checkCombinedPlonkEquations :: CommonCircuitData -> ProofWithPublicInputs -> ProofChallenges -> Bool +checkCombinedPlonkEquations common proof challenges = + and (checkCombinedPlonkEquations' common proof challenges) + +checkCombinedPlonkEquations' :: CommonCircuitData -> ProofWithPublicInputs -> ProofChallenges -> [Bool] +checkCombinedPlonkEquations' common proof_pis challenges = ok_list where + + maxdeg = circuit_quotient_degree_factor common :: Int + nn = circuit_nrows common :: Int + zeta = plonk_zeta challenges :: FExt + zeta_n = powExt_ zeta nn :: FExt + + combined_evals = evalCombinedPlonkConstraints common proof_pis challenges :: [FExt] + quotient_evals = map (reduceWithPowers zeta_n) quotient_chunks :: [FExt] + quotient_chunks = partition maxdeg (opening_quotient_polys $ openings $ the_proof proof_pis) :: [[FExt]] + + ok_list = [ q * (zeta_n - 1) == c | (q,c) <- safeZip quotient_evals combined_evals ] + + -- sum [ u^i * q[i] | i<-[0..] ] + reduceWithPowers :: FExt -> [FExt] -> FExt + reduceWithPowers u chunk = foldl' f 0 (reverse chunk) where + f !acc !x = x + u * acc + +-------------------------------------------------------------------------------- + diff --git a/src/Types.hs b/src/Types.hs index 405dba4..3a80896 100644 --- a/src/Types.hs +++ b/src/Types.hs @@ -20,6 +20,7 @@ import Algebra.GoldilocksExt import Hash.Digest import Gate.Base import Gate.Parser +import Misc.Aux -------------------------------------------------------------------------------- @@ -47,13 +48,16 @@ data CommonCircuitData = MkCommonCircuitData , circuit_num_constants :: Int -- ^ The number of constant wires. , circuit_num_public_inputs :: Int -- ^ Number of public inputs , circuit_k_is :: [F] -- ^ The @{k_i}@ values (coset shifts) used in @S_I D_i@ in Plonk's permutation argument. - , circuit_num_partial_products :: Int -- ^ The number of partial products needed to compute the `Z` polynomials. + , circuit_num_partial_products :: Int -- ^ The number of partial products needed to compute the `Z` polynomials; @ = ceil( #routed / max_degree ) - 1@ , circuit_num_lookup_polys :: Int -- ^ The number of lookup polynomials. , circuit_num_lookup_selectors :: Int -- ^ The number of lookup selectors. , circuit_luts :: [LookupTable] -- ^ The stored lookup tables. } deriving (Eq,Show,Generic) +circuit_nrows :: CommonCircuitData -> Int +circuit_nrows = fri_nrows . circuit_fri_params + instance FromJSON CommonCircuitData where parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = drop 8 } --instance ToJSON CommonCircuitData where toJSON = genericToJSON defaultOptions { fieldLabelModifier = drop 8 } @@ -74,16 +78,6 @@ data CircuitConfig = MkCircuitConfig instance FromJSON CircuitConfig where parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = drop 7 } instance ToJSON CircuitConfig where toJSON = genericToJSON defaultOptions { fieldLabelModifier = drop 7 } --- | The interval @[a,b)@ (inclusive on the left, exclusive on the right) -data Range = MkRange - { range_start :: Int - , range_end :: Int - } - deriving (Eq,Show,Generic) - -instance FromJSON Range where parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = drop 6 } -instance ToJSON Range where toJSON = genericToJSON defaultOptions { fieldLabelModifier = drop 6 } - data SelectorsInfo = MkSelectorsInfo { selector_indices :: [Int] -- ^ which gate is in which selector groups (length = number of gates) , selector_groups :: [Range] -- ^ the selector groups are continuous intervals @@ -153,6 +147,11 @@ data FriParams = MkFriParams } deriving (Eq,Show,Generic) +-- | Number of rows in the circuit +fri_nrows :: FriParams -> Int +fri_nrows params = 2^nbits where + nbits = fri_degree_bits params + instance FromJSON FriParams where parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = drop 4 } instance ToJSON FriParams where toJSON = genericToJSON defaultOptions { fieldLabelModifier = drop 4 } @@ -243,15 +242,15 @@ data Proof = MkProof deriving (Eq,Show,Generic,ToJSON,FromJSON) data OpeningSet = MkOpeningSet - { opening_constants :: [FExt] - , opening_plonk_sigmas :: [FExt] - , opening_wires :: [FExt] - , opening_plonk_zs :: [FExt] - , opening_plonk_zs_next :: [FExt] - , opening_partial_products :: [FExt] - , opening_quotient_polys :: [FExt] - , opening_lookup_zs :: [FExt] - , opening_lookup_zs_next :: [FExt] + { opening_constants :: [FExt] -- ^ note: this includes the selector columns! + , opening_plonk_sigmas :: [FExt] -- ^ these correspond to columns encoding the wire permutation (as many as routed columns) + , opening_wires :: [FExt] -- ^ these are evaluations of the witness columns + , opening_plonk_zs :: [FExt] -- ^ first columns of the permutation arguments (there @num_challenges@ number of these) + , opening_plonk_zs_next :: [FExt] -- ^ evaluations of the first columns shifted by \"one row\" + , opening_partial_products :: [FExt] -- ^ remaining columns of the permutation arguments + , opening_quotient_polys :: [FExt] -- ^ the quotient polynomials (@num_challenges * max_degree@) + , opening_lookup_zs :: [FExt] -- ^ first columns of the lookup arguments + , opening_lookup_zs_next :: [FExt] -- ^ rest of the lookup arguments } deriving (Eq,Show,Generic) diff --git a/src/testmain.hs b/src/testmain.hs index f4e07d2..95c03ac 100644 --- a/src/testmain.hs +++ b/src/testmain.hs @@ -1,4 +1,5 @@ +{-# LANGUAGE RecordWildCards #-} module Main where -------------------------------------------------------------------------------- @@ -10,6 +11,8 @@ import Hash.Sponge import Hash.Digest import Algebra.Goldilocks import Challenge.Verifier +import Plonk.Vanishing +import Plonk.Verifier import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as L @@ -17,9 +20,9 @@ import qualified Data.ByteString.Lazy.Char8 as L -------------------------------------------------------------------------------- main = do - -- let prefix = "fibonacci" + let prefix = "fibonacci" -- let prefix = "recursion_outer" - let prefix = "lookup" + -- let prefix = "lookup" text_common <- L.readFile ("../json/" ++ prefix ++ "_common.json") text_vkey <- L.readFile ("../json/" ++ prefix ++ "_vkey.json" ) @@ -28,7 +31,24 @@ main = do let Just common_data = decode text_common :: Maybe CommonCircuitData let Just verifier_data = decode text_vkey :: Maybe VerifierOnlyCircuitData let Just proof_data = decode text_proof :: Maybe ProofWithPublicInputs + + let pi_hash = sponge (public_inputs proof_data) + putStrLn $ "public inputs hash = " ++ show pi_hash + + let MkOpeningSet{..} = openings (the_proof proof_data) + putStrLn $ "# opening_constants = " ++ show (length opening_constants ) + putStrLn $ "# opening_plonk_sigmas = " ++ show (length opening_plonk_sigmas ) + putStrLn $ "# opening_wires = " ++ show (length opening_wires ) + putStrLn $ "# opening_plonk_zs = " ++ show (length opening_plonk_zs ) + putStrLn $ "# opening_plonk_zs_next = " ++ show (length opening_plonk_zs_next ) + putStrLn $ "# opening_partial_products = " ++ show (length opening_partial_products) + putStrLn $ "# opening_quotient_polys = " ++ show (length opening_quotient_polys ) + putStrLn $ "# opening_lookup_zs = " ++ show (length opening_lookup_zs ) + putStrLn $ "# opening_lookup_zs_next = " ++ show (length opening_lookup_zs_next ) let challenges = proofChallenges common_data verifier_data proof_data - print challenges \ No newline at end of file + print challenges + + print $ evalCombinedPlonkConstraints common_data proof_data challenges + print $ checkCombinedPlonkEquations' common_data proof_data challenges