Browse Source

Start of implementation: message 1 complete

Ian Goldberg 3 years ago
commit
6887efdc22
2 changed files with 258 additions and 0 deletions
  1. 194 0
      gk15.go
  2. 64 0
      main.go

+ 194 - 0
gk15.go

@@ -0,0 +1,194 @@
+/*
+ * An implementation of Groth and Kohlweiss, "One-out-of-Many Proofs: Or
+ * How to Leak a Secret and Spend a Coin", Eurocrypt 2015
+ * https://eprint.iacr.org/2014/764.pdf
+ */
+
+package main
+
+import (
+	"fmt"
+	"go.dedis.ch/kyber"
+	"go.dedis.ch/kyber/util/random"
+)
+
+type GroupParams struct {
+	/* A group of prime order */
+	group kyber.Group
+	/* Three generators of the group; the relative discrete logs
+	 * must be unknown. Commitments to a value x with randomness r
+	 * are x*A + r*B.  Y is used to pad the list of commitments to a
+	 * power of 2. */
+	A, B, Y kyber.Point
+}
+
+type PubState struct {
+	cl, ca, cb, cd []kyber.Point
+}
+
+type PrivState struct {
+	r, a, s, t, rho []kyber.Scalar
+}
+
+type Proof struct {
+}
+
+// Multiply a polynomial expressed as a slice of coefficients by the
+// scalar a
+func polymul(group kyber.Group, poly []kyber.Scalar, a kyber.Scalar) {
+	numcoeffs := len(poly)
+	for i := 0 ; i < numcoeffs ; i++ {
+		poly[i] = group.Scalar().Mul(poly[i], a)
+	}
+}
+
+// Multiply a polynomial expressed as a slice of coefficients by
+// the linear polynomial x+a
+func polymul_xplus(group kyber.Group, poly []kyber.Scalar, a kyber.Scalar) {
+	numcoeffs := len(poly)
+	if !poly[numcoeffs-1].Equal(group.Scalar().Zero()) {
+		panic("Degree too large in multiplication")
+	}
+	for i := numcoeffs-1 ; i > 0 ; i-- {
+		poly[i] = group.Scalar().Add(
+			group.Scalar().Mul(poly[i], a), poly[i-1])
+	}
+	poly[0] = group.Scalar().Mul(poly[0], a)
+}
+
+/* Sigma protocol for one out of N commitments containing 0
+ * Section 3 of https://eprint.iacr.org/2014/764.pdf
+ */
+func ProofStep1(params GroupParams, c []kyber.Point, ell uint32, privkey kyber.Scalar) (PubState, PrivState) {
+	N := uint32(len(c))
+	rand := random.New()
+	group := params.group
+
+	// Find n := ceil(log_2(N))
+	n := uint32(1)
+	two_n := uint32(2) // 2^n
+	for ; two_n < N ; {
+		n += 1
+		two_n *= 2
+	}
+	fmt.Printf("n = %d\n", n);
+
+	// We will keep the notation of the paper:
+	// r, a, s, t, cl, ca, cb are 1-based,
+	// c, rho, cd are 0-based.  The 1-based ones, we
+	// just allocate an extra array element, and never
+	// use element 0.
+	var pub PubState
+	var priv PrivState
+	priv.r = make([]kyber.Scalar, n+1)
+	priv.a = make([]kyber.Scalar, n+1)
+	priv.s = make([]kyber.Scalar, n+1)
+	priv.t = make([]kyber.Scalar, n+1)
+	priv.rho = make([]kyber.Scalar, n)
+	pub.cl = make([]kyber.Point, n+1)
+	pub.ca = make([]kyber.Point, n+1)
+	pub.cb = make([]kyber.Point, n+1)
+	pub.cd = make([]kyber.Point, n)
+
+	var j, k, mask uint32
+	// mask = 2^k
+	j = 1
+	k = 0
+	mask = 1
+	for ; k < n ; {
+		priv.r[j] = group.Scalar().Pick(rand)
+		priv.a[j] = group.Scalar().Pick(rand)
+		priv.s[j] = group.Scalar().Pick(rand)
+		priv.t[j] = group.Scalar().Pick(rand)
+		priv.rho[k] = group.Scalar().Pick(rand)
+
+		pub.cl[j] = group.Point().Mul(priv.r[j], params.B)
+		if (ell & mask) != 0 {
+			pub.cl[j] = group.Point().Add(pub.cl[j], params.A)
+		}
+		pub.ca[j] = group.Point().Add(
+				group.Point().Mul(priv.a[j], params.A),
+				group.Point().Mul(priv.s[j], params.B))
+		pub.cb[j] = group.Point().Mul(priv.t[j], params.B)
+		if (ell & mask) != 0 {
+			pub.cb[j] = group.Point().Add(pub.cb[j],
+					group.Point().Mul(priv.a[j], params.A))
+		}
+
+		j++
+		k++
+		mask *= 2
+	}
+
+	k = 0
+	for ; k < n ; {
+		pub.cd[k] = group.Point().Mul(priv.rho[k], params.B)
+		for i := uint32(0); i < two_n; i++ {
+			// Compute the coefficients of p_i
+			p_i := make([]kyber.Scalar, n+1)
+			p_i[0] = group.Scalar().One()
+			for t := uint32(1); t <= n; t++ {
+				p_i[t] = group.Scalar().Zero()
+			}
+
+			// TODO: finish computation of p_i
+			j = 1
+			// jmask = 2^(j-1)
+			jmask := uint32(1)
+			for ; j <= n ; {
+				if (i & jmask) != 0 {
+					if (ell & jmask) != 0 {
+						// Multiply p_i by x + a[j]
+						polymul_xplus(group, p_i, priv.a[j])
+					} else {
+						// Multiply p_i by a[j]
+						polymul(group, p_i, priv.a[j])
+					}
+				} else {
+					negaj := group.Scalar().Neg(priv.a[j])
+					if (ell & jmask) != 0 {
+						// Multiply p_i by -a[j]
+						polymul(group, p_i, negaj)
+					} else {
+						// Multiply p_i by x - a[j]
+						polymul_xplus(group, p_i, negaj)
+					}
+				}
+
+				j++
+				jmask *= 2
+			}
+
+			if i == ell && !p_i[n].Equal(group.Scalar().One()) {
+				panic("Leading coeff should be 1 but was not")
+			}
+			if i != ell && !p_i[n].Equal(group.Scalar().Zero()) {
+				panic("Leading coeff should be 0 but was not")
+			}
+			if i < N {
+				pub.cd[k] = group.Point().Add(pub.cd[k],
+						group.Point().Mul(p_i[k], c[i]))
+			} else {
+				pub.cd[k] = group.Point().Add(pub.cd[k],
+						group.Point().Mul(p_i[k], params.Y))
+			}
+		}
+
+		k++
+		mask *= 2
+	}
+
+	return pub, priv
+}
+
+func GenChallenge(params GroupParams, pub PubState) kyber.Scalar {
+	return params.group.Scalar()
+}
+
+func ProofStep2(params GroupParams, priv PrivState, x kyber.Scalar) Proof {
+	return Proof{}
+}
+
+func Verify(params GroupParams, pub PubState, x kyber.Scalar, proof Proof) bool {
+	return false
+}

