github.com/consensys/gnark@v0.11.0/test/blueprint_solver.go (about) 1 package test 2 3 import ( 4 "math/big" 5 6 "github.com/consensys/gnark/constraint" 7 "github.com/consensys/gnark/internal/utils" 8 ) 9 10 // blueprintSolver is a constraint.Solver that can be used to test a circuit 11 // it is a separate type to avoid method collisions with the engine. 12 type blueprintSolver struct { 13 internalVariables []*big.Int 14 q *big.Int 15 } 16 17 // implements constraint.Solver 18 19 func (s *blueprintSolver) SetValue(vID uint32, f constraint.Element) { 20 if int(vID) > len(s.internalVariables) { 21 panic("out of bounds") 22 } 23 v := s.ToBigInt(f) 24 s.internalVariables[vID].Set(v) 25 } 26 27 func (s *blueprintSolver) GetValue(cID, vID uint32) constraint.Element { 28 panic("not implemented in test.Engine") 29 } 30 func (s *blueprintSolver) GetCoeff(cID uint32) constraint.Element { 31 panic("not implemented in test.Engine") 32 } 33 34 func (s *blueprintSolver) IsSolved(vID uint32) bool { 35 panic("not implemented in test.Engine") 36 } 37 38 // implements constraint.Field 39 40 func (s *blueprintSolver) FromInterface(i interface{}) constraint.Element { 41 b := utils.FromInterface(i) 42 return s.toElement(&b) 43 } 44 45 func (s *blueprintSolver) ToBigInt(f constraint.Element) *big.Int { 46 r := new(big.Int) 47 fBytes := f.Bytes() 48 r.SetBytes(fBytes[:]) 49 return r 50 } 51 func (s *blueprintSolver) Mul(a, b constraint.Element) constraint.Element { 52 ba, bb := s.ToBigInt(a), s.ToBigInt(b) 53 ba.Mul(ba, bb).Mod(ba, s.q) 54 return s.toElement(ba) 55 } 56 func (s *blueprintSolver) Add(a, b constraint.Element) constraint.Element { 57 ba, bb := s.ToBigInt(a), s.ToBigInt(b) 58 ba.Add(ba, bb).Mod(ba, s.q) 59 return s.toElement(ba) 60 } 61 func (s *blueprintSolver) Sub(a, b constraint.Element) constraint.Element { 62 ba, bb := s.ToBigInt(a), s.ToBigInt(b) 63 ba.Sub(ba, bb).Mod(ba, s.q) 64 return s.toElement(ba) 65 } 66 func (s *blueprintSolver) Neg(a constraint.Element) constraint.Element { 67 ba := s.ToBigInt(a) 68 ba.Neg(ba).Mod(ba, s.q) 69 return s.toElement(ba) 70 } 71 func (s *blueprintSolver) Inverse(a constraint.Element) (constraint.Element, bool) { 72 ba := s.ToBigInt(a) 73 r := ba.ModInverse(ba, s.q) 74 return s.toElement(ba), r != nil 75 } 76 func (s *blueprintSolver) One() constraint.Element { 77 b := new(big.Int).SetUint64(1) 78 return s.toElement(b) 79 } 80 func (s *blueprintSolver) IsOne(a constraint.Element) bool { 81 b := s.ToBigInt(a) 82 return b.IsUint64() && b.Uint64() == 1 83 } 84 85 func (s *blueprintSolver) String(a constraint.Element) string { 86 b := s.ToBigInt(a) 87 return b.String() 88 } 89 90 func (s *blueprintSolver) Uint64(a constraint.Element) (uint64, bool) { 91 b := s.ToBigInt(a) 92 return b.Uint64(), b.IsUint64() 93 } 94 95 func (s *blueprintSolver) Read(calldata []uint32) (constraint.Element, int) { 96 // We encoded big.Int as constraint.Element on 12 uint32 words. 97 var r constraint.Element 98 for i := 0; i < len(r); i++ { 99 index := i * 2 100 r[i] = uint64(calldata[index])<<32 | uint64(calldata[index+1]) 101 } 102 return r, len(r) * 2 103 } 104 105 func (s *blueprintSolver) toElement(b *big.Int) constraint.Element { 106 return bigIntToElement(b) 107 } 108 109 func bigIntToElement(b *big.Int) constraint.Element { 110 if b.Sign() == -1 { 111 panic("negative value") 112 } 113 bytes := b.Bytes() 114 if len(bytes) > 48 { 115 panic("value too big") 116 } 117 var paddedBytes [48]byte 118 copy(paddedBytes[48-len(bytes):], bytes[:]) 119 120 var r constraint.Element 121 r.SetBytes(paddedBytes) 122 123 return r 124 } 125 126 // wrappedBigInt is a wrapper around big.Int to implement the frontend.CanonicalVariable interface 127 type wrappedBigInt struct { 128 *big.Int 129 } 130 131 func (w wrappedBigInt) Compress(to *[]uint32) { 132 // convert to Element. 133 e := bigIntToElement(w.Int) 134 135 // append the uint32 words to the slice 136 for i := 0; i < len(e); i++ { 137 *to = append(*to, uint32(e[i]>>32)) 138 *to = append(*to, uint32(e[i]&0xffffffff)) 139 } 140 }