-
Notifications
You must be signed in to change notification settings - Fork 0
/
tx_ivc.go
136 lines (112 loc) · 3.95 KB
/
tx_ivc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package txivc
import (
"fmt"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/algebra"
"github.com/consensys/gnark/std/math/emulated"
"github.com/consensys/gnark/std/math/uints"
stdplonk "github.com/consensys/gnark/std/recursion/plonk"
)
/*
*
Base case to generate initial proof to get things started
*/
type Sha256CircuitBaseCase[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT] struct {
//CurrTxPrefix [5]uints.U8 //5
//PrevTxId [32]uints.U8
//CurrTxPost [154]uints.U8 //81
RawTx []uints.U8 `gnark:",public"`
//double-sha256 hash of the concatenation of above fields. Not reversed, so not quite a TxId
CurrTxId [32]uints.U8 `gnark:",public"` //probably needs to provide the reversed version to save circuit space
}
/*
*
Base case implementation
*/
func (circuit *Sha256CircuitBaseCase[FR, G1El, G2El, GtEl]) Define(api frontend.API) error {
uapi, err := uints.New[uints.U32](api)
//do double-sha256
firstHash, err := calculateSha256(api, circuit.RawTx)
if err != nil {
return err
}
calculatedTxId, err := calculateSha256(api, firstHash)
if err != nil {
return err
}
//assert current public input matches calculated txId
for i := range circuit.CurrTxId {
uapi.ByteAssertEq(circuit.CurrTxId[i], calculatedTxId[i])
}
return nil
}
/*
*
General case to continue with proofs
*/
type Sha256Circuit[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT] struct {
PreviousProof stdplonk.Proof[FR, G1El, G2El]
PreviousVk stdplonk.VerifyingKey[FR, G1El, G2El] `gnark:"-"` // constant verification key
PreviousWitness stdplonk.Witness[FR]
CurrTxPrefix [5]uints.U8 //5
PrevTxId [32]uints.U8
CurrTxPost [188]uints.U8 //81
//double-sha256 hash of the concatenation of above fields. Not reversed, so not quite a TxId
//TokenId [32]uints.U8 `gnark:",public"` //probably needs to provide the reversed version to save circuit space
CurrTxId [32]uints.U8 `gnark:",public"` //probably needs to provide the reversed version to save circuit space
}
func isNullArray(arr []uints.U8) bool {
zeroVal := uints.NewU8(0)
for i := range arr {
if arr[i] != zeroVal {
return false
}
}
return true
}
func (circuit *Sha256Circuit[FR, G1El, G2El, GtEl]) Define(api frontend.API) error {
//assert that the token ID is being preserved
uapi, err := uints.New[uints.U32](api)
//field, err := emulated.NewField[FR](api)
//
////fmt.Printf("Checking previous txnid against witness")
//for i := range circuit.CurrTxId {
// //assert that the previous txn id (in witness) matches that of the current outpoint (in prevTxnId)
// witnessTxIdBits := field.ToBits(&circuit.PreviousWitness.Public[i])
// witnessTxIdByte := bits.FromBinary(api, witnessTxIdBits)
// uapi.ByteAssertEq(circuit.PrevTxId[i], uapi.ByteValueOf(witnessTxIdByte))
//}
//fmt.Printf("PrevTxnId checks out")
//reconstitute the transaction hex
fullTx := append(circuit.CurrTxPrefix[:], circuit.PrevTxId[:]...)
fullTx = append(fullTx, circuit.CurrTxPost[:]...)
//do double-sha256
firstHash, err := calculateSha256(api, fullTx)
if err != nil {
return err
}
calculatedTxId, err := calculateSha256(api, firstHash)
if err != nil {
return err
}
//loop over the individual bytes of the calculated hash
//and compare them to the expected digest
//fmt.Printf("Checking claimed digest matches\n")
for i := range circuit.CurrTxId {
uapi.ByteAssertEq(circuit.CurrTxId[i], calculatedTxId[i])
}
//fmt.Printf("Claimed digest matches OK\n")
// construct a verifier in-circuit
verifier, err := stdplonk.NewVerifier[FR, G1El, G2El, GtEl](api)
if err != nil {
return fmt.Errorf("new verifier: %w", err)
}
//fmt.Printf("Verifying previous proof\n")
//verify the previous proof
err = verifier.AssertProof(circuit.PreviousVk, circuit.PreviousProof, circuit.PreviousWitness, stdplonk.WithCompleteArithmetic())
//fmt.Printf("Proof checks out\n")
if err != nil {
return err
}
return nil
}