Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add msm without serialization #4

Merged
merged 12 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ cabal.project.local~
rust-wrapper/target/
rust-wrapper/Cargo.lock
rust-wrapper/haskell-wrapper/cbits/rust-wrapper.h
*.data
*.svg
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"haskell.formattingProvider": "stylish-haskell",
"rust-analyzer.check.command": "clippy"
}
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Run benchmark:
```bash
cabal run msm
```
### Profiling and benchmarking
### Haskell profiling and benchmarking

Before you need install `ghc-prof-flamegraph`. Remember path to executable file
```bash
Expand All @@ -75,4 +75,27 @@ Run generating flamegraph. Make sure the path to `ghc-prof-flamegraph` is correc
```bash
~/.local/bin/ghc-prof-flamegraph msm.prof
```
Flamegraph will be in `msm.svg` file
Flamegraph will be in `msm.svg` file


### Rust profiling and benchmarking

To run benchmark install [cargo-criterion](https://github.com/bheisler/cargo-criterion)
```bash
cargo install cargo-criterion
```
And run in `rust-wrapper`
```bash
cargo criterion --bench msm_bench
```

For generate flamegraph install [flamegraph](https://github.com/flamegraph-rs/flamegraph) (require `perf`)
```bash
cargo install flamegraph
```

And generate flamegraph from bench (in `rust-wrapper`):
```bash
cargo flamegraph --bench msm_bench
```

37 changes: 22 additions & 15 deletions bench/BenchMSM.hs
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
{-# LANGUAGE AllowAmbiguousTypes #-}
module Main where

import qualified Data.ByteString as BS
import Prelude hiding (length, sum, (-))
import qualified Data.Vector as V
import Prelude hiding (Num (..), length, sum, take, (-))
import RustFunctions (RustCore)
import Test.QuickCheck (Arbitrary (arbitrary), generate)
import Test.Tasty.Bench

import ZkFold.Base.Algebra.EllipticCurve.BLS12_381 (BLS12_381_G1, BLS12_381_G2)
import ZkFold.Base.Protocol.ARK.Plonk (Plonk)
import ZkFold.Base.Protocol.NonInteractiveProof (HaskellCore, NonInteractiveProof (..),
NonInteractiveProofTestData (..))
type PlonkSizeBS = 32
type PlonkBS n = Plonk PlonkSizeBS n BLS12_381_G1 BLS12_381_G2 BS.ByteString
import ZkFold.Base.Algebra.EllipticCurve.BLS12_381 (BLS12_381_G1)
import ZkFold.Base.Algebra.EllipticCurve.Class (EllipticCurve (ScalarField), Point)
import ZkFold.Base.Algebra.Polynomials.Univariate (PolyVec, toPolyVec)
import ZkFold.Base.Data.Vector (Vector (..))
import ZkFold.Base.Protocol.NonInteractiveProof

testMSM :: forall core size . (CoreFunction BLS12_381_G1 core) => V.Vector (Point BLS12_381_G1) -> PolyVec (ScalarField BLS12_381_G1) size -> Bool
testMSM points scalars = let !_ = msm @BLS12_381_G1 @core points scalars in True

type Length = 4096

main :: IO ()
main = do
(TestData a w) <- generate arbitrary :: IO (NonInteractiveProofTestData (PlonkBS 2) HaskellCore)
(Vector p) <- generate arbitrary :: IO (Vector Length (Point BLS12_381_G1))
(Vector s) <- generate arbitrary :: IO (Vector Length (ScalarField BLS12_381_G1))

let spHaskell = setupProve @(PlonkBS 2) @HaskellCore a
spRust = setupProve @(PlonkBS 2) @RustCore a
let
points = V.fromList p
scalars = toPolyVec @(ScalarField BLS12_381_G1) @Length $ V.fromList s

defaultMain
[
bgroup "MSM group"

[ bench "Haskell core" $ nf (show . uncurry (prove @(PlonkBS 2) @HaskellCore)) (spHaskell, w)
, bcompare "Haskell core" $
bench "Rust core" $ nf (show . uncurry (prove @(PlonkBS 2) @RustCore)) (spRust, w)
[
bench "Haskell msm" $ nf (uncurry (testMSM @HaskellCore)) (points, scalars),
bcompare "Haskell msm" $
bench "Rust-arkmsm" $ nf (uncurry (testMSM @RustCore)) (points, scalars)
]
]
52 changes: 52 additions & 0 deletions bench/BenchPolyMul.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

module Main where

import Control.DeepSeq (force)
import Control.Exception (evaluate)
import Control.Monad (replicateM)
import qualified Data.Vector as V
import Foreign
import Prelude hiding (sum, (*), (+), (-), (/), (^))
import qualified Prelude as P
import RustFunctions (rustMulFft)
import System.Random (randomIO)
import Test.Tasty.Bench

import ZkFold.Base.Algebra.Basic.Class
import ZkFold.Base.Algebra.Basic.Field
import ZkFold.Base.Algebra.Basic.Number (Prime)
import ZkFold.Base.Algebra.EllipticCurve.BLS12_381
import ZkFold.Base.Algebra.Polynomials.Univariate

-- | Generate random polynomials of given size
--
polynomials :: forall a. Prime a => Int -> IO (Poly (Zp a), Poly (Zp a))
polynomials size = do
coeffs1 <- replicateM size (toZp @a <$> randomIO)
coeffs2 <- replicateM size (toZp @a <$> randomIO)
evaluatedCoeffs1 <- evaluate . force . V.fromList $ coeffs1
evaluatedCoeffs2 <- evaluate . force . V.fromList $ coeffs2
pure (toPoly evaluatedCoeffs1, toPoly evaluatedCoeffs2)

sizes :: [Int]
sizes = ((2 :: Int) P.^) <$> [10 .. 14 :: Int]

ops :: forall a . (Eq a, Field a, Storable a) => [(String, Poly a -> Poly a -> Poly a)]
ops = [ ("DFT multiplication", mulPolyDft)
, ("Adaptive multiplication", (*))
, ("Rust FFT", \x y -> toPoly (rustMulFft @a (fromPoly x) (fromPoly y)))
]

benchOps :: Prime a => Int -> [(String, Poly (Zp a) -> Poly (Zp a) -> Poly (Zp a))] -> Benchmark
benchOps size testOps = env (polynomials size) $ \ ~(p1, p2) ->
bgroup ("Multiplying polynomials of size " <> show size) $
flip fmap testOps $ \(desc, op) -> bench desc $ nf (uncurry op) (p1, p2)

main :: IO ()
main = do
defaultMain
[ bgroup "Field without roots of unity" $ flip fmap sizes $ \s -> benchOps @BLS12_381_Base s $ tail ops
, bgroup "Field with roots of unity" $ flip fmap sizes $ \s -> benchOps @BLS12_381_Scalar s ops
]
31 changes: 31 additions & 0 deletions bench/BenchProve.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module Main where

import qualified Data.ByteString as BS
import Prelude hiding (Num (..), length, sum, take, (-))
import RustFunctions (RustCore)
import Test.QuickCheck (Arbitrary (arbitrary), generate)
import Test.Tasty.Bench

import ZkFold.Base.Algebra.EllipticCurve.BLS12_381 (BLS12_381_G1, BLS12_381_G2)
import ZkFold.Base.Protocol.ARK.Plonk (Plonk)
import ZkFold.Base.Protocol.NonInteractiveProof

type PlonkSizeBS = 128
type PlonkBS n = Plonk PlonkSizeBS n BLS12_381_G1 BLS12_381_G2 BS.ByteString

main :: IO ()
main = do
(TestData a w) <- generate arbitrary :: IO (NonInteractiveProofTestData (PlonkBS 2) HaskellCore)

let spHaskell = setupProve @(PlonkBS 2) @HaskellCore a
spRust = setupProve @(PlonkBS 2) @RustCore a

defaultMain
[
bgroup "Prove group"

[ bench "Haskell core" $ nf (show . uncurry (prove @(PlonkBS 2) @HaskellCore)) (spHaskell, w)
, bcompare "Haskell core" $
bench "Rust core" $ nf (show . uncurry (prove @(PlonkBS 2) @RustCore)) (spRust, w)
]
]
28 changes: 28 additions & 0 deletions haskell-wrapper/src/Functions.chs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module Functions where

#include "rust_wrapper.h"
import Foreign.C.String
import Prelude
import Data.ByteString (ByteString)
import Foreign.Rust.Marshall.Variable
Expand All @@ -20,3 +21,30 @@ import Foreign.Rust.Marshall.Variable
}
-> `()'
#}

{# fun pure unsafe rust_wrapper_multi_scalar_multiplication_without_serialization as ^
{ `CString'
, `Int'

, `CString'
, `Int'

, `Int'
, `CString'
}
-> `()'
#}


{# fun pure unsafe rust_wrapper_mul_fft as rustWrapperMulFFT
{ `CString'
, `Int'

, `CString'
, `Int'

, `Int'
, `CString'
}
-> `()'
#}
101 changes: 0 additions & 101 deletions haskell-wrapper/src/Pack.hs

This file was deleted.

Loading