// Binary shuffle ("biffle") for 2 ciphertexts based on general ZKPs. func Biffle(suite abstract.Suite, G, H abstract.Point, X, Y [2]abstract.Point, rand abstract.Cipher) ( Xbar, Ybar [2]abstract.Point, prover proof.Prover) { // Pick the single-bit permutation. bit := int(random.Byte(rand) & 1) // Pick a fresh ElGamal blinding factor for each pair var beta [2]abstract.Scalar for i := 0; i < 2; i++ { beta[i] = suite.Scalar().Pick(rand) } // Create the output pair vectors for i := 0; i < 2; i++ { pi_i := i ^ bit Xbar[i] = suite.Point().Mul(G, beta[pi_i]) Xbar[i].Add(Xbar[i], X[pi_i]) Ybar[i] = suite.Point().Mul(H, beta[pi_i]) Ybar[i].Add(Ybar[i], Y[pi_i]) } or := bifflePred() secrets := map[string]abstract.Scalar{ "beta0": beta[0], "beta1": beta[1]} points := bifflePoints(suite, G, H, X, Y, Xbar, Ybar) choice := map[proof.Predicate]int{or: bit} prover = or.Prover(suite, secrets, points, choice) return }
// DefaultConstructors gives a default constructor for protobuf out of the global suite func DefaultConstructors(suite abstract.Suite) protobuf.Constructors { constructors := make(protobuf.Constructors) var point abstract.Point var secret abstract.Scalar constructors[reflect.TypeOf(&point).Elem()] = func() interface{} { return suite.Point() } constructors[reflect.TypeOf(&secret).Elem()] = func() interface{} { return suite.Scalar() } return constructors }
// ReadScalarHex reads a scalar in hexadecimal from string func ReadScalarHex(suite abstract.Suite, str string) (abstract.Scalar, error) { enc, err := hex.DecodeString(str) if err != nil { return nil, err } s := suite.Scalar() err = s.UnmarshalBinary(enc) return s, err }
func signH1(suite abstract.Suite, H1pre abstract.Cipher, PG, PH abstract.Point) abstract.Scalar { H1 := H1pre.Clone() PGb, _ := PG.MarshalBinary() H1.Write(PGb) if PH != nil { PHb, _ := PH.MarshalBinary() H1.Write(PHb) } H1.Message(nil, nil, nil) // finish message absorption return suite.Scalar().Pick(H1) }
func hash(suite abstract.Suite, r abstract.Point, msg []byte) (abstract.Scalar, error) { rBuf, err := r.MarshalBinary() if err != nil { return nil, err } cipher := suite.Cipher(rBuf) cipher.Message(nil, nil, msg) // (re)compute challenge (e) e := suite.Scalar().Pick(cipher) return e, nil }
// Verify returns whether the verification of the signature succeeds or not. // Specifically, it adjusts the signature according to the exception in the // signature, so it can be verified by dedis/crypto/cosi. // publics is a slice of all public signatures, and the msg is the msg // being signed. func (bs *BFTSignature) Verify(s abstract.Suite, publics []abstract.Point) error { if bs == nil || bs.Sig == nil || bs.Msg == nil { return errors.New("Invalid signature") } // compute the aggregate key of all the signers aggPublic := s.Point().Null() for i := range publics { aggPublic.Add(aggPublic, publics[i]) } // compute the reduced public aggregate key (all - exception) aggReducedPublic := s.Point().Null().Add(s.Point().Null(), aggPublic) // compute the aggregate commit of exception aggExCommit := s.Point().Null() for _, ex := range bs.Exceptions { aggExCommit = aggExCommit.Add(aggExCommit, ex.Commitment) aggReducedPublic.Sub(aggReducedPublic, publics[ex.Index]) } // get back the commit to recreate the challenge origCommit := s.Point() if err := origCommit.UnmarshalBinary(bs.Sig[0:32]); err != nil { return err } // re create challenge h := sha512.New() if _, err := origCommit.MarshalTo(h); err != nil { return err } if _, err := aggPublic.MarshalTo(h); err != nil { return err } if _, err := h.Write(bs.Msg); err != nil { return err } // redo like in cosi -k*A + r*B == C // only with C being the reduced version k := s.Scalar().SetBytes(h.Sum(nil)) minusPublic := s.Point().Neg(aggReducedPublic) ka := s.Point().Mul(minusPublic, k) r := s.Scalar().SetBytes(bs.Sig[32:64]) rb := s.Point().Mul(nil, r) left := s.Point().Add(rb, ka) right := s.Point().Sub(origCommit, aggExCommit) if !left.Equal(right) { return errors.New("Commit recreated is not equal to one given") } return nil }
func ElGamalEncrypt(suite abstract.Suite, pubkey abstract.Point, message []byte) ( K, C abstract.Point, remainder []byte) { // Embed the message (or as much of it as will fit) into a curve point. M, remainder := suite.Point().Pick(message, random.Stream) // ElGamal-encrypt the point to produce ciphertext (K,C). k := suite.Scalar().Pick(random.Stream) // ephemeral private key K = suite.Point().Mul(nil, k) // ephemeral DH public key S := suite.Point().Mul(pubkey, k) // ephemeral DH shared secret C = S.Add(S, M) // message blinded with secret return }
func verifyCommitment(suite abstract.Suite, msg []byte, commitment abstract.Point, challenge abstract.Scalar) error { pb, err := commitment.MarshalBinary() if err != nil { return err } cipher := suite.Cipher(pb) cipher.Message(nil, nil, msg) // reconstructed challenge reconstructed := suite.Scalar().Pick(cipher) if !reconstructed.Equal(challenge) { return errors.New("Reconstructed challenge not equal to one given") } return nil }
// Initialize... func (sk *SKEME) Init(suite abstract.Suite, rand cipher.Stream, lpri PriKey, rpub Set, hide bool) { sk.suite = suite sk.hide = hide sk.lpri, sk.rpub = lpri, rpub // Create our Diffie-Hellman keypair sk.lx = suite.Scalar().Pick(rand) sk.lX = suite.Point().Mul(nil, sk.lx) sk.lXb, _ = sk.lX.MarshalBinary() // Encrypt and send the DH key to the receiver. // This is a deviation from SKEME, to protect message metadata // and further harden messages against tampering or active MITM DoS. sk.lm = Encrypt(suite, rand, sk.lXb, rpub, hide) }
func benchGenKeys(suite abstract.Suite, nkeys int) ([]abstract.Point, abstract.Scalar) { rand := random.Stream // Create an anonymity set of random "public keys" X := make([]abstract.Point, nkeys) for i := range X { // pick random points X[i], _ = suite.Point().Pick(nil, rand) } // Make just one of them an actual public/private keypair (X[mine],x) x := suite.Scalar().Pick(rand) X[0] = suite.Point().Mul(nil, x) return X, x }
// XXX belongs in crypto package? func keyPair(suite abstract.Suite, rand cipher.Stream, hide bool) (abstract.Point, abstract.Scalar, []byte) { x := suite.Scalar().Pick(rand) X := suite.Point().Mul(nil, x) if !hide { Xb, _ := X.MarshalBinary() return X, x, Xb } Xh := X.(abstract.Hiding) for { Xb := Xh.HideEncode(rand) // try to encode as uniform blob if Xb != nil { return X, x, Xb // success } x.Pick(rand) // try again with a new key X.Mul(nil, x) } }
// This simplified implementation of Schnorr Signatures is based on // crypto/anon/sig.go // The ring structure is removed and // The anonimity set is reduced to one public key = no anonimity func SchnorrSign(suite abstract.Suite, random cipher.Stream, message []byte, privateKey abstract.Scalar) []byte { // Create random secret v and public point commitment T v := suite.Scalar().Pick(random) T := suite.Point().Mul(nil, v) // Create challenge c based on message and T c := hashSchnorr(suite, message, T) // Compute response r = v - x*c r := suite.Scalar() r.Mul(privateKey, c).Sub(v, r) // Return verifiable signature {c, r} // Verifier will be able to compute v = r + x*c // And check that hashElgamal for T and the message == c buf := bytes.Buffer{} sig := basicSig{c, r} suite.Write(&buf, &sig) return buf.Bytes() }
// VerifySignature is the method to call to verify a signature issued by a Cosi // struct. Publics is the WHOLE list of publics keys, the mask at the end of the // signature will take care of removing the indivual public keys that did not // participate func VerifySignature(suite abstract.Suite, publics []abstract.Point, message, sig []byte) error { aggCommitBuff := sig[:32] aggCommit := suite.Point() if err := aggCommit.UnmarshalBinary(aggCommitBuff); err != nil { panic(err) } sigBuff := sig[32:64] sigInt := suite.Scalar().SetBytes(sigBuff) maskBuff := sig[64:] mask := newMask(suite, publics) mask.SetMask(maskBuff) aggPublic := mask.Aggregate() aggPublicMarshal, err := aggPublic.MarshalBinary() if err != nil { return err } hash := sha512.New() hash.Write(aggCommitBuff) hash.Write(aggPublicMarshal) hash.Write(message) buff := hash.Sum(nil) k := suite.Scalar().SetBytes(buff) // k * -aggPublic + s * B = k*-A + s*B // from s = k * a + r => s * B = k * a * B + r * B <=> s*B = k*A + r*B // <=> s*B + k*-A = r*B minusPublic := suite.Point().Neg(aggPublic) kA := suite.Point().Mul(minusPublic, k) sB := suite.Point().Mul(nil, sigInt) left := suite.Point().Add(kA, sB) if !left.Equal(aggCommit) { return errors.New("Signature invalid") } return nil }
func TestShuffle(suite abstract.Suite, k int, N int) { rand := suite.Cipher(abstract.RandomKey) // Create a "server" private/public keypair h := suite.Scalar().Pick(rand) H := suite.Point().Mul(nil, h) // Create a set of ephemeral "client" keypairs to shuffle c := make([]abstract.Scalar, k) C := make([]abstract.Point, k) // fmt.Println("\nclient keys:") for i := 0; i < k; i++ { c[i] = suite.Scalar().Pick(rand) C[i] = suite.Point().Mul(nil, c[i]) // fmt.Println(" "+C[i].String()) } // ElGamal-encrypt all these keypairs with the "server" key X := make([]abstract.Point, k) Y := make([]abstract.Point, k) r := suite.Scalar() // temporary for i := 0; i < k; i++ { r.Pick(rand) X[i] = suite.Point().Mul(nil, r) Y[i] = suite.Point().Mul(H, r) // ElGamal blinding factor Y[i].Add(Y[i], C[i]) // Encrypted client public key } // Repeat only the actual shuffle portion for test purposes. for i := 0; i < N; i++ { // Do a key-shuffle Xbar, Ybar, prover := Shuffle(suite, nil, H, X, Y, rand) prf, err := proof.HashProve(suite, "PairShuffle", rand, prover) if err != nil { panic("Shuffle proof failed: " + err.Error()) } //fmt.Printf("proof:\n%s\n",hex.Dump(prf)) // Check it verifier := Verifier(suite, nil, H, X, Y, Xbar, Ybar) err = proof.HashVerify(suite, "PairShuffle", verifier, prf) if err != nil { panic("Shuffle verify failed: " + err.Error()) } } }
// SignSchnorr creates a Schnorr signature from a msg and a private key func SignSchnorr(suite abstract.Suite, private abstract.Scalar, msg []byte) (SchnorrSig, error) { // using notation from https://en.wikipedia.org/wiki/Schnorr_signature // create random secret k and public point commitment r k := suite.Scalar().Pick(random.Stream) r := suite.Point().Mul(nil, k) // create challenge e based on message and r e, err := hash(suite, r, msg) if err != nil { return SchnorrSig{}, err } // compute response s = k - x*e xe := suite.Scalar().Mul(private, e) s := suite.Scalar().Sub(k, xe) return SchnorrSig{Challenge: e, Response: s}, nil }
// Sign creates an optionally anonymous, optionally linkable // signature on a given message. // // The caller supplies one or more public keys representing an anonymity set, // and the private key corresponding to one of those public keys. // The resulting signature proves to a verifier that the owner of // one of these public keys signed the message, // without revealing which key-holder signed the message, // offering anonymity among the members of this explicit anonymity set. // The other users whose keys are listed in the anonymity set need not consent // or even be aware that they have been included in an anonymity set: // anyone having a suitable public key may be "conscripted" into a set. // // If the provided anonymity set contains only one public key (the signer's), // then this function produces a traditional non-anonymous signature, // equivalent in both size and performance to a standard ElGamal signature. // // The caller may request either unlinkable or linkable anonymous signatures. // If linkScope is nil, this function generates an unlinkable signature, // which contains no information about which member signed the message. // The anonymity provided by unlinkable signatures is forward-secure, // in that a signature reveals nothing about which member generated it, // even if all members' private keys are later released. // For cryptographic background on unlinkable anonymity-set signatures - // also known as ring signatures or ad-hoc group signatures - // see Rivest, "How to Leak a Scalar" at // http://people.csail.mit.edu/rivest/RivestShamirTauman-HowToLeakAScalar.pdf. // // If the caller passes a non-nil linkScope, // the resulting anonymous signature will be linkable. // This means that given two signatures produced using the same linkScope, // a verifier will be able to tell whether // the same or different anonymity set members produced those signatures. // In particular, verifying a linkable signature yields a linkage tag. // This linkage tag has a 1-to-1 correspondence with the signer's public key // within a given linkScope, but is cryptographically unlinkable // to either the signer's public key or to linkage tags in other scopes. // The provided linkScope may be an arbitrary byte-string; // the only significance these scopes have is whether they are equal or unequal. // For details on the linkable signature algorithm this function implements, // see Liu/Wei/Wong, // "Linkable Spontaneous Anonymous Group Signature for Ad Hoc Groups" at // http://www.cs.cityu.edu.hk/~duncan/papers/04liuetal_lsag.pdf. // // Linkage tags may be used to protect against sock-puppetry or Sybil attacks // in situations where a verifier needs to know how many distinct members // of an anonymity set are present or signed messages in a given context. // It is cryptographically hard for one anonymity set member // to produce signatures with different linkage tags in the same scope. // An important and fundamental downside, however, is that // linkable signatures do NOT offer forward-secure anonymity. // If an anonymity set member's private key is later released, // it is trivial to check whether or not that member produced a given signature. // Also, anonymity set members who did NOT sign a message could // (voluntarily or under coercion) prove that they did not sign it, // e.g., simply by signing some other message in that linkage context // and noting that the resulting linkage tag comes out different. // Thus, linkable anonymous signatures are not appropriate to use // in situations where there may be significant risk // that members' private keys may later be compromised, // or that members may be persuaded or coerced into revealing whether or not // they produced a signature of interest. // func Sign(suite abstract.Suite, random cipher.Stream, message []byte, anonymitySet Set, linkScope []byte, mine int, privateKey abstract.Scalar) []byte { // Note that Rivest's original ring construction directly supports // heterogeneous rings containing public keys of different types - // e.g., a mixture of RSA keys and DSA keys with varying parameters. // Our ring signature construction currently supports // only homogeneous rings containing compatible keys // drawn from the cipher suite (e.g., the same elliptic curve). // The upside to this constrint is greater flexibility: // e.g., we also easily obtain linkable ring signatures, // which are not readily feasible with the original ring construction. n := len(anonymitySet) // anonymity set size L := []abstract.Point(anonymitySet) // public keys in anonymity set pi := mine // If we want a linkable ring signature, produce correct linkage tag, // as a pseudorandom base point multiplied by our private key. // Liu's scheme specifies the linkScope as a hash of the ring; // this is one reasonable choice of linkage scope, // but there are others, so we parameterize this choice. var linkBase, linkTag abstract.Point if linkScope != nil { linkStream := suite.Cipher(linkScope) linkBase, _ = suite.Point().Pick(nil, linkStream) linkTag = suite.Point().Mul(linkBase, privateKey) } // First pre-hash the parameters to H1 // that are invariant for different ring positions, // so that we don't have to hash them many times. H1pre := signH1pre(suite, linkScope, linkTag, message) // Pick a random commit for my ring position u := suite.Scalar().Pick(random) var UB, UL abstract.Point UB = suite.Point().Mul(nil, u) if linkScope != nil { UL = suite.Point().Mul(linkBase, u) } // Build the challenge ring s := make([]abstract.Scalar, n) c := make([]abstract.Scalar, n) c[(pi+1)%n] = signH1(suite, H1pre, UB, UL) var P, PG, PH abstract.Point P = suite.Point() PG = suite.Point() if linkScope != nil { PH = suite.Point() } for i := (pi + 1) % n; i != pi; i = (i + 1) % n { s[i] = suite.Scalar().Pick(random) PG.Add(PG.Mul(nil, s[i]), P.Mul(L[i], c[i])) if linkScope != nil { PH.Add(PH.Mul(linkBase, s[i]), P.Mul(linkTag, c[i])) } c[(i+1)%n] = signH1(suite, H1pre, PG, PH) //fmt.Printf("s%d %s\n",i,s[i].String()) //fmt.Printf("c%d %s\n",(i+1)%n,c[(i+1)%n].String()) } s[pi] = suite.Scalar() s[pi].Mul(privateKey, c[pi]).Sub(u, s[pi]) // s_pi = u - x_pi c_pi // Encode and return the signature buf := bytes.Buffer{} if linkScope != nil { // linkable ring signature sig := lSig{c[0], s, linkTag} suite.Write(&buf, &sig) } else { // unlinkable ring signature sig := uSig{c[0], s} suite.Write(&buf, &sig) } return buf.Bytes() }
// Returns a secret that depends on on a message and a point func hashSchnorr(suite abstract.Suite, message []byte, p abstract.Point) abstract.Scalar { pb, _ := p.MarshalBinary() c := suite.Cipher(pb) c.Message(nil, nil, message) return suite.Scalar().Pick(c) }
// Decrypt and verify a key encrypted via encryptKey. // On success, returns the key and the length of the decrypted header. func decryptKey(suite abstract.Suite, ciphertext []byte, anonymitySet Set, mine int, privateKey abstract.Scalar, hide bool) ([]byte, int, error) { // Decode the (supposed) ephemeral public key from the front X := suite.Point() var Xb []byte if hide { Xh := X.(abstract.Hiding) hidelen := Xh.HideLen() if len(ciphertext) < hidelen { return nil, 0, errors.New("ciphertext too short") } X.(abstract.Hiding).HideDecode(ciphertext[:hidelen]) Xb = ciphertext[:hidelen] } else { enclen := X.MarshalSize() if len(ciphertext) < enclen { return nil, 0, errors.New("ciphertext too short") } if err := X.UnmarshalBinary(ciphertext[:enclen]); err != nil { return nil, 0, err } Xb = ciphertext[:enclen] } Xblen := len(Xb) // Decode the (supposed) master secret with our private key nkeys := len(anonymitySet) if mine < 0 || mine >= nkeys { panic("private-key index out of range") } seclen := suite.ScalarLen() if len(ciphertext) < Xblen+seclen*nkeys { return nil, 0, errors.New("ciphertext too short") } S := suite.Point().Mul(X, privateKey) seed, _ := S.MarshalBinary() cipher := suite.Cipher(seed) xb := make([]byte, seclen) secofs := Xblen + seclen*mine cipher.Partial(xb, ciphertext[secofs:secofs+seclen], nil) x := suite.Scalar() if err := x.UnmarshalBinary(xb); err != nil { return nil, 0, err } // Make sure it reproduces the correct ephemeral public key Xv := suite.Point().Mul(nil, x) if !X.Equal(Xv) { return nil, 0, errors.New("invalid ciphertext") } // Regenerate and check the rest of the header, // to ensure that that any of the anonymitySet members could decrypt it hdr := header(suite, X, x, Xb, xb, anonymitySet) hdrlen := len(hdr) if hdrlen != Xblen+seclen*nkeys { panic("wrong header size") } if subtle.ConstantTimeCompare(hdr, ciphertext[:hdrlen]) == 0 { return nil, 0, errors.New("invalid ciphertext") } return xb, hdrlen, nil }
// ReadScalar64 takes a Base64-encoded scalar and returns that scalar, // optionally an error func ReadScalar64(suite abstract.Suite, r io.Reader) (abstract.Scalar, error) { s := suite.Scalar() dec := base64.NewDecoder(base64.StdEncoding, r) err := suite.Read(dec, &s) return s, err }