package stage2 import ( . "kesim.org/seal/nizk" ) // Implements the proof and verification of a statement of the following form: // // ( Z=g^(x*y) && X=g^x && Y=g^y && Z_=g^(x_*y_) && X_=g^x_ && Y_=g^y_ ) // case "none" // || ( Z=g^(x*y) && X=g^x && Y=g^y && Z_=g^(x_*r_) && X_=g^x_ && R_=g^r_ && C=g^(a*b) && A=g^a && B=g^b ) // case "unset" // || ( Z=g^(x*r) && X=g^x && R=g^r && Z_=g^(x_*r_) && X_=g^x_ && R_=g^r_ && C=g^(a*b+1) && A=g^a && B=g^b ) // case "set" // // for given A, B, C, R, X, Y, Z, R_, X_, Y_, Z_ on the curve type Type int const ( None Type = iota Unset Set ) type Statement struct { typ Type a *Scalar b *Scalar r *Scalar x *Scalar y *Scalar r_ *Scalar x_ *Scalar y_ *Scalar *Commitment } type Commitment struct { A *Point B *Point C *Point R *Point X *Point Y *Point Z *Point R_ *Point X_ *Point Y_ *Point Z_ *Point } func NewStatement(typ Type) *Statement { var s [8]*Scalar for i := range s { s[i] = Curve.RandomScalar() } return NewStatementFromScalars(typ, s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]) } func NewStatementFromScalars(typ Type, a, b, r, x, y, r_, x_, y_ *Scalar) *Statement { if typ > Set || typ < None { panic("unknown type") } return &Statement{ typ: typ, a: a, b: b, r: r, x: x, y: y, r_: r_, x_: x_, y_: y_, Commitment: commitment(typ, a, b, r, x, y, r_, x_, y_), } } func commitment(typ Type, a, b, r, x, y, r_, x_, y_ *Scalar) *Commitment { var Z, Z_ *Point c := a.Mul(b) switch typ { case None: Z = G.Exp(x.Mul(y)) Z_ = G.Exp(x_.Mul(y_)) case Set: Z = G.Exp(x.Mul(r)) Z_ = G.Exp(x_.Mul(r_)) c = c.Add(One) case Unset: Z = G.Exp(x.Mul(y)) Z_ = G.Exp(x_.Mul(r_)) default: panic("not possible") } return &Commitment{ A: G.Exp(a), B: G.Exp(b), C: G.Exp(c), R: G.Exp(r), X: G.Exp(x), Y: G.Exp(y), Z: Z, R_: G.Exp(r_), X_: G.Exp(x_), Y_: G.Exp(y_), Z_: Z_, } } func (s *Statement) Commit() *Commitment { return s.Commitment } type Proof struct { Ch [3]*Scalar R1 [3]*Scalar R2 [3]*Scalar R3 [2]*Scalar } func (s *Statement) Proof() *Proof { var ( e1, e1_ [3]Bytes e2, e2_ [3]Bytes e3, e3_ [2]Bytes r1, r2 [3]*Scalar r3 [2]*Scalar w [2]*Scalar ) for _, scs := range [][]*Scalar{r1[:], r2[:], r3[:], w[:]} { for i := range scs { scs[i] = Curve.RandomScalar() } } switch s.typ { case None: e1[0] = G.Exp(r1[0]).Mul(s.X.Exp(w[0])) e1[1] = G.Exp(r1[1]).Mul(s.X_.Exp(w[0])) e1[2] = G.Exp(r1[2]).Mul(s.A.Exp(w[0])) e1_[0] = s.R.Exp(r1[0]).Mul(s.Z.Exp(w[0])) e1_[1] = s.R_.Exp(r1[1]).Mul(s.Z_.Exp(w[0])) e1_[2] = s.B.Exp(r1[2]).Mul(s.C.Div(G).Exp(w[0])) e2[0] = G.Exp(r2[0]).Mul(s.X.Exp(w[1])) e2[1] = G.Exp(r2[1]).Mul(s.X_.Exp(w[1])) e2[2] = G.Exp(r2[2]).Mul(s.A.Exp(w[1])) e2_[0] = s.Y.Exp(r2[0]).Mul(s.Z.Exp(w[1])) e2_[1] = s.R_.Exp(r2[1]).Mul(s.Z_.Exp(w[1])) e2_[2] = s.B.Exp(r2[2]).Mul(s.C.Exp(w[1])) e3[0] = G.Exp(r3[0]) e3[1] = G.Exp(r3[1]) e3_[0] = s.Y.Exp(r3[0]) e3_[1] = s.Y_.Exp(r3[1]) case Unset: e1[0] = G.Exp(r1[0]).Mul(s.X.Exp(w[0])) e1[1] = G.Exp(r1[1]).Mul(s.X_.Exp(w[0])) e1[2] = G.Exp(r1[2]).Mul(s.A.Exp(w[0])) e1_[0] = s.R.Exp(r1[0]).Mul(s.Z.Exp(w[0])) e1_[1] = s.R_.Exp(r1[1]).Mul(s.Z_.Exp(w[0])) e1_[2] = s.B.Exp(r1[2]).Mul(s.C.Div(G).Exp(w[0])) e2[0] = G.Exp(r2[0]) e2[1] = G.Exp(r2[1]) e2[2] = G.Exp(r2[2]) e2_[0] = s.Y.Exp(r2[0]) e2_[1] = s.R_.Exp(r2[1]) e2_[2] = s.B.Exp(r2[2]) e3[0] = G.Exp(r3[0]).Mul(s.X.Exp(w[1])) e3[1] = G.Exp(r3[1]).Mul(s.X_.Exp(w[1])) e3_[0] = s.Y.Exp(r3[0]).Mul(s.Z.Exp(w[1])) e3_[1] = s.Y_.Exp(r3[1]).Mul(s.Z_.Exp(w[1])) case Set: e1[0] = G.Exp(r1[0]) e1[1] = G.Exp(r1[1]) e1[2] = G.Exp(r1[2]) e1_[0] = s.R.Exp(r1[0]) e1_[1] = s.R_.Exp(r1[1]) e1_[2] = s.B.Exp(r1[2]) e2[0] = G.Exp(r2[0]).Mul(s.X.Exp(w[0])) e2[1] = G.Exp(r2[1]).Mul(s.X_.Exp(w[0])) e2[2] = G.Exp(r2[2]).Mul(s.A.Exp(w[0])) e2_[0] = s.Y.Exp(r2[0]).Mul(s.Z.Exp(w[0])) e2_[1] = s.R_.Exp(r2[1]).Mul(s.Z_.Exp(w[0])) e2_[2] = s.B.Exp(r2[2]).Mul(s.C.Exp(w[0])) e3[0] = G.Exp(r3[0]).Mul(s.X.Exp(w[1])) e3[1] = G.Exp(r3[1]).Mul(s.X_.Exp(w[1])) e3_[0] = s.Y.Exp(r3[0]).Mul(s.Z.Exp(w[1])) e3_[1] = s.Y_.Exp(r3[1]).Mul(s.Z_.Exp(w[1])) default: panic("not possible") } points := []Bytes{G, s.A, s.B, s.C, s.R, s.X, s.Y, s.Z, s.R_, s.X_, s.Y_, s.Z_} points = append(points, e1[:]...) points = append(points, e2[:]...) points = append(points, e3[:]...) points = append(points, e1_[:]...) points = append(points, e2_[:]...) points = append(points, e3_[:]...) ch := Challenge(points...) pr := &Proof{} switch s.typ { case None: pr.Ch[0] = w[0] pr.Ch[1] = w[1] pr.Ch[2] = ch.Sub(w[0]).Sub(w[1]) pr.R1[0] = r1[0] pr.R1[1] = r1[1] pr.R1[2] = r1[2] pr.R2[0] = r2[0] pr.R2[1] = r2[1] pr.R2[2] = r2[2] pr.R3[0] = r3[0].Sub(s.x.Mul(pr.Ch[2])) pr.R3[1] = r3[1].Sub(s.x_.Mul(pr.Ch[2])) case Unset: pr.Ch[0] = w[0] pr.Ch[1] = ch.Sub(w[0]).Sub(w[1]) pr.Ch[2] = w[1] pr.R1[0] = r1[0] pr.R1[1] = r1[1] pr.R1[2] = r1[2] pr.R2[0] = r2[0].Sub(s.x.Mul(pr.Ch[1])) pr.R2[1] = r2[1].Sub(s.x_.Mul(pr.Ch[1])) pr.R2[2] = r2[2].Sub(s.a.Mul(pr.Ch[1])) pr.R3[0] = r3[0] pr.R3[1] = r3[1] case Set: pr.Ch[0] = ch.Sub(w[0]).Sub(w[1]) pr.Ch[1] = w[0] pr.Ch[2] = w[1] pr.R1[0] = r1[0].Sub(s.x.Mul(pr.Ch[0])) pr.R1[1] = r1[1].Sub(s.x_.Mul(pr.Ch[0])) pr.R1[2] = r1[2].Sub(s.a.Mul(pr.Ch[0])) pr.R2[0] = r2[0] pr.R2[1] = r2[1] pr.R2[2] = r2[2] pr.R3[0] = r3[0] pr.R3[1] = r3[1] default: panic("unreachable") } return pr } func (c *Commitment) Verify(p *Proof) bool { var ( e1, e1_ [3]Bytes e2, e2_ [3]Bytes e3, e3_ [2]Bytes ) e1[0] = G.Exp(p.R1[0]).Mul(c.X.Exp(p.Ch[0])) e1[1] = G.Exp(p.R1[1]).Mul(c.X_.Exp(p.Ch[0])) e1[2] = G.Exp(p.R1[2]).Mul(c.A.Exp(p.Ch[0])) e1_[0] = c.R.Exp(p.R1[0]).Mul(c.Z.Exp(p.Ch[0])) e1_[1] = c.R_.Exp(p.R1[1]).Mul(c.Z_.Exp(p.Ch[0])) e1_[2] = c.B.Exp(p.R1[2]).Mul(c.C.Div(G).Exp(p.Ch[0])) e2[0] = G.Exp(p.R2[0]).Mul(c.X.Exp(p.Ch[1])) e2[1] = G.Exp(p.R2[1]).Mul(c.X_.Exp(p.Ch[1])) e2[2] = G.Exp(p.R2[2]).Mul(c.A.Exp(p.Ch[1])) e2_[0] = c.Y.Exp(p.R2[0]).Mul(c.Z.Exp(p.Ch[1])) e2_[1] = c.R_.Exp(p.R2[1]).Mul(c.Z_.Exp(p.Ch[1])) e2_[2] = c.B.Exp(p.R2[2]).Mul(c.C.Exp(p.Ch[1])) e3[0] = G.Exp(p.R3[0]).Mul(c.X.Exp(p.Ch[2])) e3[1] = G.Exp(p.R3[1]).Mul(c.X_.Exp(p.Ch[2])) e3_[0] = c.Y.Exp(p.R3[0]).Mul(c.Z.Exp(p.Ch[2])) e3_[1] = c.Y_.Exp(p.R3[1]).Mul(c.Z_.Exp(p.Ch[2])) points := []Bytes{G, c.A, c.B, c.C, c.R, c.X, c.Y, c.Z, c.R_, c.X_, c.Y_, c.Z_} points = append(points, e1[:]...) points = append(points, e2[:]...) points = append(points, e3[:]...) points = append(points, e1_[:]...) points = append(points, e2_[:]...) points = append(points, e3_[:]...) ch := Challenge(points...) return p.Ch[0].Add(p.Ch[1]).Add(p.Ch[2]).Equal(ch) }