+ 64 - 0
main.go

@@ -0,0 +1,64 @@
+package main
+
+import (
+	"fmt"
+	"os"
+	"strconv"
+	"math/big"
+	"go.dedis.ch/kyber"
+	"go.dedis.ch/kyber/pairing/bn256"
+	"go.dedis.ch/kyber/util/random"
+)
+
+func main() {
+	/* Command-line arg is N, the number of commitments */
+	var N int
+	var err error
+	if len(os.Args) > 1 {
+		N, err = strconv.Atoi(os.Args[1])
+		if err != nil {
+			panic(err)
+		}
+	} else {
+		N = 25
+	}
+	if (N < 2) {
+		panic("N must be at least 2")
+	}
+	N32 := uint32(N)
+	group := bn256.NewSuite().G1()
+	rand := random.New()
+	params := GroupParams {
+		group,
+		group.Point().Pick(rand),
+		group.Point().Pick(rand),
+		group.Point().Pick(rand),
+	}
+
+	// Create an array of commitments, one of which is a commitment
+	// to 0
+	Cs := make([]kyber.Point, N32)
+
+	// Which one do we know?  Pick a random 0 <= ell < N
+	Nbig := big.NewInt(int64(N))
+	ell := uint32(random.Int(Nbig, rand).Int64())
+	var privkey kyber.Scalar
+	var i uint32
+	for i = 0; i < N32; i++ {
+		if i == ell {
+			privkey = group.Scalar().Pick(rand)
+			Cs[i] = group.Point().Mul(privkey, params.B)
+		} else {
+			Cs[i] = group.Point().Pick(rand)
+		}
+	}
+
+	pub, priv := ProofStep1(params, Cs, ell, privkey)
+	x := GenChallenge(params, pub)
+	proof := ProofStep2(params, priv, x)
+	if Verify(params, pub, x, proof) {
+		fmt.Printf("SUCCESS\n")
+	} else {
+		fmt.Printf("VERIFICATION FAILED\n")
+	}
+}