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  }