Skip to content

Commit c5a2591

Browse files
committed
clean up
1 parent 33d534d commit c5a2591

File tree

3 files changed

+77
-49
lines changed

3 files changed

+77
-49
lines changed

haskell-accumulator/haskell-accumulator.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ test-suite bindings-test
3535
, base >=4.2 && <5
3636
, bytestring
3737
, cardano-crypto-class
38+
, containers
3839
, criterion
3940
, haskell-accumulator-lib
41+
, plutus-core
4042
, plutus-tx
4143
, random

haskell-accumulator/lib/Accumulator.hs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,21 @@ module Accumulator where
55
import Cardano.Crypto.Hash.Blake2b (Blake2b_224)
66
import Cardano.Crypto.Hash.Class (digest)
77
import qualified Data.ByteString as BS
8+
import Data.List (foldl')
89
import qualified Data.Map as Map
910
import Data.Proxy (Proxy (Proxy))
1011

1112
type Element = BS.ByteString
1213
type Count = Int
1314
type Blake2bHash = BS.ByteString
1415

15-
-- Use a Map for fast lookups and precompute the hash of each element
16+
-- | Use a Map for fast lookups and precompute the hash of each element
1617
type Accumulator = Map.Map Element (Blake2bHash, Count)
1718

1819
emptyAccumulator :: Accumulator
1920
emptyAccumulator = Map.empty
2021

21-
-- Function to add an element with its Blake2b hash and count
22+
-- | Function to add an element with its Blake2b hash and count
2223
addElement :: Accumulator -> Element -> Accumulator
2324
addElement acc element =
2425
let hashValue = digest (Proxy @Blake2b_224) element
@@ -28,13 +29,17 @@ addElement acc element =
2829
(hashValue, 1)
2930
acc
3031

32+
-- | Function to remove an element from the accumulator
3133
removeElement :: Element -> Accumulator -> Accumulator
3234
removeElement = Map.update adjustCount
3335
where
3436
adjustCount (h, count)
3537
| count > 1 = Just (h, count - 1)
3638
| otherwise = Nothing
3739

38-
-- Function to check if an element is in the accumulator
40+
-- | Function to check if an element is in the accumulator
3941
elementExists :: Element -> Accumulator -> Bool
4042
elementExists = Map.member
43+
44+
buildAccumulator :: [Element] -> Accumulator
45+
buildAccumulator = foldl' addElement emptyAccumulator

haskell-accumulator/test/Main.hs

Lines changed: 67 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
module Main where
55

6-
import Accumulator (Accumulator, Element (..), addElement, emptyAccumulator, removeElement)
6+
import Accumulator (Accumulator, Element (..), addElement, buildAccumulator, emptyAccumulator, removeElement)
77
import Bindings (getPolyCommitOverG1, getPolyCommitOverG2)
88
import Cardano.Crypto.EllipticCurve.BLS12_381.Internal (
99
Point1 (..),
@@ -21,7 +21,7 @@ import Cardano.Crypto.EllipticCurve.BLS12_381.Internal (
2121
)
2222
import Criterion.Main
2323
import qualified Data.ByteString as B
24-
import Data.List (nub)
24+
import qualified Data.Set as Set
2525
import qualified Field as F
2626
import GHC.IO (unsafePerformIO)
2727
import PlutusTx.Numeric (
@@ -33,30 +33,35 @@ import PlutusTx.Numeric (
3333
MultiplicativeSemigroup (..),
3434
)
3535
import System.Random (randomRIO)
36+
import Text.Printf (printf)
3637

37-
-- Helper function to generate a random ByteString of a given length
38+
-- | Helper function to convert a ByteString to a hex string
39+
byteStringAsHex :: B.ByteString -> String
40+
byteStringAsHex bs = "0x" ++ concat (B.foldr' (\w s -> printf "%02x" w : s) [] bs)
41+
42+
-- | Helper function to generate a random ByteString of a given length
3843
generateRandomByteString :: Int -> IO B.ByteString
3944
generateRandomByteString n = B.pack <$> mapM (\_ -> randomRIO (0, 255)) [1 .. n]
4045

41-
-- Generate a random set of N ByteStrings
46+
-- | Generate a random set of N ByteStrings
4247
generateRandomSet :: Int -> IO [Element]
4348
generateRandomSet n = mapM (\_ -> generateRandomByteString 32) [1 .. n]
4449

45-
-- Helper function to pick n random elements from a list
50+
-- | Helper function to pick n random elements from a list
4651
pickRandomElements :: Int -> [a] -> IO [a]
4752
pickRandomElements n xs = mapM (\_ -> (xs !!) <$> randomRIO (0, length xs Prelude.- 1)) [1 .. n]
4853

49-
-- Create test setup with a set of elements and a subset of that set
50-
mkTestSetup :: Int -> Int -> IO (Accumulator, [Element], [Point1], [Point2])
51-
mkTestSetup setSize subSetSize = do
54+
-- | Create test setup with a set of elements and a subset of that set
55+
generateTestSetup :: Int -> Int -> IO (Accumulator, [Element], [Point1], [Point2])
56+
generateTestSetup setSize subSetSize = do
5257
-- Generate a random set of ByteStrings
5358
set <- generateRandomSet setSize
54-
let setMap = foldl addElement emptyAccumulator set :: Accumulator
59+
let accumulator = buildAccumulator set
5560

56-
-- Define a tau
61+
-- Define a tau (a large secret value that no one knows)
5762
let tau = F.Scalar 22_435_875_175_126_190_499_447_740_508_185_965_837_690_552_500_527_637_822_603_658_699_938_581_184_511
5863

59-
-- Define powers of tau
64+
-- Define powers of tau (tau^0, tau^1, ..., tau^setSize+1 over the field)
6065
let powerOfTauField = map (F.powModScalar tau) [0 .. (fromIntegral setSize)]
6166

6267
-- Convert the powers of tau to integers back
@@ -75,72 +80,88 @@ mkTestSetup setSize subSetSize = do
7580

7681
-- Randomly pick subSetSize elements from the set
7782
subsetNonUnique <- pickRandomElements subSetSize set
78-
let subset = nub subsetNonUnique
83+
-- let subset = nub subsetNonUnique
84+
let subset = Set.toList $ Set.fromList subsetNonUnique
7985

80-
return (setMap, subset, crsG1, crsG2)
86+
return (accumulator, subset, crsG1, crsG2)
8187

82-
-- Helper to extract the result or force an error
88+
-- | Helper to extract the result or force an error
8389
benchmarkProofG1 :: [Element] -> Accumulator -> [Point1] -> IO ()
8490
benchmarkProofG1 subSet setMap crsG1 = do
8591
result <- getPolyCommitOverG1 subSet setMap crsG1
8692
case result of
8793
Left err -> error err -- Force an error to trigger computation
8894
Right _ -> return ()
8995

96+
-- | Helper to extract the result or force an error
9097
benchmarkProofG2 :: [Element] -> Accumulator -> [Point2] -> IO ()
9198
benchmarkProofG2 subSet setMap crsG2 = do
9299
result <- getPolyCommitOverG2 subSet setMap crsG2
93100
case result of
94101
Left err -> error err -- Force an error to trigger computation
95102
Right _ -> return ()
96103

97-
-- Main function with benchmarking
98-
main :: IO ()
99-
main = do
100-
-- Create a test setup with 1_000 elements and a subset of 1 (the proof is over the set minus the subset)
101-
(setMap, subSet, crsG1, crsG2) <- mkTestSetup 10 2
102-
103-
-- Benchmark the two calculations
104+
-- | Run benchmarks for proof calculations
105+
runBenchmarks :: IO ()
106+
runBenchmarks = do
107+
(accumulator, subSet, crsG1, crsG2) <- generateTestSetup 1_000 0
104108
defaultMain
105109
[ bgroup
106110
"proof calculations"
107-
[ bench "getProofOverG1" $ nfIO (benchmarkProofG1 subSet setMap crsG1)
108-
, bench "getProofOverG2" $ nfIO (benchmarkProofG2 subSet setMap crsG2)
111+
[ bench "getProofOverG1" $ nfIO (benchmarkProofG1 subSet accumulator crsG1)
112+
, bench "getProofOverG2" $ nfIO (benchmarkProofG2 subSet accumulator crsG2)
109113
]
110114
]
111115

112-
-- An basic E2E example.
116+
-- | Run an end-to-end example
117+
runE2EExample :: IO ()
118+
runE2EExample = do
119+
-- Create a test setup with 1_000 elements and a subset of size 0 (the proof is over the set minus the subset, so this is a good test case)
120+
(accumulator, subSet, crsG1, crsG2) <- generateTestSetup 1_000 0
113121

114-
-- Say we have this set of elements (note that the first argument of the mkTestSetup function call above
115-
-- should be bigger than the length of this set)
116-
let mySet = ["element1", "element2", "element3", "element4"] :: [Element]
122+
-- Say we have this set of elements (note that the first argument of the generateTestSetup function call above
123+
-- should be bigger than the length of this set, as we use the CRS from there)
124+
let mySet = ["element1", "element2", "element3", "element4", "element5", "element6", "element7", "element8", "element9", "element10"] :: [Element]
117125
-- We can get the offchain explicit accumulator via
118-
myAcc = foldl addElement emptyAccumulator mySet :: Accumulator
126+
myAcc = buildAccumulator mySet
119127

120128
-- Then we can calculate the onchain representation of our accumulator via
121129
accCommit <- getPolyCommitOverG2 [] myAcc crsG2
122130

123131
-- Say we want to proof the subset of the set
124-
let mySubset = ["element1", "element4"] :: [Element]
132+
let mySubset = ["element3", "element9"] :: [Element]
125133

126134
-- then the proof can be calculated via
127135
proof <- getPolyCommitOverG2 mySubset myAcc crsG2
128136

129137
-- Verify the proof onchain (but doing it with offchain code)
130-
case accCommit of
131-
Left err -> print $ err ++ " for accumulator"
132-
Right g2AccCommit -> case proof of
133-
Left err -> print $ err ++ " for proof"
134-
Right g2ProofCommit -> do
135-
let subsetAcc = foldl addElement emptyAccumulator mySubset :: Accumulator
136-
g1 = blsGenerator :: Point1
137-
subsetCommit <- getPolyCommitOverG1 [] subsetAcc crsG1
138-
case subsetCommit of
139-
Left err -> print $ err ++ " for subset accumulator"
140-
Right g1SubsetCommit -> do
141-
let pt1 = millerLoop g1 g2AccCommit
142-
pt2 = millerLoop g1SubsetCommit g2ProofCommit
143-
pairingCheck = ptFinalVerify pt1 pt2
144-
print pairingCheck
145-
146-
print "Run complete"
138+
case (accCommit, proof) of
139+
(Left err, _) -> print $ err ++ " for accumulator"
140+
(_, Left err) -> print $ err ++ " for proof"
141+
(Right g2AccCommit, Right g2ProofCommit) -> do
142+
let subsetAcc = buildAccumulator mySubset
143+
subsetCommit <- getPolyCommitOverG1 [] subsetAcc crsG1
144+
case subsetCommit of
145+
Left err -> print $ err ++ " for subset accumulator"
146+
Right g1SubsetCommit -> do
147+
let g1 = blsGenerator :: Point1
148+
pt1 = millerLoop g1 g2AccCommit
149+
pt2 = millerLoop g1SubsetCommit g2ProofCommit
150+
pairingCheck = ptFinalVerify pt1 pt2
151+
accBS = blsCompress g2AccCommit
152+
proofBS = blsCompress g2ProofCommit
153+
print "Proving that the subset is in the set for:"
154+
print $ "Subset: " ++ show mySubset
155+
print $ "With proof: " ++ show (byteStringAsHex proofBS)
156+
print $ "Set: " ++ show mySet
157+
print $ "With accumulator commitment: " ++ show (byteStringAsHex accBS)
158+
print $ "The proof is: " ++ show pairingCheck
159+
160+
-- Verify the proof onchain (but doing it with offchain code)
161+
print "E2E run complete"
162+
163+
-- Main function with benchmarking and an E2E example
164+
main :: IO ()
165+
main = do
166+
runBenchmarks
167+
runE2EExample

0 commit comments

Comments
 (0)