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 }