A very experimental PLC implementation which uses BFT consensus for decentralization
1package proof
2
3import (
4 "encoding/hex"
5 "slices"
6 "testing"
7 "time"
8
9 "github.com/consensys/gnark-crypto/ecc"
10 "github.com/consensys/gnark-crypto/ecc/bn254"
11 "github.com/consensys/gnark/backend/groth16"
12 "github.com/consensys/gnark/frontend"
13 "github.com/consensys/gnark/frontend/cs/r1cs"
14 "github.com/samber/lo"
15 "github.com/stretchr/testify/require"
16
17 "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc"
18)
19
20func TestBlockChallenge(t *testing.T) {
21 st := time.Now()
22
23 var bcCircuit BlockChallengeCircuit
24 r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &bcCircuit)
25 require.NoError(t, err)
26
27 t.Log("Compile took", time.Since(st))
28
29 st = time.Now()
30 pk, vk, err := groth16.Setup(r1cs)
31 require.NoError(t, err)
32 t.Log("Setup took", time.Since(st))
33
34 st = time.Now()
35 origValidatorID := lo.Must(hex.DecodeString("deadbeefdeadbeefdeadbeefdeadbeef"))
36 origLastCommitHash := lo.Must(hex.DecodeString("deadf00ddeadf00ddeadf00ddeadbeef"))
37
38 opDataSlice := slices.Repeat(lo.Must(hex.DecodeString("ffee")), 775)
39 opData := [OperationDataLength]byte{}
40 copy(opData[:], opDataSlice)
41 assignmentShared := buildBlockChallengeCircuitAssignmentShared(origLastCommitHash, opData)
42 assignment := buildBlockChallengeCircuitAssignmentFull(assignmentShared, origValidatorID)
43 t.Log("Out of circuit took", time.Since(st))
44
45 st = time.Now()
46 witness, err := frontend.NewWitness(assignment, bn254.ID.ScalarField())
47 require.NoError(t, err)
48 t.Log("Witness took", time.Since(st))
49
50 st = time.Now()
51 proof, err := groth16.Prove(r1cs, pk, witness)
52 require.NoError(t, err)
53 t.Log("Prove took", time.Since(st))
54
55 publicWitness, err := witness.Public()
56 require.NoError(t, err)
57
58 st = time.Now()
59 err = groth16.Verify(proof, vk, publicWitness)
60 require.NoError(t, err)
61 t.Log("Verify took", time.Since(st))
62}
63
64func buildBlockChallengeCircuitAssignmentShared(lastCommitHash []byte, data [OperationDataLength]byte) BlockChallengeCircuit {
65 var assignment BlockChallengeCircuit
66
67 if len(lastCommitHash) > 31 {
68 lastCommitHash = lastCommitHash[len(lastCommitHash)-31:]
69 }
70 assignment.LastCommitHash = lastCommitHash
71
72 for i := 0; i < len(assignment.OperationData); i++ {
73 d := data[31*i : 31*(i+1)]
74 assignment.OperationData[i] = d
75 }
76
77 return assignment
78}
79
80func buildBlockChallengeCircuitAssignmentFull(shared BlockChallengeCircuit, validatorAddress []byte) *BlockChallengeCircuit {
81 h := mimc.NewMiMC()
82
83 h.Write(validatorAddress)
84 h.Write(shared.LastCommitHash.([]byte))
85
86 for i := 0; i < len(shared.OperationData); i++ {
87 h.Write(shared.OperationData[i].([]byte))
88 }
89
90 shared.ValidatorAddress = validatorAddress
91 shared.SpecificHash = h.Sum(nil)
92
93 return &shared
94}