github.com/consensys/gnark@v0.11.0/internal/generator/backend/template/representations/coeff.go.tmpl (about) 1 import ( 2 "github.com/consensys/gnark/constraint" 3 "github.com/consensys/gnark/internal/utils" 4 "math/big" 5 "encoding/binary" 6 "errors" 7 {{ template "import_fr" . }} 8 ) 9 10 // CoeffTable ensure we store unique coefficients in the constraint system 11 type CoeffTable struct { 12 Coefficients []fr.Element 13 mCoeffs map[fr.Element]uint32 // maps coefficient to coeffID 14 } 15 16 func newCoeffTable(capacity int) CoeffTable { 17 r := CoeffTable{ 18 Coefficients: make([]fr.Element, 5, 5+capacity), 19 mCoeffs: make(map[fr.Element]uint32, capacity), 20 } 21 22 r.Coefficients[constraint.CoeffIdZero].SetUint64(0) 23 r.Coefficients[constraint.CoeffIdOne].SetOne() 24 r.Coefficients[constraint.CoeffIdTwo].SetUint64(2) 25 r.Coefficients[constraint.CoeffIdMinusOne].SetInt64(-1) 26 r.Coefficients[constraint.CoeffIdMinusTwo].SetInt64(-2) 27 28 return r 29 30 } 31 32 func (ct *CoeffTable) toBytes() []byte { 33 buf := make([]byte, 0, 8 + len(ct.Coefficients)*fr.Bytes) 34 ctLen := uint64(len(ct.Coefficients)) 35 36 buf = binary.LittleEndian.AppendUint64(buf, ctLen) 37 for _, c := range ct.Coefficients { 38 for _, w := range c { 39 buf = binary.LittleEndian.AppendUint64(buf, w) 40 } 41 } 42 43 return buf 44 } 45 46 func (ct *CoeffTable) fromBytes(buf []byte) error { 47 if len(buf) < 8 { 48 return errors.New("invalid buffer size") 49 } 50 ctLen := binary.LittleEndian.Uint64(buf[:8]) 51 buf = buf[8:] 52 53 if uint64(len(buf)) < ctLen*fr.Bytes { 54 return errors.New("invalid buffer size") 55 } 56 ct.Coefficients = make([]fr.Element, ctLen) 57 for i := uint64(0); i < ctLen; i++ { 58 var c fr.Element 59 k := int(i) * fr.Bytes 60 for j := 0; j < fr.Limbs; j++ { 61 c[j] = binary.LittleEndian.Uint64(buf[k + j * 8 : k + (j+1)*8]) 62 } 63 ct.Coefficients[i] = c 64 } 65 return nil 66 } 67 68 func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { 69 c := (*fr.Element)(coeff[:]) 70 var cID uint32 71 if c.IsZero() { 72 cID = constraint.CoeffIdZero 73 } else if c.IsOne() { 74 cID = constraint.CoeffIdOne 75 } else if c.Equal(&two) { 76 cID = constraint.CoeffIdTwo 77 } else if c.Equal(&minusOne) { 78 cID = constraint.CoeffIdMinusOne 79 } else if c.Equal(&minusTwo) { 80 cID = constraint.CoeffIdMinusTwo 81 } else { 82 cc := *c 83 if id, ok := ct.mCoeffs[cc]; ok { 84 cID = id 85 } else { 86 cID = uint32(len(ct.Coefficients)) 87 ct.Coefficients = append(ct.Coefficients, cc) 88 ct.mCoeffs[cc] = cID 89 } 90 } 91 return cID 92 } 93 94 func (ct *CoeffTable) MakeTerm(coeff constraint.Element, variableID int) constraint.Term { 95 cID := ct.AddCoeff(coeff) 96 return constraint.Term{VID: uint32(variableID), CID: cID} 97 } 98 99 // CoeffToString implements constraint.Resolver 100 func (ct *CoeffTable) CoeffToString(cID int) string { 101 return ct.Coefficients[cID].String() 102 } 103 104 // implements constraint.Field 105 type field struct{} 106 107 var _ constraint.Field = &field{} 108 109 var ( 110 two fr.Element 111 minusOne fr.Element 112 minusTwo fr.Element 113 ) 114 115 func init() { 116 minusOne.SetOne() 117 minusOne.Neg(&minusOne) 118 two.SetOne() 119 two.Double(&two) 120 minusTwo.Neg(&two) 121 } 122 123 124 125 126 func (engine *field) FromInterface(i interface{}) constraint.Element { 127 var e fr.Element 128 if _, err := e.SetInterface(i); err != nil { 129 // need to clean that --> some code path are dissimilar 130 // for example setting a fr.Element from an fp.Element 131 // fails with the above but succeeds through big int... (2-chains) 132 b := utils.FromInterface(i) 133 e.SetBigInt(&b) 134 } 135 var r constraint.Element 136 copy(r[:], e[:]) 137 return r 138 } 139 func (engine *field) ToBigInt(c constraint.Element) *big.Int { 140 e := (*fr.Element)(c[:]) 141 r := new(big.Int) 142 e.BigInt(r) 143 return r 144 145 } 146 func (engine *field) Mul(a, b constraint.Element) constraint.Element { 147 _a := (*fr.Element)(a[:]) 148 _b := (*fr.Element)(b[:]) 149 _a.Mul(_a, _b) 150 return a 151 } 152 153 func (engine *field) Add(a, b constraint.Element) constraint.Element { 154 _a := (*fr.Element)(a[:]) 155 _b := (*fr.Element)(b[:]) 156 _a.Add(_a, _b) 157 return a 158 } 159 func (engine *field) Sub(a, b constraint.Element) constraint.Element { 160 _a := (*fr.Element)(a[:]) 161 _b := (*fr.Element)(b[:]) 162 _a.Sub(_a, _b) 163 return a 164 } 165 func (engine *field) Neg(a constraint.Element) constraint.Element { 166 e := (*fr.Element)(a[:]) 167 e.Neg(e) 168 return a 169 170 } 171 func (engine *field) Inverse(a constraint.Element) (constraint.Element, bool) { 172 if a.IsZero() { 173 return a, false 174 } 175 e := (*fr.Element)(a[:]) 176 if e.IsZero() { 177 return a, false 178 } else if e.IsOne() { 179 return a, true 180 } 181 var t fr.Element 182 t.Neg(e) 183 if t.IsOne() { 184 return a, true 185 } 186 187 e.Inverse(e) 188 return a, true 189 } 190 191 func (engine *field) IsOne(a constraint.Element) bool { 192 e := (*fr.Element)(a[:]) 193 return e.IsOne() 194 } 195 196 func (engine *field) One() constraint.Element { 197 e := fr.One() 198 var r constraint.Element 199 copy(r[:], e[:]) 200 return r 201 } 202 203 func (engine *field) String(a constraint.Element) string { 204 e := (*fr.Element)(a[:]) 205 return e.String() 206 } 207 208 func (engine *field) Uint64(a constraint.Element) (uint64, bool) { 209 e := (*fr.Element)(a[:]) 210 if !e.IsUint64() { 211 return 0, false 212 } 213 return e.Uint64(), true 214 }