// InitNull does the same thing as Init PLUS initialize every points / coef to the Null // Identity Element so we can use it like a "temp" / "aggregate" variable to add with others poly func (pub *PubPoly) InitNull(g abstract.Group, k int, b abstract.Point) *PubPoly { pub.Init(g, k, b) for i, _ := range pub.p { pub.p[i] = g.Point().Null() } return pub }
func EncryptPoint(g abstract.Group, msgPt abstract.Point, pk abstract.Point) (abstract.Point, abstract.Point) { k := g.Scalar().Pick(random.Stream) c1 := g.Point().Mul(nil, k) c2 := g.Point().Mul(pk, k) c2 = c2.Add(c2, msgPt) return c1, c2 }
func testHiding(g abstract.Group, k int) { rand := random.Stream // Test conversion from random strings to points and back p := g.Point() p2 := g.Point() l := p.(abstract.Hiding).HideLen() buf := make([]byte, l) for i := 0; i < k; i++ { rand.XORKeyStream(buf, buf) //println("R "+hex.EncodeToString(buf)) p.(abstract.Hiding).HideDecode(buf) //println("P "+p.String()) b2 := p.(abstract.Hiding).HideEncode(rand) if b2 == nil { panic("HideEncode failed") } //println("R'"+hex.EncodeToString(b2)) p2.(abstract.Hiding).HideDecode(b2) //println("P'"+p2.String()) if !p.Equal(p2) { panic("HideDecode produced wrong point") } //println("") } }
func NewGroupBench(g abstract.Group) *GroupBench { var gb GroupBench gb.g = g gb.x = g.Secret().Pick(random.Stream) gb.y = g.Secret().Pick(random.Stream) gb.xe, _ = gb.x.MarshalBinary() gb.X, _ = g.Point().Pick(nil, random.Stream) gb.Y, _ = g.Point().Pick(nil, random.Stream) gb.Xe, _ = gb.X.MarshalBinary() return &gb }
// Create a fresh sharing polynomial in the Secret space of a given group. // Shares the provided Secret s, or picks a random one if s == nil. func (p *PriPoly) Pick(g abstract.Group, k int, s0 abstract.Secret, rand cipher.Stream) *PriPoly { p.g = g s := make([]abstract.Secret, k) if s0 == nil { // Choose secret to share if none provided s0 = g.Secret().Pick(rand) } s[0] = s0 for i := 1; i < k; i++ { s[i] = g.Secret().Pick(rand) } p.s = s return p }
func testScalarClone(g abstract.Group, rand cipher.Stream) { N := 1000 one := g.Scalar().One() for i := 0; i < N; i++ { s1 := g.Scalar().Pick(rand) s2 := s1.Clone() if !s1.Equal(s2) { panic("Clone didn't create a scalar s2 with same value as s1's.") } if !s1.Equal(one) { s1.Mul(s1, s1) if s1.Equal(s2) { panic("Modifying s1 shouldn't modify s2") } } } }
func testPointClone(g abstract.Group, rand cipher.Stream) { N := 1000 null := g.Point().Null() for i := 0; i < N; i++ { P1, _ := g.Point().Pick(nil, rand) P2 := P1.Clone() if !P1.Equal(P2) { panic("Clone didn't create a point with same " + "coordinates as the original point.") } if !P1.Equal(null) { P1.Add(P1, P1) if P1.Equal(P2) { panic("Modifying P1 shouldn't modify P2") } } } }
func testEmbed(g abstract.Group, rand cipher.Stream, points *[]abstract.Point, s string) { //println("embedding: ",s) b := []byte(s) p, rem := g.Point().Pick(b, rand) //println("embedded, remainder",len(rem),"/",len(b),":",string(rem)) x, err := p.Data() if err != nil { panic("Point extraction failed: " + err.Error()) } //println("extracted data: ",string(x)) if !bytes.Equal(append(x, rem...), b) { panic("Point embedding corrupted the data") } *points = append(*points, p) }
// Simple helper to compute G^{ab-cd} for Theta vector computation. func thenc(grp abstract.Group, G abstract.Point, a, b, c, d abstract.Scalar) abstract.Point { var ab, cd abstract.Scalar if a != nil { ab = grp.Scalar().Mul(a, b) } else { ab = grp.Scalar().Zero() } if c != nil { if d != nil { cd = grp.Scalar().Mul(c, d) } else { cd = c } } else { cd = grp.Scalar().Zero() } return grp.Point().Mul(G, ab.Sub(ab, cd)) }
func Shuffle(pi []int, group abstract.Group, g, h abstract.Point, X, Y []abstract.Point, rand cipher.Stream) (XX, YY []abstract.Point, P proof.Prover) { k := len(X) if k != len(Y) { panic("X,Y vectors have inconsistent length") } ps := shuffle.PairShuffle{} ps.Init(group, k) // Pick a fresh ElGamal blinding factor for each pair beta := make([]abstract.Scalar, k) for i := 0; i < k; i++ { beta[i] = group.Scalar().Pick(rand) } // Create the output pair vectors Xbar := make([]abstract.Point, k) Ybar := make([]abstract.Point, k) for i := 0; i < k; i++ { Xbar[i] = group.Point().Mul(g, beta[pi[i]]) Xbar[i].Add(Xbar[i], X[pi[i]]) Ybar[i] = group.Point().Mul(h, beta[pi[i]]) Ybar[i].Add(Ybar[i], Y[pi[i]]) } prover := func(ctx proof.ProverContext) error { return ps.Prove(pi, g, h, beta, X, Y, rand, ctx) } return Xbar, Ybar, prover }
func EncryptKey(g abstract.Group, msgPt abstract.Point, pks []abstract.Point) (abstract.Point, abstract.Point) { k := g.Scalar().Pick(random.Stream) c1 := g.Point().Mul(nil, k) var c2 abstract.Point = nil for _, pk := range pks { if c2 == nil { c2 = g.Point().Mul(pk, k) } else { c2 = c2.Add(c2, g.Point().Mul(pk, k)) } } c2 = c2.Add(c2, msgPt) return c1, c2 }
func Encrypt(g abstract.Group, msg []byte, pks []abstract.Point) ([]abstract.Point, []abstract.Point) { c1s := []abstract.Point{} c2s := []abstract.Point{} var msgPt abstract.Point remainder := msg for len(remainder) != 0 { msgPt, remainder = g.Point().Pick(remainder, random.Stream) k := g.Scalar().Pick(random.Stream) c1 := g.Point().Mul(nil, k) var c2 abstract.Point = nil for _, pk := range pks { if c2 == nil { c2 = g.Point().Mul(pk, k) } else { c2 = c2.Add(c2, g.Point().Mul(pk, k)) } } c2 = c2.Add(c2, msgPt) c1s = append(c1s, c1) c2s = append(c2s, c2) } return c1s, c2s }
func testPointSet(g abstract.Group, rand cipher.Stream) { N := 1000 null := g.Point().Null() for i := 0; i < N; i++ { P1, _ := g.Point().Pick(nil, rand) P2 := g.Point() P2.Set(P1) if !P1.Equal(P2) { panic("Set() set to a different point.") } if !P1.Equal(null) { P1.Add(P1, P1) if P1.Equal(P2) { panic("Modifying P1 shouldn't modify P2") } } } }
func Decrypt(g abstract.Group, c1 abstract.Point, c2 abstract.Point, sk abstract.Scalar) abstract.Point { return g.Point().Sub(c2, g.Point().Mul(c1, sk)) }
"github.com/dedis/crypto/abstract" "github.com/dedis/crypto/edwards" "github.com/dedis/crypto/random" ) /* This file is a testing suite for sharing.go. It provides multiple test cases * for ensuring that encryption schemes built upon this package such as Shamir * secret sharing are safe and secure. * * The tests can also serve as references for how to work with this library. */ /* Global Variables */ var group abstract.Group = new(edwards.ExtendedCurve).Init( edwards.Param25519(), false) var altGroup abstract.Group = new(edwards.ProjectiveCurve).Init( edwards.ParamE382(), false) var k int = 10 var n int = 20 var secret = group.Scalar().Pick(random.Stream) var point = group.Point().Mul(group.Point().Base(), secret) var altSecret = altGroup.Scalar().Pick(random.Stream) var altPoint = altGroup.Point().Mul(altGroup.Point().Base(), altSecret) /* Setup Functions * * These functions provide greater modularity by consolidating commonly used * setup tasks. * * Not every function uses these methods, since they may have unique set-up
// Apply a generic set of validation tests to a cryptographic Group, // using a given source of [pseudo-]randomness. // // Returns a log of the pseudorandom Points produced in the test, // for comparison across alternative implementations // that are supposed to be equivalent. // func testGroup(g abstract.Group, rand cipher.Stream) []abstract.Point { // fmt.Printf("\nTesting group '%s': %d-byte Point, %d-byte Scalar\n", // g.String(), g.PointLen(), g.ScalarLen()) points := make([]abstract.Point, 0) ptmp := g.Point() stmp := g.Scalar() pzero := g.Point().Null() szero := g.Scalar().Zero() sone := g.Scalar().One() // Do a simple Diffie-Hellman test s1 := g.Scalar().Pick(rand) s2 := g.Scalar().Pick(rand) if s1.Equal(s2) { panic("uh-oh, not getting unique secrets!") } gen := g.Point().Base() points = append(points, gen) // Verify additive and multiplicative identities of the generator. ptmp.Mul(nil, stmp.SetInt64(-1)).Add(ptmp, gen) if !ptmp.Equal(pzero) { panic("oops, generator additive identity doesn't work") } if g.PrimeOrder() { // secret.Inv works only in prime-order groups ptmp.Mul(nil, stmp.SetInt64(2)).Mul(ptmp, stmp.Inv(stmp)) if !ptmp.Equal(gen) { panic("oops, generator multiplicative identity doesn't work") } } p1 := g.Point().Mul(gen, s1) p2 := g.Point().Mul(gen, s2) if p1.Equal(p2) { panic("uh-oh, encryption isn't producing unique points!") } points = append(points, p1) dh1 := g.Point().Mul(p1, s2) dh2 := g.Point().Mul(p2, s1) if !dh1.Equal(dh2) { panic("Diffie-Hellman didn't work") } points = append(points, dh1) //println("shared secret = ",dh1.String()) // Test secret inverse to get from dh1 back to p1 if g.PrimeOrder() { ptmp.Mul(dh1, g.Scalar().Inv(s2)) if !ptmp.Equal(p1) { panic("Scalar inverse didn't work") } } // Zero and One identity secrets //println("dh1^0 = ",ptmp.Mul(dh1, szero).String()) if !ptmp.Mul(dh1, szero).Equal(pzero) { panic("Encryption with secret=0 didn't work") } if !ptmp.Mul(dh1, sone).Equal(dh1) { panic("Encryption with secret=1 didn't work") } // Additive homomorphic identities ptmp.Add(p1, p2) stmp.Add(s1, s2) pt2 := g.Point().Mul(gen, stmp) if !pt2.Equal(ptmp) { panic("Additive homomorphism doesn't work") } ptmp.Sub(p1, p2) stmp.Sub(s1, s2) pt2.Mul(gen, stmp) if !pt2.Equal(ptmp) { panic("Additive homomorphism doesn't work") } st2 := g.Scalar().Neg(s2) st2.Add(s1, st2) if !stmp.Equal(st2) { panic("Scalar.Neg doesn't work") } pt2.Neg(p2).Add(pt2, p1) if !pt2.Equal(ptmp) { panic("Point.Neg doesn't work") } // Multiplicative homomorphic identities stmp.Mul(s1, s2) if !ptmp.Mul(gen, stmp).Equal(dh1) { panic("Multiplicative homomorphism doesn't work") } if g.PrimeOrder() { st2.Inv(s2) st2.Mul(st2, stmp) if !st2.Equal(s1) { panic("Scalar division doesn't work") } st2.Div(stmp, s2) if !st2.Equal(s1) { panic("Scalar division doesn't work") } } // Test randomly picked points last := gen for i := 0; i < 5; i++ { rgen, _ := g.Point().Pick(nil, rand) if rgen.Equal(last) { panic("Pick() not producing unique points") } last = rgen ptmp.Mul(rgen, stmp.SetInt64(-1)).Add(ptmp, rgen) if !ptmp.Equal(pzero) { panic("random generator fails additive identity") } if g.PrimeOrder() { ptmp.Mul(rgen, stmp.SetInt64(2)).Mul(ptmp, stmp.Inv(stmp)) if !ptmp.Equal(rgen) { panic("random generator fails multiplicative identity") } } points = append(points, rgen) } // Test embedding data testEmbed(g, rand, &points, "Hi!") testEmbed(g, rand, &points, "The quick brown fox jumps over the lazy dog") // Test verifiable secret sharing // XXX re-enable when we move this into 'test' sub-package //testSharing(g) // Test encoding and decoding buf := new(bytes.Buffer) for i := 0; i < 5; i++ { buf.Reset() s := g.Scalar().Pick(rand) if _, err := s.MarshalTo(buf); err != nil { panic("encoding of secret fails: " + err.Error()) } if _, err := stmp.UnmarshalFrom(buf); err != nil { panic("decoding of secret fails: " + err.Error()) } if !stmp.Equal(s) { panic("decoding produces different secret than encoded") } buf.Reset() p, _ := g.Point().Pick(nil, rand) if _, err := p.MarshalTo(buf); err != nil { panic("encoding of point fails: " + err.Error()) } if _, err := ptmp.UnmarshalFrom(buf); err != nil { panic("decoding of point fails: " + err.Error()) } if !ptmp.Equal(p) { panic("decoding produces different point than encoded") } } // Test that we can marshal/ unmarshal null point pzero = g.Point().Null() b, _ := pzero.MarshalBinary() repzero := g.Point() err := repzero.UnmarshalBinary(b) if err != nil { panic(err) } testPointSet(g, rand) testPointClone(g, rand) testScalarSet(g, rand) testScalarClone(g, rand) return points }
func testSharing(g abstract.Group) { k := 4 n := 10 p1 := new(PriPoly).Pick(g, k, nil, random.Stream) p2 := new(PriPoly).Pick(g, k, nil, random.Stream) p3 := new(PriPoly).Add(p1, p2) if p1.Equal(p2) || p1.Equal(p3) || !p1.Equal(p1) || !p2.Equal(p2) { panic("PriPoly equality doesn't work") } pub1 := new(PubPoly).Commit(p1, nil) pub2 := new(PubPoly).Commit(p2, nil) pub3 := new(PubPoly).Commit(p3, nil) if pub1.Equal(pub2) || pub1.Equal(pub3) { panic("PubPoly equality false positive") } if !pub1.Equal(pub1) || !pub2.Equal(pub2) { panic("PubPoly equality false negative") } pub3c := new(PubPoly).Add(pub1, pub2) if !pub3.Equal(pub3c) { panic("PubPoly homomorphic addition doesn't work") } ps1 := new(PriShares).Split(p1, n) if !ps1.Secret().Equal(p1.Secret()) { panic("Secret recovery doesn't work!") } // Share-checking for i := 0; i < n; i++ { if !pub1.Check(i, ps1.Share(i)) { panic("Share checking doesn't work") } if pub2.Check(i, ps1.Share(i)) { panic("Share checking false positive!?") } } // Produce share commitments from the public polynomial commitment. pubs1 := new(PubShares).Split(pub1, n) for i := 0; i < n; i++ { P := g.Point().Mul(nil, ps1.Share(i)) if !P.Equal(pubs1.Share(i)) { panic("Homomorphic share splitting didn't work") } } // Cut out even-numbered shares for fun for i := 0; i < n; i += 2 { ps1.SetShare(i, nil) pubs1.SetShare(i, nil) } if !ps1.Secret().Equal(p1.Secret()) { panic("Secret recovery from partial set doesn't work!") } // Homomorphic share reconstruction P := g.Point().Mul(nil, p1.Secret()) if !P.Equal(pub1.SecretCommit()) { panic("Public polynomial committed wrong secret") } if !P.Equal(pubs1.SecretCommit()) { panic("Homomorphic secret reconstruction didn't work") } // Cut to the minimum number of shares ps1.SetShare(1, nil) if !ps1.Secret().Equal(p1.Secret()) { panic("Secret recovery from partial set doesn't work!") } if !P.Equal(pubs1.SecretCommit()) { panic("Homomorphic secret reconstruction didn't work") } }