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  }