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 }