github.com/incognitochain/go-incognito-sdk@v1.0.1/privacy/zkp/oneoutofmany/oneoutofmany.go (about) 1 package oneoutofmany 2 3 import ( 4 "github.com/incognitochain/go-incognito-sdk/privacy" 5 "github.com/incognitochain/go-incognito-sdk/privacy/zkp/utils" 6 "github.com/pkg/errors" 7 "math/big" 8 ) 9 10 // This protocol proves in zero-knowledge that one-out-of-N commitments contains 0 11 12 // Statement to be proved 13 type OneOutOfManyStatement struct { 14 Commitments []*privacy.Point 15 } 16 17 // Statement's witness 18 type OneOutOfManyWitness struct { 19 stmt *OneOutOfManyStatement 20 rand *privacy.Scalar 21 indexIsZero uint64 22 } 23 24 // Statement's proof 25 type OneOutOfManyProof struct { 26 Statement *OneOutOfManyStatement 27 cl, ca, cb, cd []*privacy.Point 28 f, za, zb []*privacy.Scalar 29 zd *privacy.Scalar 30 } 31 32 func (proof OneOutOfManyProof) ValidateSanity() bool { 33 if len(proof.cl) != privacy.CommitmentRingSizeExp || len(proof.ca) != privacy.CommitmentRingSizeExp || 34 len(proof.cb) != privacy.CommitmentRingSizeExp || len(proof.cd) != privacy.CommitmentRingSizeExp || 35 len(proof.f) != privacy.CommitmentRingSizeExp || len(proof.za) != privacy.CommitmentRingSizeExp || 36 len(proof.zb) != privacy.CommitmentRingSizeExp { 37 return false 38 } 39 40 for i := 0; i < len(proof.cl); i++ { 41 if !proof.cl[i].PointValid() { 42 return false 43 } 44 if !proof.ca[i].PointValid() { 45 return false 46 } 47 if !proof.cb[i].PointValid() { 48 return false 49 } 50 if !proof.cd[i].PointValid() { 51 return false 52 } 53 54 if !proof.f[i].ScalarValid() { 55 return false 56 } 57 if !proof.za[i].ScalarValid() { 58 return false 59 } 60 if !proof.zb[i].ScalarValid() { 61 return false 62 } 63 } 64 65 return proof.zd.ScalarValid() 66 } 67 68 func (proof OneOutOfManyProof) isNil() bool { 69 if proof.cl == nil { 70 return true 71 } 72 if proof.ca == nil { 73 return true 74 } 75 if proof.cb == nil { 76 return true 77 } 78 if proof.cd == nil { 79 return true 80 } 81 if proof.f == nil { 82 return true 83 } 84 if proof.za == nil { 85 return true 86 } 87 if proof.zb == nil { 88 return true 89 } 90 return proof.zd == nil 91 } 92 93 func (proof *OneOutOfManyProof) Init() *OneOutOfManyProof { 94 proof.zd = new(privacy.Scalar) 95 proof.Statement = new(OneOutOfManyStatement) 96 97 return proof 98 } 99 100 // Set sets Statement 101 func (stmt *OneOutOfManyStatement) Set(commitments []*privacy.Point) { 102 stmt.Commitments = commitments 103 } 104 105 // Set sets Witness 106 func (wit *OneOutOfManyWitness) Set(commitments []*privacy.Point, rand *privacy.Scalar, indexIsZero uint64) { 107 wit.stmt = new(OneOutOfManyStatement) 108 wit.stmt.Set(commitments) 109 110 wit.indexIsZero = indexIsZero 111 wit.rand = rand 112 } 113 114 // Set sets Proof 115 func (proof *OneOutOfManyProof) Set( 116 commitments []*privacy.Point, 117 cl, ca, cb, cd []*privacy.Point, 118 f, za, zb []*privacy.Scalar, 119 zd *privacy.Scalar) { 120 121 proof.Statement = new(OneOutOfManyStatement) 122 proof.Statement.Set(commitments) 123 124 proof.cl, proof.ca, proof.cb, proof.cd = cl, ca, cb, cd 125 proof.f, proof.za, proof.zb = f, za, zb 126 proof.zd = zd 127 } 128 129 // Bytes converts one of many proof to bytes array 130 func (proof OneOutOfManyProof) Bytes() []byte { 131 // if proof is nil, return an empty array 132 if proof.isNil() { 133 return []byte{} 134 } 135 136 // N = 2^n 137 n := privacy.CommitmentRingSizeExp 138 139 var bytes []byte 140 141 // convert array cl to bytes array 142 for i := 0; i < n; i++ { 143 bytes = append(bytes, proof.cl[i].ToBytesS()...) 144 } 145 // convert array ca to bytes array 146 for i := 0; i < n; i++ { 147 //fmt.Printf("proof.ca[i]: %v\n", proof.ca[i]) 148 //fmt.Printf("proof.ca[i]: %v\n", proof.ca[i].Compress()) 149 bytes = append(bytes, proof.ca[i].ToBytesS()...) 150 } 151 152 // convert array cb to bytes array 153 for i := 0; i < n; i++ { 154 bytes = append(bytes, proof.cb[i].ToBytesS()...) 155 } 156 157 // convert array cd to bytes array 158 for i := 0; i < n; i++ { 159 bytes = append(bytes, proof.cd[i].ToBytesS()...) 160 } 161 162 // convert array f to bytes array 163 for i := 0; i < n; i++ { 164 bytes = append(bytes, proof.f[i].ToBytesS()...) 165 } 166 167 // convert array za to bytes array 168 for i := 0; i < n; i++ { 169 bytes = append(bytes, proof.za[i].ToBytesS()...) 170 } 171 172 // convert array zb to bytes array 173 for i := 0; i < n; i++ { 174 bytes = append(bytes, proof.zb[i].ToBytesS()...) 175 } 176 177 // convert array zd to bytes array 178 bytes = append(bytes, proof.zd.ToBytesS()...) 179 180 return bytes 181 } 182 183 // SetBytes converts an array of bytes to an object of OneOutOfManyProof 184 func (proof *OneOutOfManyProof) SetBytes(bytes []byte) error { 185 if len(bytes) == 0 { 186 return nil 187 } 188 189 n := privacy.CommitmentRingSizeExp 190 191 offset := 0 192 var err error 193 194 // get cl array 195 proof.cl = make([]*privacy.Point, n) 196 for i := 0; i < n; i++ { 197 proof.cl[i], err = new(privacy.Point).FromBytesS(bytes[offset : offset+privacy.Ed25519KeySize]) 198 if err != nil { 199 return err 200 } 201 offset = offset + privacy.Ed25519KeySize 202 } 203 204 // get ca array 205 proof.ca = make([]*privacy.Point, n) 206 for i := 0; i < n; i++ { 207 proof.ca[i], err = new(privacy.Point).FromBytesS(bytes[offset : offset+privacy.Ed25519KeySize]) 208 if err != nil { 209 return err 210 } 211 offset = offset + privacy.Ed25519KeySize 212 } 213 214 // get cb array 215 proof.cb = make([]*privacy.Point, n) 216 for i := 0; i < n; i++ { 217 proof.cb[i], err = new(privacy.Point).FromBytesS(bytes[offset : offset+privacy.Ed25519KeySize]) 218 if err != nil { 219 return err 220 } 221 offset = offset + privacy.Ed25519KeySize 222 } 223 224 // get cd array 225 proof.cd = make([]*privacy.Point, n) 226 for i := 0; i < n; i++ { 227 proof.cd[i], err = new(privacy.Point).FromBytesS(bytes[offset : offset+privacy.Ed25519KeySize]) 228 if err != nil { 229 return err 230 } 231 offset = offset + privacy.Ed25519KeySize 232 } 233 234 // get f array 235 proof.f = make([]*privacy.Scalar, n) 236 for i := 0; i < n; i++ { 237 proof.f[i] = new(privacy.Scalar).FromBytesS(bytes[offset : offset+privacy.Ed25519KeySize]) 238 offset = offset + privacy.Ed25519KeySize 239 } 240 241 // get za array 242 proof.za = make([]*privacy.Scalar, n) 243 for i := 0; i < n; i++ { 244 proof.za[i] = new(privacy.Scalar).FromBytesS(bytes[offset : offset+privacy.Ed25519KeySize]) 245 offset = offset + privacy.Ed25519KeySize 246 } 247 248 // get zb array 249 proof.zb = make([]*privacy.Scalar, n) 250 for i := 0; i < n; i++ { 251 proof.zb[i] = new(privacy.Scalar).FromBytesS(bytes[offset : offset+privacy.Ed25519KeySize]) 252 offset = offset + privacy.Ed25519KeySize 253 } 254 255 // get zd 256 proof.zd = new(privacy.Scalar).FromBytesS(bytes[offset : offset+privacy.Ed25519KeySize]) 257 258 return nil 259 } 260 261 // Prove produces a proof for the statement 262 func (wit OneOutOfManyWitness) Prove() (*OneOutOfManyProof, error) { 263 // Check the number of Commitment list's elements 264 N := len(wit.stmt.Commitments) 265 if N != privacy.CommitmentRingSize { 266 return nil, errors.New("the number of Commitment list's elements must be equal to CMRingSize") 267 } 268 n := privacy.CommitmentRingSizeExp 269 // Check indexIsZero 270 if wit.indexIsZero > uint64(N) { 271 return nil, errors.New("Index is zero must be Index in list of commitments") 272 } 273 // represent indexIsZero in binary 274 indexIsZeroBinary := privacy.ConvertIntToBinary(int(wit.indexIsZero), n) 275 // 276 r := make([]*privacy.Scalar, n) 277 a := make([]*privacy.Scalar, n) 278 s := make([]*privacy.Scalar, n) 279 t := make([]*privacy.Scalar, n) 280 u := make([]*privacy.Scalar, n) 281 cl := make([]*privacy.Point, n) 282 ca := make([]*privacy.Point, n) 283 cb := make([]*privacy.Point, n) 284 cd := make([]*privacy.Point, n) 285 for j := 0; j < n; j++ { 286 // Generate random numbers 287 r[j] = privacy.RandomScalar() 288 a[j] = privacy.RandomScalar() 289 s[j] = privacy.RandomScalar() 290 t[j] = privacy.RandomScalar() 291 u[j] = privacy.RandomScalar() 292 // convert indexIsZeroBinary[j] to privacy.Scalar 293 indexInt := new(privacy.Scalar).FromUint64(uint64(indexIsZeroBinary[j])) 294 // Calculate cl, ca, cb, cd 295 // cl = Com(l, r) 296 cl[j] = privacy.PedCom.CommitAtIndex(indexInt, r[j], privacy.PedersenPrivateKeyIndex) 297 // ca = Com(a, s) 298 ca[j] = privacy.PedCom.CommitAtIndex(a[j], s[j], privacy.PedersenPrivateKeyIndex) 299 // cb = Com(la, t) 300 la := new(privacy.Scalar).Mul(indexInt, a[j]) 301 //la.Mod(la, privacy.Curve.Params().N) 302 cb[j] = privacy.PedCom.CommitAtIndex(la, t[j], privacy.PedersenPrivateKeyIndex) 303 } 304 // Calculate: cd_k = ci^pi,k 305 for k := 0; k < n; k++ { 306 // Calculate pi,k which is coefficient of x^k in polynomial pi(x) 307 cd[k] = new(privacy.Point).Identity() 308 for i := 0; i < N; i++ { 309 iBinary := privacy.ConvertIntToBinary(i, n) 310 pik := getCoefficient(iBinary, k, n, a, indexIsZeroBinary) 311 cd[k].Add(cd[k], new(privacy.Point).ScalarMult(wit.stmt.Commitments[i], pik)) 312 } 313 cd[k].Add(cd[k], privacy.PedCom.CommitAtIndex(new(privacy.Scalar).FromUint64(0), u[k], privacy.PedersenPrivateKeyIndex)) 314 } 315 // Calculate x 316 cmtsInBytes := make([][]byte, 0) 317 for _, cmts := range wit.stmt.Commitments{ 318 cmtsInBytes = append(cmtsInBytes, cmts.ToBytesS()) 319 } 320 x := utils.GenerateChallenge(cmtsInBytes) 321 for j := 0; j < n; j++ { 322 x = utils.GenerateChallenge([][]byte{ 323 x.ToBytesS(), 324 cl[j].ToBytesS(), 325 ca[j].ToBytesS(), 326 cb[j].ToBytesS(), 327 cd[j].ToBytesS(), 328 }) 329 } 330 // Calculate za, zb zd 331 za := make([]*privacy.Scalar, n) 332 zb := make([]*privacy.Scalar, n) 333 f := make([]*privacy.Scalar, n) 334 for j := 0; j < n; j++ { 335 // f = lx + a 336 f[j] = new(privacy.Scalar).Mul(new(privacy.Scalar).FromUint64(uint64(indexIsZeroBinary[j])), x) 337 f[j].Add(f[j], a[j]) 338 // za = s + rx 339 za[j] = new(privacy.Scalar).Mul(r[j], x) 340 za[j].Add(za[j], s[j]) 341 // zb = r(x - f) + t 342 zb[j] = new(privacy.Scalar).Sub(x, f[j]) 343 zb[j].Mul(zb[j], r[j]) 344 zb[j].Add(zb[j], t[j]) 345 } 346 // zd = rand * x^n - sum_{k=0}^{n-1} u[k] * x^k 347 xi := new(privacy.Scalar).FromUint64(1) 348 sum := new(privacy.Scalar).FromUint64(0) 349 for k := 0; k < n; k++ { 350 tmp := new(privacy.Scalar).Mul(xi, u[k]) 351 sum.Add(sum, tmp) 352 xi.Mul(xi, x) 353 } 354 zd := new(privacy.Scalar).Mul(xi, wit.rand) 355 zd.Sub(zd, sum) 356 proof := new(OneOutOfManyProof).Init() 357 proof.Set(wit.stmt.Commitments, cl, ca, cb, cd, f, za, zb, zd) 358 return proof, nil 359 } 360 361 // Verify verifies a proof output by Prove 362 func (proof OneOutOfManyProof) Verify() (bool, error) { 363 N := len(proof.Statement.Commitments) 364 365 // the number of Commitment list's elements must be equal to CMRingSize 366 if N != privacy.CommitmentRingSize { 367 return false, errors.New("Invalid length of commitments list in one out of many proof") 368 } 369 n := privacy.CommitmentRingSizeExp 370 371 //Calculate x 372 x := new(privacy.Scalar).FromUint64(0) 373 374 for j := 0; j < n; j++ { 375 x = utils.GenerateChallenge([][]byte{x.ToBytesS(), proof.cl[j].ToBytesS(), proof.ca[j].ToBytesS(), proof.cb[j].ToBytesS(), proof.cd[j].ToBytesS()}) 376 } 377 378 for i := 0; i < n; i++ { 379 //Check cl^x * ca = Com(f, za) 380 leftPoint1 := new(privacy.Point).ScalarMult(proof.cl[i], x) 381 leftPoint1.Add(leftPoint1, proof.ca[i]) 382 383 rightPoint1 := privacy.PedCom.CommitAtIndex(proof.f[i], proof.za[i], privacy.PedersenPrivateKeyIndex) 384 385 if !privacy.IsPointEqual(leftPoint1, rightPoint1) { 386 return false, errors.New("verify one out of many proof statement 1 failed") 387 } 388 389 //Check cl^(x-f) * cb = Com(0, zb) 390 xSubF := new(privacy.Scalar).Sub(x, proof.f[i]) 391 392 leftPoint2 := new(privacy.Point).ScalarMult(proof.cl[i], xSubF) 393 leftPoint2.Add(leftPoint2, proof.cb[i]) 394 rightPoint2 := privacy.PedCom.CommitAtIndex(new(privacy.Scalar).FromUint64(0), proof.zb[i], privacy.PedersenPrivateKeyIndex) 395 396 if !privacy.IsPointEqual(leftPoint2, rightPoint2) { 397 return false, errors.New("verify one out of many proof statement 2 failed") 398 } 399 } 400 401 leftPoint3 := new(privacy.Point).Identity() 402 leftPoint32 := new(privacy.Point).Identity() 403 404 for i := 0; i < N; i++ { 405 iBinary := privacy.ConvertIntToBinary(i, n) 406 407 exp := new(privacy.Scalar).FromUint64(1) 408 fji := new(privacy.Scalar).FromUint64(1) 409 for j := 0; j < n; j++ { 410 if iBinary[j] == 1 { 411 fji.Set(proof.f[j]) 412 } else { 413 fji.Sub(x, proof.f[j]) 414 } 415 416 exp.Mul(exp, fji) 417 } 418 419 leftPoint3.Add(leftPoint3, new(privacy.Point).ScalarMult(proof.Statement.Commitments[i], exp)) 420 } 421 422 tmp2 := new(privacy.Scalar).FromUint64(1) 423 for k := 0; k < n; k++ { 424 xk := new(privacy.Scalar).Sub(new(privacy.Scalar).FromUint64(0), tmp2) 425 leftPoint32.Add(leftPoint32, new(privacy.Point).ScalarMult(proof.cd[k], xk)) 426 tmp2.Mul(tmp2, x) 427 } 428 429 leftPoint3.Add(leftPoint3, leftPoint32) 430 431 rightPoint3 := privacy.PedCom.CommitAtIndex(new(privacy.Scalar).FromUint64(0), proof.zd, privacy.PedersenPrivateKeyIndex) 432 433 if !privacy.IsPointEqual(leftPoint3, rightPoint3) { 434 return false, errors.New("verify one out of many proof statement 3 failed") 435 } 436 437 return true, nil 438 } 439 440 // Get coefficient of x^k in the polynomial p_i(x) 441 func getCoefficient(iBinary []byte, k int, n int, scLs []*privacy.Scalar, l []byte) *privacy.Scalar { 442 443 a := make([]*big.Int, len(scLs)) 444 for i := 0; i < len(scLs); i++ { 445 a[i] = privacy.ScalarToBigInt(scLs[i]) 446 } 447 448 //AP2 449 curveOrder := privacy.LInt 450 res := privacy.Poly{big.NewInt(1)} 451 var fji privacy.Poly 452 for j := n - 1; j >= 0; j-- { 453 fj := privacy.Poly{a[j], big.NewInt(int64(l[j]))} 454 if iBinary[j] == 0 { 455 fji = privacy.Poly{big.NewInt(0), big.NewInt(1)}.Sub(fj, curveOrder) 456 } else { 457 fji = fj 458 } 459 res = res.Mul(fji, curveOrder) 460 } 461 462 var sc2 *privacy.Scalar 463 if res.GetDegree() < k { 464 sc2 = new(privacy.Scalar).FromUint64(0) 465 } else { 466 sc2 = privacy.BigIntToScalar(res[k]) 467 } 468 return sc2 469 } 470 471 func getCoefficientInt(iBinary []byte, k int, n int, a []*big.Int, l []byte) *big.Int { 472 res := privacy.Poly{big.NewInt(1)} 473 var fji privacy.Poly 474 475 for j := n - 1; j >= 0; j-- { 476 fj := privacy.Poly{a[j], big.NewInt(int64(l[j]))} 477 if iBinary[j] == 0 { 478 fji = privacy.Poly{big.NewInt(0), big.NewInt(1)}.Sub(fj, privacy.LInt) 479 } else { 480 fji = fj 481 } 482 483 res = res.Mul(fji, privacy.LInt) 484 } 485 486 if res.GetDegree() < k { 487 return big.NewInt(0) 488 } 489 return res[k] 490 }