func (ps *PairShuffle) Prove( pi []int, g, h abstract.Point, beta []abstract.Scalar, X, Y []abstract.Point, rand cipher.Stream, ctx proof.ProverContext) error { grp := ps.grp k := ps.k if k != len(pi) || k != len(beta) { panic("mismatched vector lengths") } // Compute pi^-1 inverse permutation piinv := make([]int, k) for i := 0; i < k; i++ { piinv[pi[i]] = i } // P step 1 p1 := &ps.p1 z := grp.Scalar() // scratch // pick random secrets u := make([]abstract.Scalar, k) w := make([]abstract.Scalar, k) a := make([]abstract.Scalar, k) var tau0, nu, gamma abstract.Scalar ctx.PriRand(u, w, a, &tau0, &nu, &gamma) // compute public commits p1.Gamma = grp.Point().Mul(g, gamma) wbeta := grp.Scalar() // scratch wbetasum := grp.Scalar().Set(tau0) p1.Lambda1 = grp.Point().Null() p1.Lambda2 = grp.Point().Null() XY := grp.Point() // scratch wu := grp.Scalar() // scratch for i := 0; i < k; i++ { p1.A[i] = grp.Point().Mul(g, a[i]) p1.C[i] = grp.Point().Mul(g, z.Mul(gamma, a[pi[i]])) p1.U[i] = grp.Point().Mul(g, u[i]) p1.W[i] = grp.Point().Mul(g, z.Mul(gamma, w[i])) wbetasum.Add(wbetasum, wbeta.Mul(w[i], beta[pi[i]])) p1.Lambda1.Add(p1.Lambda1, XY.Mul(X[i], wu.Sub(w[piinv[i]], u[i]))) p1.Lambda2.Add(p1.Lambda2, XY.Mul(Y[i], wu.Sub(w[piinv[i]], u[i]))) } p1.Lambda1.Add(p1.Lambda1, XY.Mul(g, wbetasum)) p1.Lambda2.Add(p1.Lambda2, XY.Mul(h, wbetasum)) if err := ctx.Put(p1); err != nil { return err } // V step 2 v2 := &ps.v2 if err := ctx.PubRand(v2); err != nil { return err } B := make([]abstract.Point, k) for i := 0; i < k; i++ { P := grp.Point().Mul(g, v2.Zrho[i]) B[i] = P.Sub(P, p1.U[i]) } // P step 3 p3 := &ps.p3 b := make([]abstract.Scalar, k) for i := 0; i < k; i++ { b[i] = grp.Scalar().Sub(v2.Zrho[i], u[i]) } d := make([]abstract.Scalar, k) for i := 0; i < k; i++ { d[i] = grp.Scalar().Mul(gamma, b[pi[i]]) p3.D[i] = grp.Point().Mul(g, d[i]) } if err := ctx.Put(p3); err != nil { return err } // V step 4 v4 := &ps.v4 if err := ctx.PubRand(v4); err != nil { return err } // P step 5 p5 := &ps.p5 r := make([]abstract.Scalar, k) for i := 0; i < k; i++ { r[i] = grp.Scalar().Add(a[i], z.Mul(v4.Zlambda, b[i])) } s := make([]abstract.Scalar, k) for i := 0; i < k; i++ { s[i] = grp.Scalar().Mul(gamma, r[pi[i]]) } p5.Ztau = grp.Scalar().Neg(tau0) for i := 0; i < k; i++ { p5.Zsigma[i] = grp.Scalar().Add(w[i], b[pi[i]]) p5.Ztau.Add(p5.Ztau, z.Mul(b[i], beta[i])) } if err := ctx.Put(p5); err != nil { return err } // P,V step 6: embedded simple k-shuffle proof return ps.pv6.Prove(g, gamma, r, s, rand, ctx) }
// The "Simple k-shuffle" defined in section 3 of // Neff, "Verifiable Mixing (Shuffling) of ElGamal Pairs", 2004. // The Scalar vector y must be a permutation of Scalar vector x // but with all elements multiplied by common Scalar gamma. func (ss *SimpleShuffle) Prove(G abstract.Point, gamma abstract.Scalar, x, y []abstract.Scalar, rand cipher.Stream, ctx proof.ProverContext) error { grp := ss.grp k := len(x) if k <= 1 { panic("can't shuffle length 1 vector") } if k != len(y) { panic("mismatched vector lengths") } // // Dump input vectors to show their correspondences // for i := 0; i < k; i++ { // println("x",grp.Scalar().Mul(gamma,x[i]).String()) // } // for i := 0; i < k; i++ { // println("y",y[i].String()) // } // Step 0: inputs for i := 0; i < k; i++ { // (4) ss.p0.X[i] = grp.Point().Mul(G, x[i]) ss.p0.Y[i] = grp.Point().Mul(G, y[i]) } if err := ctx.Put(ss.p0); err != nil { return err } // V step 1 if err := ctx.PubRand(&ss.v1); err != nil { return err } t := ss.v1.Zt // P step 2 gamma_t := grp.Scalar().Mul(gamma, t) xhat := make([]abstract.Scalar, k) yhat := make([]abstract.Scalar, k) for i := 0; i < k; i++ { // (5) and (6) xhat,yhat vectors xhat[i] = grp.Scalar().Sub(x[i], t) yhat[i] = grp.Scalar().Sub(y[i], gamma_t) } thlen := 2*k - 1 // (7) theta and Theta vectors theta := make([]abstract.Scalar, thlen) ctx.PriRand(theta) Theta := make([]abstract.Point, thlen+1) Theta[0] = thenc(grp, G, nil, nil, theta[0], yhat[0]) for i := 1; i < k; i++ { Theta[i] = thenc(grp, G, theta[i-1], xhat[i], theta[i], yhat[i]) } for i := k; i < thlen; i++ { Theta[i] = thenc(grp, G, theta[i-1], gamma, theta[i], nil) } Theta[thlen] = thenc(grp, G, theta[thlen-1], gamma, nil, nil) ss.p2.Theta = Theta if err := ctx.Put(ss.p2); err != nil { return err } // V step 3 if err := ctx.PubRand(&ss.v3); err != nil { return err } c := ss.v3.Zc // P step 4 alpha := make([]abstract.Scalar, thlen) runprod := grp.Scalar().Set(c) for i := 0; i < k; i++ { // (8) runprod.Mul(runprod, xhat[i]) runprod.Div(runprod, yhat[i]) alpha[i] = grp.Scalar().Add(theta[i], runprod) } gammainv := grp.Scalar().Inv(gamma) rungamma := grp.Scalar().Set(c) for i := 1; i < k; i++ { rungamma.Mul(rungamma, gammainv) alpha[thlen-i] = grp.Scalar().Add(theta[thlen-i], rungamma) } ss.p4.Zalpha = alpha if err := ctx.Put(ss.p4); err != nil { return err } return nil }