github.com/Evanesco-Labs/go-evanesco@v1.0.1/zkpminer/problem/problem.go (about)

     1  package problem
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"github.com/consensys/gnark-crypto/ecc"
     8  	"github.com/consensys/gnark/backend"
     9  	"github.com/consensys/gnark/backend/groth16"
    10  	"github.com/consensys/gnark/frontend"
    11  	"github.com/Evanesco-Labs/go-evanesco/core/types"
    12  	"github.com/Evanesco-Labs/go-evanesco/crypto"
    13  	"github.com/Evanesco-Labs/go-evanesco/zkpminer/keypair"
    14  	//"github.com/ethereum/go-ethereum/zkpminer/log"
    15  	"github.com/Evanesco-Labs/go-evanesco/log"
    16  	"github.com/Evanesco-Labs/go-evanesco/zkpminer/vrf"
    17  	"math/big"
    18  	"os"
    19  )
    20  
    21  type GetHeaderByNum = func(uint642 uint64) (*types.Header, error)
    22  
    23  var (
    24  	ErrorInvalidR1CSPath = errors.New("r1cs path invalid")
    25  	ErrorInvalidPkPath   = errors.New("proving key path invalid")
    26  	ErrorInvalidVkPath   = errors.New("verifying key path invalid")
    27  )
    28  
    29  func CompileCircuit() frontend.CompiledConstraintSystem {
    30  	var mimcCircuit Circuit
    31  	r1cs, err := frontend.Compile(ecc.BN254, backend.GROTH16, &mimcCircuit)
    32  	if err != nil {
    33  		return nil
    34  	}
    35  	return r1cs
    36  }
    37  
    38  func SetupZKP(r1cs frontend.CompiledConstraintSystem) (groth16.ProvingKey, groth16.VerifyingKey) {
    39  	pk, vk, err := groth16.Setup(r1cs)
    40  	if err != nil {
    41  		return nil, nil
    42  	}
    43  	return pk, vk
    44  }
    45  
    46  func NewProvingKey(b []byte) groth16.ProvingKey {
    47  	k := groth16.NewProvingKey(ecc.BN254)
    48  	buf := bytes.Buffer{}
    49  	buf.Write(b)
    50  	_, err := k.ReadFrom(&buf)
    51  	if err != nil {
    52  		return nil
    53  	}
    54  	return k
    55  }
    56  
    57  func NewVerifyingKey(b []byte) groth16.VerifyingKey {
    58  	k := groth16.NewVerifyingKey(ecc.BN254)
    59  	buf := bytes.Buffer{}
    60  	buf.Write(b)
    61  	_, err := k.ReadFrom(&buf)
    62  	if err != nil {
    63  		return nil
    64  	}
    65  	return k
    66  }
    67  
    68  func ZKPProve(r1cs frontend.CompiledConstraintSystem, pk groth16.ProvingKey, preimage []byte) ([]byte, []byte) {
    69  	var c Circuit
    70  	c.PreImage.Assign(preimage)
    71  	mimchash := MimcHasher.Hash(preimage)
    72  	c.Hash.Assign(mimchash)
    73  	proof, err := groth16.Prove(r1cs, pk, &c)
    74  	if err != nil {
    75  		log.Debug("groth16 error:","err", err.Error())
    76  		return nil, nil
    77  	}
    78  	buf := bytes.Buffer{}
    79  	proof.WriteTo(&buf)
    80  	return mimchash, buf.Bytes()
    81  }
    82  
    83  func ZKPVerify(vk groth16.VerifyingKey, preimage []byte, hash []byte, proof []byte) bool {
    84  	p := groth16.NewProof(ecc.BN254)
    85  	buf := bytes.Buffer{}
    86  	buf.Write(proof)
    87  	_, err := p.ReadFrom(&buf)
    88  	if err != nil {
    89  		return false
    90  	}
    91  	var c Circuit
    92  	c.Hash.Assign(hash)
    93  	c.PreImage.Assign(preimage)
    94  	err = groth16.Verify(p, vk, &c)
    95  	if err != nil {
    96  		return false
    97  	}
    98  	return true
    99  }
   100  
   101  type Prover struct {
   102  	r1cs frontend.CompiledConstraintSystem
   103  	pk   groth16.ProvingKey
   104  }
   105  
   106  func (p *Prover) Prove(preimage []byte) ([]byte, []byte) {
   107  	return ZKPProve(p.r1cs, p.pk, preimage)
   108  }
   109  
   110  func NewProblemProver(pkPath string) (*Prover, error) {
   111  	log.Info("Compiling ZKP circuit")
   112  	r1cs := CompileCircuit()
   113  	pkFile, err := os.OpenFile(pkPath, os.O_RDONLY, 0644)
   114  	if err != nil {
   115  		return nil, ErrorInvalidPkPath
   116  	}
   117  	defer pkFile.Close()
   118  	log.Info("Loading ZKP prove key. This takes a few minutes")
   119  	pk := groth16.NewProvingKey(ecc.BN254)
   120  	_, err = pk.ReadFrom(pkFile)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  	return &Prover{
   125  		r1cs: r1cs,
   126  		pk:   pk,
   127  	}, nil
   128  }
   129  
   130  type Verifier struct {
   131  	coinbaseInterval uint64
   132  	submitAdvance    uint64
   133  	vk               groth16.VerifyingKey
   134  	getHeaderByNum   GetHeaderByNum
   135  }
   136  
   137  func NewProblemVerifier(vkPath string, interval, advance uint64, getHeaderByNum GetHeaderByNum) (*Verifier, error) {
   138  	vkFile, err := os.OpenFile(vkPath, os.O_RDONLY, 0644)
   139  	if err != nil {
   140  		return nil, ErrorInvalidVkPath
   141  	}
   142  	defer vkFile.Close()
   143  	vk := groth16.NewVerifyingKey(ecc.BN254)
   144  	_, err = vk.ReadFrom(vkFile)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	return &Verifier{
   149  		coinbaseInterval: interval,
   150  		submitAdvance:    advance,
   151  		vk:               vk,
   152  		getHeaderByNum:   getHeaderByNum,
   153  	}, nil
   154  }
   155  
   156  func (v *Verifier) VerifyZKP(preimage []byte, mimcHash []byte, proof []byte) bool {
   157  	return ZKPVerify(v.vk, preimage, mimcHash, proof)
   158  }
   159  
   160  //todo: add additional check if the lottery miner pledged
   161  func (v *Verifier) VerifyLottery(lottery *types.Lottery, sigBytes []byte, lastCoinbaseHeader *types.Header) (res bool) {
   162  
   163  	defer func() {
   164  		if r := recover();r!= nil{
   165  			res = false
   166  		}
   167  	}()
   168  
   169  	if lottery == nil || sigBytes == nil || lastCoinbaseHeader == nil {
   170  		return false
   171  	}
   172  	msg, err := json.Marshal(lottery)
   173  	if err != nil {
   174  		log.Debug("marshal err", "err",err)
   175  		return false
   176  	}
   177  
   178  	msgHash := crypto.Keccak256(msg)
   179  	ecdsaPK, err := crypto.SigToPub(msgHash, sigBytes)
   180  	if err != nil {
   181  		log.Debug("sig to pub err", "err",err)
   182  		return false
   183  	}
   184  	pk, err := keypair.NewPublicKey(ecdsaPK)
   185  	if err != nil {
   186  		log.Debug("new pub key err", "err",err)
   187  		return false
   188  	}
   189  
   190  	if crypto.PubkeyToAddress(*ecdsaPK) != lottery.MinerAddr {
   191  		log.Debug("miner address not equal")
   192  		return false
   193  	}
   194  
   195  	lastCoinbaseHash := lastCoinbaseHeader.Hash()
   196  	index, err := vrf.ProofToHash(pk, lastCoinbaseHash[:], lottery.VrfProof)
   197  	if err != nil {
   198  		log.Debug("vrf proof err")
   199  		return false
   200  	}
   201  
   202  	if index != lottery.Index {
   203  		log.Debug("index not the same")
   204  		return false
   205  	}
   206  
   207  	challengeHeight := lastCoinbaseHeader.Number.Uint64() + GetChallengeIndex(index, uint64(v.coinbaseInterval)-uint64(v.submitAdvance))
   208  	challengeHeader, err := v.getHeaderByNum(challengeHeight)
   209  	if err != nil || challengeHeader == nil {
   210  		log.Debug("get header err", "challenge height",challengeHeight)
   211  		return false
   212  	}
   213  
   214  	if challengeHeader.Hash() != lottery.ChallengeHeaderHash {
   215  		log.Debug("head not equal")
   216  		return false
   217  	}
   218  
   219  	addrBytes := lottery.MinerAddr.Bytes()
   220  	preimage := append(addrBytes, lottery.ChallengeHeaderHash[:]...)
   221  	preimage = crypto.Keccak256(preimage)
   222  	return v.VerifyZKP(preimage, lottery.MimcHash, lottery.ZkpProof)
   223  }
   224  
   225  func GetChallengeIndex(index [32]byte, interval uint64) uint64 {
   226  	n := new(big.Int).SetBytes(index[:])
   227  	module := new(big.Int).SetUint64(interval)
   228  	return new(big.Int).Mod(n, module).Uint64()
   229  }