github.com/incognitochain/go-incognito-sdk@v1.0.1/privacy/polynomials.go (about)

     1  package privacy
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/incognitochain/go-incognito-sdk/common"
     6  	"github.com/incognitochain/go-incognito-sdk/privacy/curve25519"
     7  	"math/big"
     8  	"math/rand"
     9  	"time"
    10  )
    11  
    12  // Data structure for a polynomial
    13  // Just an array in Reverse
    14  // f(x) = 3x^3 + 2x + 1 => [1 2 0 3]
    15  type Poly []*big.Int
    16  
    17  // Helper function for generating a polynomial with given integers
    18  func newPoly(coeffs ...int) (p Poly) {
    19  	p = make([]*big.Int, len(coeffs))
    20  	for i := 0; i < len(coeffs); i++ {
    21  		p[i] = big.NewInt(int64(coeffs[i]))
    22  	}
    23  	p.trim()
    24  	return
    25  }
    26  
    27  func ScalarToBigInt(sc *Scalar) *big.Int {
    28  	keyR := Reverse(sc.key)
    29  	keyRByte := keyR.ToBytes()
    30  	bi := new(big.Int).SetBytes(keyRByte[:])
    31  	return bi
    32  }
    33  
    34  func BigIntToScalar(bi *big.Int) *Scalar {
    35  	biByte := common.AddPaddingBigInt(bi, Ed25519KeySize)
    36  	var key curve25519.Key
    37  	key.FromBytes(SliceToArray(biByte))
    38  	keyR := Reverse(key)
    39  	sc, err := new(Scalar).SetKey(&keyR)
    40  	if err != nil {
    41  		return nil
    42  	}
    43  	return sc
    44  }
    45  
    46  // Returns a polynomial with random coefficients
    47  // You can give the degree of the polynomial
    48  // A random coefficients have a [0, 2^bits) integer
    49  func randomPoly(degree, bits int64) (p Poly) {
    50  	p = make(Poly, degree+1)
    51  	rr := rand.New(rand.NewSource(time.Now().UnixNano()))
    52  	exp := big.NewInt(2)
    53  	exp.Exp(exp, big.NewInt(bits), nil)
    54  	for i := 0; i <= p.GetDegree(); i++ {
    55  		p[i] = new(big.Int)
    56  		p[i].Rand(rr, exp)
    57  	}
    58  	p.trim()
    59  	return
    60  }
    61  
    62  // trim() makes sure that the highest coefficient never has zero value
    63  // when you add or subtract two polynomials, sometimes the highest coefficient goes zero
    64  // if you don't remove the highest and zero coefficient, GetDegree() returns the wrong result
    65  func (p *Poly) trim() {
    66  	var last int = 0
    67  	for i := p.GetDegree(); i > 0; i-- { // why i > 0, not i >=0? do not remove the constant
    68  		if (*p)[i].Sign() != 0 {
    69  			last = i
    70  			break
    71  		}
    72  	}
    73  	*p = (*p)[:(last + 1)]
    74  }
    75  
    76  // isZero() checks if P = 0
    77  func (p *Poly) isZero() bool {
    78  	if p.GetDegree() == 0 && (*p)[0].Cmp(big.NewInt(0)) == 0 {
    79  		return true
    80  	}
    81  	return false
    82  }
    83  
    84  // GetDegree returns the degree
    85  // if p = x^3 + 2x^2 + 5, GetDegree() returns 3
    86  func (p Poly) GetDegree() int {
    87  	return len(p) - 1
    88  }
    89  
    90  // pretty print
    91  func (p Poly) String() (s string) {
    92  	s = "["
    93  	for i := len(p) - 1; i >= 0; i-- {
    94  		switch p[i].Sign() {
    95  		case -1:
    96  			if i == len(p)-1 {
    97  				s += "-"
    98  			} else {
    99  				s += " - "
   100  			}
   101  			if i == 0 || p[i].Int64() != -1 {
   102  				s += p[i].String()[1:]
   103  			}
   104  		case 0:
   105  			continue
   106  		case 1:
   107  			if i < len(p)-1 {
   108  				s += " + "
   109  			}
   110  			if i == 0 || p[i].Int64() != 1 {
   111  				s += p[i].String()
   112  			}
   113  		}
   114  		if i > 0 {
   115  			s += "x"
   116  			if i > 1 {
   117  				s += "^" + fmt.Sprintf("%d", i)
   118  			}
   119  		}
   120  	}
   121  	if s == "[" {
   122  		s += "0"
   123  	}
   124  	s += "]"
   125  	return
   126  }
   127  
   128  // Compare() compares two polynomials and returns -1, 0, or 1
   129  // if P == Q, returns 0
   130  // if P > Q, returns 1
   131  // if P < Q, returns -1
   132  func (p *Poly) compare(q *Poly) int {
   133  	switch {
   134  	case p.GetDegree() > q.GetDegree():
   135  		return 1
   136  	case p.GetDegree() < q.GetDegree():
   137  		return -1
   138  	}
   139  	for i := 0; i <= p.GetDegree(); i++ {
   140  		switch (*p)[i].Cmp((*q)[i]) {
   141  		case 1:
   142  			return 1
   143  		case -1:
   144  			return -1
   145  		}
   146  	}
   147  	return 0
   148  }
   149  
   150  // Add() adds two polynomials
   151  // modulo m can be nil
   152  func (p Poly) add(q Poly, m *big.Int) Poly {
   153  	if p.compare(&q) < 0 {
   154  		return q.add(p, m)
   155  	}
   156  	var r Poly = make([]*big.Int, len(p))
   157  	for i := 0; i < len(q); i++ {
   158  		a := new(big.Int)
   159  		a.Add(p[i], q[i])
   160  		r[i] = a
   161  	}
   162  	for i := len(q); i < len(p); i++ {
   163  		a := new(big.Int)
   164  		a.Set(p[i])
   165  		r[i] = a
   166  	}
   167  	if m != nil {
   168  		for i := 0; i < len(p); i++ {
   169  			r[i].Mod(r[i], m)
   170  		}
   171  	}
   172  	r.trim()
   173  	return r
   174  }
   175  
   176  // Neg() returns a polynomial Q = -P
   177  func (p *Poly) neg() Poly {
   178  	var q Poly = make([]*big.Int, len(*p))
   179  	for i := 0; i < len(*p); i++ {
   180  		b := new(big.Int)
   181  		b.Neg((*p)[i])
   182  		q[i] = b
   183  	}
   184  	return q
   185  }
   186  
   187  // Clone() does deep-copy
   188  // adjust increases the degree of copied polynomial
   189  // adjust cannot have a negative integer
   190  // for example, P = x + 1 and adjust = 2, Clone() returns x^3 + x^2
   191  func (p Poly) clone(adjust int) Poly {
   192  	var q Poly = make([]*big.Int, len(p)+adjust)
   193  	if adjust < 0 {
   194  		return newPoly(0)
   195  	}
   196  	for i := 0; i < adjust; i++ {
   197  		q[i] = big.NewInt(0)
   198  	}
   199  	for i := adjust; i < len(p)+adjust; i++ {
   200  		b := new(big.Int)
   201  		b.Set(p[i-adjust])
   202  		q[i] = b
   203  	}
   204  	return q
   205  }
   206  
   207  // sanitize() does modular arithmetic with m
   208  func (p *Poly) sanitize(m *big.Int) {
   209  	if m == nil {
   210  		return
   211  	}
   212  	for i := 0; i <= (*p).GetDegree(); i++ {
   213  		(*p)[i].Mod((*p)[i], m)
   214  	}
   215  	p.trim()
   216  }
   217  
   218  // Sub() subtracts P from Q
   219  // Since we already have Add(), Sub() does Add(P, -Q)
   220  func (p Poly) Sub(q Poly, m *big.Int) Poly {
   221  	r := q.neg()
   222  	return p.add(r, m)
   223  }
   224  
   225  // P * Q
   226  func (p Poly) Mul(q Poly, m *big.Int) Poly {
   227  	if m != nil {
   228  		p.sanitize(m)
   229  		q.sanitize(m)
   230  	}
   231  	var r Poly = make([]*big.Int, p.GetDegree()+q.GetDegree()+1)
   232  	for i := 0; i < len(r); i++ {
   233  		r[i] = big.NewInt(0)
   234  	}
   235  	for i := 0; i < len(p); i++ {
   236  		for j := 0; j < len(q); j++ {
   237  			a := new(big.Int)
   238  			a.Mul(p[i], q[j])
   239  			a.Add(a, r[i+j])
   240  			if m != nil {
   241  				a = new(big.Int).Mod(a, m)
   242  			}
   243  			r[i+j] = a
   244  		}
   245  	}
   246  	r.trim()
   247  	return r
   248  }
   249  
   250  // returns (P / Q, P % Q)
   251  func (p Poly) div(q Poly, m *big.Int) (quo, rem Poly) {
   252  	if m != nil {
   253  		p.sanitize(m)
   254  		q.sanitize(m)
   255  	}
   256  	if p.GetDegree() < q.GetDegree() || q.isZero() {
   257  		quo = newPoly(0)
   258  		rem = p.clone(0)
   259  		return
   260  	}
   261  	quo = make([]*big.Int, p.GetDegree()-q.GetDegree()+1)
   262  	rem = p.clone(0)
   263  	for i := 0; i < len(quo); i++ {
   264  		quo[i] = big.NewInt(0)
   265  	}
   266  	t := p.clone(0)
   267  	qd := q.GetDegree()
   268  	for {
   269  		td := t.GetDegree()
   270  		rd := td - qd
   271  		if rd < 0 || t.isZero() {
   272  			rem = t
   273  			break
   274  		}
   275  		r := new(big.Int)
   276  		if m != nil {
   277  			r.ModInverse(q[qd], m)
   278  			r.Mul(r, t[td])
   279  			r.Mod(r, m)
   280  		} else {
   281  			r.Div(t[td], q[qd])
   282  		}
   283  		// if r == 0, it means that the highest coefficient of the result is not an integer
   284  		// this polynomial library handles integer coefficients
   285  		if r.Cmp(big.NewInt(0)) == 0 {
   286  			quo = newPoly(0)
   287  			rem = p.clone(0)
   288  			return
   289  		}
   290  		u := q.clone(rd)
   291  		for i := rd; i < len(u); i++ {
   292  			u[i].Mul(u[i], r)
   293  			if m != nil {
   294  				u[i].Mod(u[i], m)
   295  			}
   296  		}
   297  		t = t.Sub(u, m)
   298  		t.trim()
   299  		quo[rd] = r
   300  	}
   301  	quo.trim()
   302  	rem.trim()
   303  	return
   304  }
   305  
   306  // returns the greatest common divisor(GCD) of P and Q (Euclidean algorithm)
   307  func (p Poly) gcd(q Poly, m *big.Int) Poly {
   308  	if p.compare(&q) < 0 {
   309  		return q.gcd(p, m)
   310  	}
   311  	if q.isZero() {
   312  		return p
   313  	} else {
   314  		_, rem := p.div(q, m)
   315  		return q.gcd(rem, m)
   316  	}
   317  }
   318  
   319  // Eval() returns p(x) where x is the given big integer
   320  func (p Poly) eval(x *big.Int, m *big.Int) (y *big.Int) {
   321  	y = big.NewInt(0)
   322  	accx := big.NewInt(1)
   323  	xd := new(big.Int)
   324  	for i := 0; i <= p.GetDegree(); i++ {
   325  		xd.Mul(accx, p[i])
   326  		y.Add(y, xd)
   327  		accx.Mul(accx, x)
   328  		if m != nil {
   329  			y.Mod(y, m)
   330  			accx.Mod(accx, m)
   331  		}
   332  	}
   333  	return y
   334  }