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  }