mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-10 06:28:04 -05:00
259 lines
7.1 KiB
Go
259 lines
7.1 KiB
Go
//go:build !mock_prover
|
|
|
|
package core
|
|
|
|
/*
|
|
#cgo LDFLAGS: -lzkp -lm -ldl -lzktrie -L${SRCDIR}/lib/ -Wl,-rpath=${SRCDIR}/lib
|
|
#cgo gpu LDFLAGS: -lzkp -lm -ldl -lgmp -lstdc++ -lprocps -lzktrie -L/usr/local/cuda/lib64/ -lcudart -L${SRCDIR}/lib/ -Wl,-rpath=${SRCDIR}/lib
|
|
#include <stdlib.h>
|
|
#include "./lib/libzkp.h"
|
|
*/
|
|
import "C" //nolint:typecheck
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"unsafe"
|
|
|
|
"github.com/scroll-tech/go-ethereum/core/types"
|
|
"github.com/scroll-tech/go-ethereum/log"
|
|
|
|
"scroll-tech/common/types/message"
|
|
|
|
"scroll-tech/prover/config"
|
|
)
|
|
|
|
// ProverCore sends block-traces to rust-prover through ffi and get back the zk-proof.
|
|
type ProverCore struct {
|
|
cfg *config.ProverCoreConfig
|
|
VK string
|
|
}
|
|
|
|
// NewProverCore inits a ProverCore object.
|
|
func NewProverCore(cfg *config.ProverCoreConfig) (*ProverCore, error) {
|
|
paramsPathStr := C.CString(cfg.ParamsPath)
|
|
assetsPathStr := C.CString(cfg.AssetsPath)
|
|
defer func() {
|
|
C.free(unsafe.Pointer(paramsPathStr))
|
|
C.free(unsafe.Pointer(assetsPathStr))
|
|
}()
|
|
|
|
var vk string
|
|
var rawVK *C.char
|
|
if cfg.ProofType == message.ProofTypeBatch {
|
|
C.init_batch_prover(paramsPathStr, assetsPathStr)
|
|
rawVK = C.get_batch_vk()
|
|
} else if cfg.ProofType == message.ProofTypeChunk {
|
|
C.init_chunk_prover(paramsPathStr, assetsPathStr)
|
|
rawVK = C.get_chunk_vk()
|
|
}
|
|
defer C.free_c_chars(rawVK)
|
|
|
|
if rawVK != nil {
|
|
vk = C.GoString(rawVK)
|
|
}
|
|
|
|
if cfg.DumpDir != "" {
|
|
err := os.MkdirAll(cfg.DumpDir, os.ModePerm)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
log.Info("Enabled dump_proof", "dir", cfg.DumpDir)
|
|
}
|
|
|
|
return &ProverCore{cfg: cfg, VK: vk}, nil
|
|
}
|
|
|
|
// ProveBatch call rust ffi to generate batch proof.
|
|
func (p *ProverCore) ProveBatch(taskID string, chunkInfos []*message.ChunkInfo, chunkProofs []*message.ChunkProof) (*message.BatchProof, error) {
|
|
if p.cfg.ProofType != message.ProofTypeBatch {
|
|
return nil, fmt.Errorf("prover is not a batch-prover (type: %v), but is trying to prove a batch", p.cfg.ProofType)
|
|
}
|
|
|
|
chunkInfosByt, err := json.Marshal(chunkInfos)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
chunkProofsByt, err := json.Marshal(chunkProofs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
isValid, err := p.checkChunkProofs(chunkProofsByt)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !isValid {
|
|
return nil, fmt.Errorf("non-match chunk protocol, task-id: %s", taskID)
|
|
}
|
|
|
|
proofByt, err := p.proveBatch(chunkInfosByt, chunkProofsByt)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to generate batch proof: %v", err)
|
|
}
|
|
|
|
err = p.mayDumpProof(taskID, proofByt)
|
|
if err != nil {
|
|
log.Error("Dump batch proof failed", "task-id", taskID, "error", err)
|
|
}
|
|
|
|
zkProof := &message.BatchProof{}
|
|
return zkProof, json.Unmarshal(proofByt, zkProof)
|
|
}
|
|
|
|
// ProveChunk call rust ffi to generate chunk proof.
|
|
func (p *ProverCore) ProveChunk(taskID string, traces []*types.BlockTrace) (*message.ChunkProof, error) {
|
|
if p.cfg.ProofType != message.ProofTypeChunk {
|
|
return nil, fmt.Errorf("prover is not a chunk-prover (type: %v), but is trying to prove a chunk", p.cfg.ProofType)
|
|
}
|
|
|
|
tracesByt, err := json.Marshal(traces)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
proofByt, err := p.proveChunk(tracesByt)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = p.mayDumpProof(taskID, proofByt)
|
|
if err != nil {
|
|
log.Error("Dump chunk proof failed", "task-id", taskID, "error", err)
|
|
}
|
|
|
|
zkProof := &message.ChunkProof{}
|
|
return zkProof, json.Unmarshal(proofByt, zkProof)
|
|
}
|
|
|
|
// TracesToChunkInfo convert traces to chunk info
|
|
func (p *ProverCore) TracesToChunkInfo(traces []*types.BlockTrace) (*message.ChunkInfo, error) {
|
|
tracesByt, err := json.Marshal(traces)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
chunkInfoByt := p.tracesToChunkInfo(tracesByt)
|
|
|
|
chunkInfo := &message.ChunkInfo{}
|
|
return chunkInfo, json.Unmarshal(chunkInfoByt, chunkInfo)
|
|
}
|
|
|
|
// CheckChunkProofsResponse represents the result of a chunk proof checking operation.
|
|
// Ok indicates whether the proof checking was successful.
|
|
// Error provides additional details in case the check failed.
|
|
type CheckChunkProofsResponse struct {
|
|
Ok bool `json:"ok"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
// ProofResult encapsulates the result from generating a proof.
|
|
// Message holds the generated proof in byte slice format.
|
|
// Error provides additional details in case the proof generation failed.
|
|
type ProofResult struct {
|
|
Message []byte `json:"message,omitempty"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
func (p *ProverCore) checkChunkProofs(chunkProofsByt []byte) (bool, error) {
|
|
chunkProofsStr := C.CString(string(chunkProofsByt))
|
|
defer C.free(unsafe.Pointer(chunkProofsStr))
|
|
|
|
log.Info("Start to check chunk proofs ...")
|
|
cResult := C.check_chunk_proofs(chunkProofsStr)
|
|
defer C.free_c_chars(cResult)
|
|
log.Info("Finish checking chunk proofs!")
|
|
|
|
var result CheckChunkProofsResponse
|
|
err := json.Unmarshal([]byte(C.GoString(cResult)), &result)
|
|
if err != nil {
|
|
return false, fmt.Errorf("failed to parse check chunk proofs result: %v", err)
|
|
}
|
|
|
|
if result.Error != "" {
|
|
return false, fmt.Errorf("failed to check chunk proofs: %s", result.Error)
|
|
}
|
|
|
|
return result.Ok, nil
|
|
}
|
|
|
|
func (p *ProverCore) proveBatch(chunkInfosByt []byte, chunkProofsByt []byte) ([]byte, error) {
|
|
chunkInfosStr := C.CString(string(chunkInfosByt))
|
|
chunkProofsStr := C.CString(string(chunkProofsByt))
|
|
|
|
defer func() {
|
|
C.free(unsafe.Pointer(chunkInfosStr))
|
|
C.free(unsafe.Pointer(chunkProofsStr))
|
|
}()
|
|
|
|
log.Info("Start to create batch proof ...")
|
|
bResult := C.gen_batch_proof(chunkInfosStr, chunkProofsStr)
|
|
defer C.free_c_chars(bResult)
|
|
log.Info("Finish creating batch proof!")
|
|
|
|
var result ProofResult
|
|
err := json.Unmarshal([]byte(C.GoString(bResult)), &result)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse batch proof result: %v", err)
|
|
}
|
|
|
|
if result.Error != "" {
|
|
return nil, fmt.Errorf("failed to generate batch proof: %s", result.Error)
|
|
}
|
|
|
|
return result.Message, nil
|
|
}
|
|
|
|
func (p *ProverCore) proveChunk(tracesByt []byte) ([]byte, error) {
|
|
tracesStr := C.CString(string(tracesByt))
|
|
defer C.free(unsafe.Pointer(tracesStr))
|
|
|
|
log.Info("Start to create chunk proof ...")
|
|
cProof := C.gen_chunk_proof(tracesStr)
|
|
defer C.free_c_chars(cProof)
|
|
log.Info("Finish creating chunk proof!")
|
|
|
|
var result ProofResult
|
|
err := json.Unmarshal([]byte(C.GoString(cProof)), &result)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse chunk proof result: %v", err)
|
|
}
|
|
|
|
if result.Error != "" {
|
|
return nil, fmt.Errorf("failed to generate chunk proof: %s", result.Error)
|
|
}
|
|
|
|
return result.Message, nil
|
|
}
|
|
|
|
func (p *ProverCore) mayDumpProof(id string, proofByt []byte) error {
|
|
if p.cfg.DumpDir == "" {
|
|
return nil
|
|
}
|
|
path := filepath.Join(p.cfg.DumpDir, id)
|
|
f, err := os.Create(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
if err = f.Close(); err != nil {
|
|
log.Error("failed to close proof dump file", "id", id, "error", err)
|
|
}
|
|
}()
|
|
log.Info("Saving proof", "task-id", id)
|
|
_, err = f.Write(proofByt)
|
|
return err
|
|
}
|
|
|
|
func (p *ProverCore) tracesToChunkInfo(tracesByt []byte) []byte {
|
|
tracesStr := C.CString(string(tracesByt))
|
|
defer C.free(unsafe.Pointer(tracesStr))
|
|
|
|
cChunkInfo := C.block_traces_to_chunk_info(tracesStr)
|
|
defer C.free_c_chars(cChunkInfo)
|
|
|
|
chunkInfo := C.GoString(cChunkInfo)
|
|
return []byte(chunkInfo)
|
|
}
|