// Checks the signature against // the message func SchnorrVerify(suite abstract.Suite, kp SchnorrPublicKey, msg []byte, sig []byte) (bool, error) { buf := bytes.NewBuffer(sig) signature := SchnorrSignature{} err := abstract.Read(buf, &signature, suite) if err != nil { return false, err } s := signature.S e := signature.E var gs, ye, r abstract.Point gs = suite.Point().Mul(nil, s) // g^s ye = suite.Point().Mul(kp.Y, e) // y^e r = suite.Point().Add(gs, ye) // g^xy^e r_bin, _ := r.MarshalBinary() msg_and_r := append(msg, r_bin...) hasher := sha3.New256() hasher.Write(msg_and_r) h := hasher.Sum(nil) // again I'm hoping this just reads the state out // and doesn't actually perform any ops lct := suite.Cipher(h) ev := suite.Secret().Pick(lct) return ev.Equal(e), nil }
// ReadPubKey will read the file and decrypt the public key inside // It takes a suite to decrypt and a file name // Returns the public key, whatever text is in front and an error if anything went wrong func ReadPubKey(suite abstract.Suite, fileName string) (abstract.Point, string, error) { public := suite.Point() // Opening files pubFile, err := os.Open(fileName) if err != nil { return nil, "", err } defer pubFile.Close() // read the string before by, err := ioutil.ReadAll(pubFile) if err != nil { return nil, "", errors.New(fmt.Sprintf("Error reading the whole file %s", err)) } splits := strings.Split(string(by), " ") if len(splits) != 2 { return nil, "", errors.New(fmt.Sprintf("Error reading pub key file format is not correct (val space val)")) } before := splits[0] key := strings.NewReader(splits[1]) // Some readings public, err = ReadPub64(suite, key) if err != nil { return nil, "", errors.New(fmt.Sprintf("Error reading the public key itself: %s", err)) } return public, before, nil }
func ElGamalVerify(suite abstract.Suite, message []byte, publicKey abstract.Point, signatureBuffer []byte, g abstract.Point) error { // Decode the signature buf := bytes.NewBuffer(signatureBuffer) sig := basicSig{} if err := abstract.Read(buf, &sig, suite); err != nil { return err } r := sig.R c := sig.C // Compute base**(r + x*c) == T var P, T abstract.Point P = suite.Point() T = suite.Point() T.Add(T.Mul(g, r), P.Mul(publicKey, c)) // Verify that the hash based on the message and T // matches the challange c from the signature c = hashElGamal(suite, message, T) if !c.Equal(sig.C) { return errors.New("invalid signature") } return nil }
/* GenerateZ takes some random agreed information and creates Z the "public-only" key that is witness-independent as per the paper. We've probably broken that slightly in this implementation because I could not pick a point without generating it via a Secret, instead of directly via a Point - that is, even as a 32-byte string, we cannot decode on C25519 (and this wouldn't work for abstract suites anyway). However, it demonstrates the idea. */ func GenerateZ(suite abstract.Suite, info []byte) (abstract.Point, error) { hasher := sha3.New256() hasher.Write(info) zraw := hasher.Sum(nil) //I think this might be cheating zrawCt := suite.Cipher(zraw) zfactor := suite.Secret().Pick(zrawCt) Z := suite.Point() Z.Mul(nil, zfactor) // every 32-bit integer exists on Curve25519 only if we have the fullgroup // this should work, but doesn't. /*var Z abstract.Point zrawBuf := bytes.NewBuffer(zraw) err := abstract.Read(zrawBuf, &Z, suite); if err != nil { return nil, err }*/ return Z, nil }
func NewNode(hn coconet.Host, suite abstract.Suite, random cipher.Stream) *Node { sn := &Node{Host: hn, suite: suite} msgSuite = suite sn.PrivKey = suite.Secret().Pick(random) sn.PubKey = suite.Point().Mul(nil, sn.PrivKey) sn.peerKeys = make(map[string]abstract.Point) sn.Rounds = make(map[int]*Round) sn.closed = make(chan error, 20) sn.done = make(chan int, 10) sn.commitsDone = make(chan int, 10) sn.viewChangeCh = make(chan string, 0) sn.FailureRate = 0 h := fnv.New32a() h.Write([]byte(hn.Name())) seed := h.Sum32() sn.Rand = rand.New(rand.NewSource(int64(seed))) sn.Host.SetSuite(suite) sn.VoteLog = NewVoteLog() sn.Actions = make(map[int][]*Vote) sn.RoundsPerView = 100 return sn }
// Determine all the alternative DH point positions for a ciphersuite. func (si *suiteInfo) init(ste abstract.Suite, nlevels int) { si.ste = ste si.tag = make([]uint32, nlevels) si.pos = make([]int, nlevels) si.plen = ste.Point().(abstract.Hiding).HideLen() // XXX // Create a pseudo-random stream from which to pick positions str := fmt.Sprintf("NegoCipherSuite:%s", ste.String()) rand := ste.Cipher([]byte(str)) // Alternative 0 is always at position 0, so start with level 1. levofs := 0 // starting offset for current level //fmt.Printf("Suite %s positions:\n", ste.String()) for i := 0; i < nlevels; i++ { // Pick a random position within this level var buf [4]byte rand.XORKeyStream(buf[:], buf[:]) levlen := 1 << uint(i) // # alt positions at this level levmask := levlen - 1 // alternative index mask si.tag[i] = binary.BigEndian.Uint32(buf[:]) levidx := int(si.tag[i]) & levmask si.pos[i] = levofs + levidx*si.plen //fmt.Printf("%d: idx %d/%d pos %d\n", // i, levidx, levlen, si.pos[i]) levofs += levlen * si.plen // next level table offset } // Limit of highest point field si.max = si.pos[nlevels-1] + si.plen }
// 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 }
// Create new signing node that incorporates a given private key func NewKeyedNode(hn coconet.Host, suite abstract.Suite, PrivKey abstract.Secret) *Node { sn := &Node{Host: hn, suite: suite, PrivKey: PrivKey} sn.PubKey = suite.Point().Mul(nil, sn.PrivKey) sn.peerKeys = make(map[string]abstract.Point) sn.closed = make(chan error, 20) sn.done = make(chan int, 10) sn.commitsDone = make(chan int, 10) sn.viewChangeCh = make(chan string, 0) sn.RoundCommits = make(map[int][]*SigningMessage) sn.RoundResponses = make(map[int][]*SigningMessage) sn.FailureRate = 0 h := fnv.New32a() h.Write([]byte(hn.Name())) seed := h.Sum32() sn.Rand = rand.New(rand.NewSource(int64(seed))) sn.Host.SetSuite(suite) sn.VoteLog = NewVoteLog() sn.Actions = make(map[int][]*Vote) sn.RoundsPerView = 0 sn.Rounds = make(map[int]Round) sn.MaxWait = 50 * time.Second return sn }
// VerifySignature verifies if the challenge and the secret (from the response phase) form a // correct signature for this message using the aggregated public key. func VerifySignature(suite abstract.Suite, msg []byte, public abstract.Point, challenge, secret abstract.Scalar) error { // recompute the challenge and check if it is the same commitment := suite.Point() commitment = commitment.Add(commitment.Mul(nil, secret), suite.Point().Mul(public, challenge)) return verifyCommitment(suite, msg, commitment, challenge) }
func ElGamalDecrypt(suite abstract.Suite, prikey abstract.Secret, K, C abstract.Point) ( M abstract.Point) { // ElGamal-decrypt the ciphertext (K,C) to reproduce the message. S := suite.Point().Mul(K, prikey) // regenerate shared secret M = suite.Point().Sub(C, S) // use to un-blind the message 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 }
// GenerateKeyPair generates a new random private/public keypair in the specified group func GenerateKeyPair(suite abstract.Suite) (*PriKey, *PubKey) { secret := suite.Secret().Pick(suite.Cipher(nil)) base := suite.Point().Base() pk := PubKey{suite, base, suite.Point().Mul(base, secret)} sk := PriKey{pk, secret} return &sk, &pk }
// ReadPubHex reads a hexadecimal representation of a public point and convert it to the // right struct func ReadPubHex(suite abstract.Suite, s string) (abstract.Point, error) { encoded, err := hex.DecodeString(s) if err != nil { return nil, err } point := suite.Point() err = point.UnmarshalBinary(encoded) return point, err }
func ElGamalDecrypt(suite abstract.Suite, prikey abstract.Secret, K, C abstract.Point) ( message []byte, err error) { // ElGamal-decrypt the ciphertext (K,C) to reproduce the message. S := suite.Point().Mul(K, prikey) // regenerate shared secret M := suite.Point().Sub(C, S) // use to un-blind the message message, err = M.Data() // extract the embedded data return }
// GetSharedSecret returns the shared secret, as in the Verdict hash-based construction, for the given public and // private keys func GetSharedSecret(pk *PubKey, sk *PriKey) (abstract.Secret, abstract.Point) { var suite abstract.Suite suite = crypto.Suite point := suite.Point().Mul(pk.Elem, sk.secret) r := crypto.HashKDF(point) R := suite.Point().Mul(crypto.Generator, r) return r, R }
// generate keys for the tree func (t *Tree) GenKeys(suite abstract.Suite, rand abstract.Cipher) { t.TraverseTree(func(t *Tree) { PrivKey := suite.Secret().Pick(rand) PubKey := suite.Point().Mul(nil, PrivKey) prk, _ := PrivKey.MarshalBinary() pbk, _ := PubKey.MarshalBinary() t.PriKey = string(hex.EncodeToString(prk)) t.PubKey = string(hex.EncodeToString(pbk)) }) }
// computeSubtreeAggregate will compute the aggregate subtree public key for // each node of the tree. // root is the root of the subtree we want to compute the aggregate for // recursive function so it will go down to the leaves then go up to the root // Return the aggregate sub tree public key for this root (and compute each sub // aggregate public key for each of the children). func (t *Tree) computeSubtreeAggregate(suite abstract.Suite, root *TreeNode) abstract.Point { aggregate := suite.Point().Add(suite.Point().Null(), root.ServerIdentity.Public) // DFS search for _, ch := range root.Children { aggregate = aggregate.Add(aggregate, t.computeSubtreeAggregate(suite, ch)) } // sets the field root.PublicAggregateSubTree = aggregate return aggregate }
func ElGamalEncrypt(suite abstract.Suite, pubkey abstract.Point, M abstract.Point) ( 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.Secret().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 (v *stateVector) addShuffle(suite abstract.Suite, shuf *shuffler, rand abstract.Cipher) error { // Get the previous shuffle state. i := len(v.States) prev := v.States[i-1] X, Y := prev.X, prev.Dec // Compute the new base using the public keys of the remaining // servers. H := suite.Point().Null() for j := i - 1; j < shuf.N; j++ { H = suite.Point().Add(H, shuf.HH[j]) } // Do a key-shuffle. Xbar, Ybar, prover := shuffle.Shuffle(suite, nil, H, X, Y, rand) prf, err := proof.HashProve(suite, "PairShuffle", rand, prover) if err != nil { return err } // Seeded random for the decryption proof. seed := abstract.Sum(suite, prf) prfRand := suite.Cipher(seed) // Scratch space for calculations. zs := suite.Secret() zp := suite.Point() // Peel off a layer of encryption. dec := make([]abstract.Point, len(Xbar)) decPrf := make([]*decryptionProof, len(Xbar)) for j := range Xbar { // Decryption. zp.Mul(Xbar[j], shuf.h) dec[j] = suite.Point().Sub(Ybar[j], zp) // Decryption proof. t := suite.Secret().Pick(rand) T := suite.Point().Mul(Xbar[j], t) c := suite.Secret().Pick(prfRand) s := suite.Secret().Add(t, zs.Mul(c, shuf.h)) decPrf[j] = &decryptionProof{T, s} } // Append the new state to the state vector. state := &shuffleState{H, Xbar, Ybar, dec, prf, decPrf} v.States = append(v.States, state) return nil }
// The schnorrGenerateKeypair does exactly that - // it generates a valid keypair for later use // in producing signatures. // I wanted to add a little bit of proper key // management to the process but I couldn't work out // how to pass a simple random stream to suite.Secret().Pick(). // I looked into Go streams very briefly but decided // I was spending too much time on that // instead I passed /dev/urandom through the cipher // interface. func SchnorrGenerateKeypair(suite abstract.Suite) (SchnorrKeyset, error) { rsource := make([]byte, 16) _, err := rand.Read(rsource) if err != nil { return SchnorrKeyset{}, err } rct := suite.Cipher(rsource) x := suite.Secret().Pick(rct) // some x y := suite.Point().Mul(nil, x) // y = g^x \in G, DLP. return SchnorrKeyset{x, y}, nil }
func newHost(suite abstract.Suite, rand cipher.Stream, hostname string) *host { h := &host{} h.name = hostname h.log.init(suite) h.pri = suite.Secret().Pick(rand) h.pub = suite.Point().Mul(nil, h.pri) h.id = abstract.HashBytes(suite, h.pub.Encode()) h.peers = make(map[string]*peer) h.trees = make(map[string]*treeNode) return h }
func SchnorrMGenerateCommitment(suite abstract.Suite) (SchnorrMPrivateCommitment, error) { rsource := make([]byte, 16) _, err := rand.Read(rsource) if err != nil { return SchnorrMPrivateCommitment{}, err } // I have no idea if I just encrypted randomness or not // I'm hoping this just reads the state out. rct := suite.Cipher(rsource) v := suite.Secret().Pick(rct) // some v t := suite.Point().Mul(nil, v) // g^v = t return SchnorrMPrivateCommitment{T: t, V: v}, nil }
func (c *ownedCoder) commonSetup(suite abstract.Suite) { c.suite = suite // Divide the embeddable data in the verifiable point // between an encryption key and a MAC check c.keylen = suite.Cipher(nil).KeySize() c.maclen = suite.Point().PickLen() - c.keylen if c.maclen < c.keylen*3/4 { panic("misconfigured ciphersuite: MAC too small!") } randkey := make([]byte, suite.Cipher(nil).KeySize()) rand.Read(randkey) c.random = suite.Cipher(randkey) }
// Verify checks a signature generated by Sign. // // The caller provides the message, anonymity set, and linkage scope // with which the signature was purportedly produced. // If the signature is a valid linkable signature (linkScope != nil), // this function returns a linkage tag that uniquely corresponds // to the signer within the given linkScope. // If the signature is a valid unlinkable signature (linkScope == nil), // returns an empty but non-nil byte-slice instead of a linkage tag on success. // Returns a nil linkage tag and an error if the signature is invalid. func Verify(suite abstract.Suite, message []byte, anonymitySet Set, linkScope []byte, signatureBuffer []byte) ([]byte, error) { n := len(anonymitySet) // anonymity set size L := []abstract.Point(anonymitySet) // public keys in ring // Decode the signature buf := bytes.NewBuffer(signatureBuffer) var linkBase, linkTag abstract.Point sig := lSig{} sig.S = make([]abstract.Scalar, n) if linkScope != nil { // linkable ring signature if err := suite.Read(buf, &sig); err != nil { return nil, err } linkStream := suite.Cipher(linkScope) linkBase, _ = suite.Point().Pick(nil, linkStream) linkTag = sig.Tag } else { // unlinkable ring signature if err := suite.Read(buf, &sig.C0); err != nil { return nil, err } if err := suite.Read(buf, &sig.S); err != nil { return nil, err } } // Pre-hash the ring-position-invariant parameters to H1. H1pre := signH1pre(suite, linkScope, linkTag, message) // Verify the signature var P, PG, PH abstract.Point P = suite.Point() PG = suite.Point() if linkScope != nil { PH = suite.Point() } s := sig.S ci := sig.C0 for i := 0; i < n; i++ { PG.Add(PG.Mul(nil, s[i]), P.Mul(L[i], ci)) if linkScope != nil { PH.Add(PH.Mul(linkBase, s[i]), P.Mul(linkTag, ci)) } ci = signH1(suite, H1pre, PG, PH) } if !ci.Equal(sig.C0) { return nil, errors.New("invalid signature") } // Return the re-encoded linkage tag, for uniqueness checking if linkScope != nil { tag, _ := linkTag.MarshalBinary() return tag, nil } else { return []byte{}, 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.Secret().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.Secret) { 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.Secret().Pick(rand) X[0] = suite.Point().Mul(nil, x) return X, x }
// VerifySignatureWithException will verify the signature taking into account // the exceptions given. An exception is the pubilc key + commitment of a peer that did not // sign. // NOTE: No exception mechanism for "before" commitment has been yet coded. func VerifySignatureWithException(suite abstract.Suite, public abstract.Point, msg []byte, challenge, secret abstract.Scalar, exceptions []Exception) error { // first reduce the aggregate public key subPublic := suite.Point().Add(suite.Point().Null(), public) aggExCommit := suite.Point().Null() for _, ex := range exceptions { subPublic = subPublic.Sub(subPublic, ex.Public) aggExCommit = aggExCommit.Add(aggExCommit, ex.Commitment) } // recompute the challenge and check if it is the same commitment := suite.Point() commitment = commitment.Add(commitment.Mul(nil, secret), suite.Point().Mul(public, challenge)) // ADD the exceptions commitment here commitment = commitment.Add(commitment, aggExCommit) // check if it is ok return verifyCommitment(suite, msg, commitment, challenge) }
// VerifySchnorr verifies a given Schnorr signature. It returns nil iff the given signature is valid. func VerifySchnorr(suite abstract.Suite, public abstract.Point, msg []byte, sig SchnorrSig) error { // compute rv = g^s * y^e (where y = g^x) gs := suite.Point().Mul(nil, sig.Response) ye := suite.Point().Mul(public, sig.Challenge) rv := suite.Point().Add(gs, ye) // recompute challenge (e) from rv e, err := hash(suite, rv, msg) if err != nil { return err } if !e.Equal(sig.Challenge) { return errors.New("Signature not valid: Reconstructed challenge isn't equal to challenge in signature") } return nil }
// 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 }
// This simplified implementation of ElGamal Signatures is based on // crypto/anon/sig.go func ElGamalSign(suite abstract.Suite, random cipher.Stream, message []byte, privateKey abstract.Secret) BasicSig { // Create random secret v and public point commitment T v := suite.Secret().Pick(random) T := suite.Point().Mul(nil, v) // Create challenge c based on message and T c := hashElGamal(suite, message, T) // Compute response r = v - x*c r := suite.Secret() r.Mul(privateKey, c).Sub(v, r) // Return verifiable signature {c, r} sig := BasicSig{c, r} return sig }