Esempio n. 1
0
func (ch *Channel) AddFullUpdateTx(ev *wire.Envelope, utx *wire.UpdateTx) error {
	if !(ch.Phase == OPEN || ch.Phase == PENDING_CLOSED) {
		return errors.New("channel not OPEN or PENDING_CLOSED")
	}
	if len(ev.Signatures) != 2 {
		return errors.New("wrong number of signatures")
	}
	if !ed25519.Verify(sliceTo32Byte(ch.Account.Pubkey), ev.Payload, sliceTo64Byte(ev.Signatures[ch.Me])) {
		return errors.New("my account signature not valid")
	}
	if !ed25519.Verify(sliceTo32Byte(ch.Counterparty.Pubkey), ev.Payload, sliceTo64Byte(ev.Signatures[swap[ch.Me]])) {
		return errors.New("counterparty signature not valid")
	}
	if utx.ChannelId != ch.OpeningTx.ChannelId {
		return errors.New("channel id incorrect")
	}
	if ch.LastFullUpdateTx != nil {
		if utx.SequenceNumber > ch.LastFullUpdateTx.SequenceNumber {
			return errors.New("sequence number too low")
		}
	}

	ch.LastFullUpdateTx = utx
	ch.LastFullUpdateTxEnvelope = ev

	return nil
}
func (jd *Judge) AddChannel(ev *wire.Envelope, otx *wire.OpeningTx, acct0 *Account, acct1 *Account) (*Channel, error) {
	if len(ev.Signatures) != 2 {
		return nil, errors.New("wrong number of signatures")
	}
	if len(otx.Pubkeys) != 2 {
		return nil, errors.New("wrong number of public keys")
	}
	if bytes.Compare(acct0.Judge.Pubkey, acct1.Judge.Pubkey) != 0 {
		return nil, errors.New("accounts do not have matching judges")
	}
	if !ed25519.Verify(sliceTo32Byte(otx.Pubkeys[0]), ev.Payload, sliceTo64Byte(ev.Signatures[0])) {
		return nil, errors.New("signature 0 not valid")
	}
	if !ed25519.Verify(sliceTo32Byte(otx.Pubkeys[1]), ev.Payload, sliceTo64Byte(ev.Signatures[1])) {
		return nil, errors.New("signature 1 not valid")
	}

	ch := &Channel{
		ChannelId:         otx.ChannelId,
		OpeningTx:         otx,
		OpeningTxEnvelope: ev,
		Accounts:          []*Account{acct0, acct1},
		Judge:             jd,
		Phase:             PENDING_OPEN,
	}

	return ch, nil
}
Esempio n. 3
0
func (ch *Channel) Open(ev *wire.Envelope, otx *wire.OpeningTx) error {
	if ch.Phase != PENDING_OPEN {
		return errors.New("channel not PENDING_OPEN")
	}
	if len(ev.Signatures) != 3 {
		return errors.New("wrong number of signatures")
	}
	if !ed25519.Verify(sliceTo32Byte(ch.Account.Pubkey), ev.Payload, sliceTo64Byte(ev.Signatures[ch.Me])) {
		return errors.New("my account signature not valid")
	}
	if !ed25519.Verify(sliceTo32Byte(ch.Counterparty.Pubkey), ev.Payload, sliceTo64Byte(ev.Signatures[swap[ch.Me]])) {
		return errors.New("counterparty signature not valid")
	}
	if !ed25519.Verify(sliceTo32Byte(ch.Judge.Pubkey), ev.Payload, sliceTo64Byte(ev.Signatures[2])) {
		return errors.New("judge signature not valid")
	}

	if bytes.Compare(ev.Payload, ch.OpeningTxEnvelope.Payload) != 0 {
		return errors.New("opening tx not valid")
	}

	ch.Phase = OPEN
	ch.OpeningTx = otx
	ch.OpeningTxEnvelope = ev

	return nil
}
Esempio n. 4
0
func checkAuth(w http.ResponseWriter, login, token, sig string) {
	tokenRaw, err := base64.StdEncoding.DecodeString(token)
	if err != nil {
		log.Println(err)
		http.Error(w, "Error with your request", http.StatusBadRequest)
		return
	}

	sigRaw, err := base64.StdEncoding.DecodeString(sig)
	if err != nil {
		log.Println(err)
		http.Error(w, "Error with your request", http.StatusBadRequest)
		return
	}

	var sigForVerif [ed25519.SignatureSize]byte
	copy(sigForVerif[:], sigRaw[:])

	user, ok := users[login]
	if !ok {
		http.Error(w, "Bad auth", http.StatusUnauthorized)
		return
	}

	userPubKeyRaw, err := base64.StdEncoding.DecodeString(user.PubKey)
	if err != nil || len(userPubKeyRaw) != ed25519.PublicKeySize {
		http.Error(w, "Internal error", http.StatusInternalServerError)
		return
	}
	var userPubKey [ed25519.PublicKeySize]byte
	copy(userPubKey[:], userPubKeyRaw)

	ok = ed25519.Verify(&userPubKey, tokenRaw, &sigForVerif)
	if ok {
		if len(tokenRaw) != 32+ed25519.SignatureSize {
			http.Error(w, "Bad token", http.StatusUnauthorized)
			return
		}
		ourToken := tokenRaw[:len(tokenRaw)-ed25519.SignatureSize]
		ourSig := tokenRaw[len(tokenRaw)-ed25519.SignatureSize:]
		var ourSigForVerif [ed25519.SignatureSize]byte
		copy(ourSigForVerif[:], ourSig)

		ok = ed25519.Verify(signingPubKey, ourToken, &ourSigForVerif)
		if !ok {
			http.Error(w, "Bad token", http.StatusUnauthorized)
			return
		}
		log.Printf("%s just logged in\n", login)
	} else {
		log.Printf("%s didn't log in", login)
		http.Error(w, "Bad auth", http.StatusUnauthorized)
	}
}
func (ch *Channel) AddFollowOnTx(ev *wire.Envelope) error {
	if ch.Phase != OPEN {
		return errors.New("channel not OPEN")
	}
	if len(ev.Signatures) != 1 {
		return errors.New("wrong number of signatures")
	}
	if !ed25519.Verify(sliceTo32Byte(ch.Accounts[0].Pubkey), ev.Payload, sliceTo64Byte(ev.Signatures[0])) ||
		!ed25519.Verify(sliceTo32Byte(ch.Accounts[1].Pubkey), ev.Payload, sliceTo64Byte(ev.Signatures[0])) {
		return errors.New("signature not valid")
	}

	ch.FollowOnTxs = append(ch.FollowOnTxs, ev)
	return nil
}
Esempio n. 6
0
// Verify checks whether the message has a valid signature.
func Verify(publicKey [32]byte, message []byte, signature *[64]byte) bool {

	publicKey[31] &= 0x7F

	/* Convert the Curve25519 public key into an Ed25519 public key.  In
	particular, convert Curve25519's "montgomery" x-coordinate into an
	Ed25519 "edwards" y-coordinate:

	ed_y = (mont_x - 1) / (mont_x + 1)

	NOTE: mont_x=-1 is converted to ed_y=0 since fe_invert is mod-exp

	Then move the sign bit into the pubkey from the signature.
	*/

	var edY, one, montX, montXMinusOne, montXPlusOne edwards25519.FieldElement
	edwards25519.FeFromBytes(&montX, &publicKey)
	edwards25519.FeOne(&one)
	edwards25519.FeSub(&montXMinusOne, &montX, &one)
	edwards25519.FeAdd(&montXPlusOne, &montX, &one)
	edwards25519.FeInvert(&montXPlusOne, &montXPlusOne)
	edwards25519.FeMul(&edY, &montXMinusOne, &montXPlusOne)

	var A_ed [32]byte
	edwards25519.FeToBytes(&A_ed, &edY)

	A_ed[31] |= signature[63] & 0x80
	signature[63] &= 0x7F

	return ed25519.Verify(&A_ed, message, signature)
}
Esempio n. 7
0
// Verify checks that an ed25519 signature is valid
func (v Ed25519Verifier) Verify(key data.PublicKey, sig []byte, msg []byte) error {
	if key.Algorithm() != data.ED25519Key {
		return ErrInvalidKeyType{}
	}
	var sigBytes [ed25519.SignatureSize]byte
	if len(sig) != ed25519.SignatureSize {
		logrus.Debugf("signature length is incorrect, must be %d, was %d.", ed25519.SignatureSize, len(sig))
		return ErrInvalid
	}
	copy(sigBytes[:], sig)

	var keyBytes [ed25519.PublicKeySize]byte
	pub := key.Public()
	if len(pub) != ed25519.PublicKeySize {
		logrus.Errorf("public key is incorrect size, must be %d, was %d.", ed25519.PublicKeySize, len(pub))
		return ErrInvalidKeyLength{msg: fmt.Sprintf("ed25519 public key must be %d bytes.", ed25519.PublicKeySize)}
	}
	n := copy(keyBytes[:], key.Public())
	if n < ed25519.PublicKeySize {
		logrus.Errorf("failed to copy the key, must have %d bytes, copied %d bytes.", ed25519.PublicKeySize, n)
		return ErrInvalid
	}

	if !ed25519.Verify(&keyBytes, msg, &sigBytes) {
		logrus.Debugf("failed ed25519 verification")
		return ErrInvalid
	}
	return nil
}
Esempio n. 8
0
func (u *User) SetKeys(pubkey *[ed25519.PublicKeySize]byte, privkey *[ed25519.PrivateKeySize]byte) (err error) {
	sign := ed25519.Sign(privkey, signtestmsg)
	if ed25519.Verify(pubkey, signtestmsg, sign) {
		return nil
	}
	return ErrInvalidKey
}
Esempio n. 9
0
// NewED25519Verifierr returns a Verifier that uses the ED25519 algorithm to verify updates.
func NewED25519Verifier(targetVersion string) update.Verifier {

	return verifyFn(func(checksum, signature []byte, hash crypto.Hash, publicKey crypto.PublicKey) error {
		key, ok := publicKey.(*[32]byte)
		if !ok {
			return errors.New("not a valid public key length")
		}

		if len(signature) != 64 {
			return fmt.Errorf("invalid signature length")
		}
		var sigRes = new([64]byte)
		for i, v := range signature {
			sigRes[i] = v
		}
		var b []byte
		b = append(b, []byte(targetVersion)...)
		b = append(b, byte(0))
		b = append(b, checksum...)
		if !ed25519.Verify(key, checksum, sigRes) {
			return errors.New("failed to verify signature")
		}

		return nil
	})
}
Esempio n. 10
0
// VerifySessionKey authenticates a session key.
func (id *Identity) VerifySessionKey(sk *[SessionKeySize]byte) (*[64]byte, bool) {
	peerID := new([ed25519.PublicKeySize]byte)
	keyData := new([64]byte)
	signature := new([ed25519.SignatureSize]byte)
	copy(peerID[:], sk[:])
	copy(keyData[:], sk[ed25519.PublicKeySize:])
	copy(signature[:], sk[blobDataSize:])

	var found bool
	for i := range id.peers {
		if subtle.ConstantTimeCompare(id.peers[i][:], peerID[:]) == 1 {
			found = true
		}
	}

	if !found {
		if id.PeerLookup != nil {
			if !id.PeerLookup(peerID) {
				return nil, false
			}
		} else {
			return nil, false
		}
	}

	if !ed25519.Verify(peerID, sk[:blobDataSize], signature) {
		return nil, false
	}

	return keyData, true
}
Esempio n. 11
0
func GetKey(conn *transport.Conn, inBuf []byte, pk *[32]byte, dename string, pkSig *[32]byte) (*[32]byte, error) {
	getKey := &proto.ClientToServer{
		GetSignedKey: (*proto.Byte32)(pk),
	}
	if err := WriteProtobuf(conn, getKey); err != nil {
		return nil, err
	}

	response, err := ReceiveProtobuf(conn, inBuf)
	if err != nil {
		return nil, err
	}

	var userKey [32]byte
	copy(userKey[:], response.SignedKey[:32])

	var sig [64]byte
	copy(sig[:], response.SignedKey[32:(32+64)])

	if !ed25519.Verify(pkSig, userKey[:], &sig) {
		return nil, errors.New("Improperly signed key returned")
	}

	return &userKey, nil
}
Esempio n. 12
0
// Verify verifies a public key using SignaturePublicKey.
func (pk PublicKey) Verify(SignaturePublicKey *[ed25519.PublicKeySize]byte) bool {
	tcalc := pk.CalcKeyID()
	if tcalc != pk.KeyID {
		return false
	}
	return ed25519.Verify(SignaturePublicKey, tcalc[:], &pk.Signature)
}
Esempio n. 13
0
// VerifyOpeningTx checks the signatures of an OpeningTx, unmarshals it and returns it.
func VerifyOpeningTx(ev *wire.Envelope) (*wire.OpeningTx, error) {
	otx := wire.OpeningTx{}
	err := proto.Unmarshal(ev.Payload, &otx)
	if err != nil {
		return nil, err
	}

	// Check signatures
	if !ed25519.Verify(sliceTo32Byte(otx.Pubkey1), ev.Payload, sliceTo64Byte(ev.Signature1)) {
		return nil, errors.New("signature 1 invalid")
	}
	if !ed25519.Verify(sliceTo32Byte(otx.Pubkey2), ev.Payload, sliceTo64Byte(ev.Signature2)) {
		return nil, errors.New("signature 2 invalid")
	}

	return &otx, nil
}
Esempio n. 14
0
// VerifyUpdateTx checks the signatures of an UpdateTx, unmarshals it and returns it.
func (ch *Channel) VerifyUpdateTx(ev *wire.Envelope) (*wire.UpdateTx, error) {
	// Check signatures
	if !ed25519.Verify(sliceTo32Byte(ch.OpeningTx.Pubkey1), ev.Payload, sliceTo64Byte(ev.Signature1)) {
		return nil, errors.New("signature 1 invalid")
	}
	if !ed25519.Verify(sliceTo32Byte(ch.OpeningTx.Pubkey2), ev.Payload, sliceTo64Byte(ev.Signature2)) {
		return nil, errors.New("signature 2 invalid")
	}

	utx := wire.UpdateTx{}
	err := proto.Unmarshal(ev.Payload, &utx)
	if err != nil {
		return nil, err
	}

	return &utx, nil
}
Esempio n. 15
0
func (ch *Channel) AddClosingTx(ev *wire.Envelope) error {
	if ch.Phase != OPEN {
		return errors.New("channel not OPEN")
	}
	if len(ev.Signatures) != 1 {
		return errors.New("wrong number of signatures")
	}
	if !ed25519.Verify(sliceTo32Byte(ch.Accounts[0].Pubkey), ev.Payload, sliceTo64Byte(ev.Signatures[0])) &&
		!ed25519.Verify(sliceTo32Byte(ch.Accounts[1].Pubkey), ev.Payload, sliceTo64Byte(ev.Signatures[0])) {
		return errors.New("signature not valid")
	}

	ch.ClosingTxEnvelope = ev
	ch.CloseTime = time.Now()

	return nil
}
Esempio n. 16
0
File: ed.go Progetto: kmeaw/wrongssh
func (key ed25519PublicKey) Verify(data []byte, sig *ssh.Signature) error {
	signature := [ed25519.SignatureSize]byte{}
	copy(signature[:], sig.Blob)
	if !ed25519.Verify(&key.publicKey, data, &signature) {
		return ErrorVerificationFailed
	}

	return nil
}
Esempio n. 17
0
// Verify runs the NaCl verification routine on the given msg / sig
// input.
func (k SigningPublicKey) Verify(msg []byte, sig []byte) error {
	var tmp [ed25519.SignatureSize]byte
	copy(tmp[:], sig)
	ok := ed25519.Verify((*[ed25519.PublicKeySize]byte)(&k), msg, &tmp)
	if !ok {
		return saltpack.ErrBadSignature
	}
	return nil
}
Esempio n. 18
0
// AddFulfillment verifies a fulfillment's signature and adds it to the Channel's
// Fulfillments array.
func (ch *Channel) AddFulfillment(ev *wire.Envelope, eval func()) error {
	if ch.State != schema.Channel_PendingClosed {
		return errors.New("channel must be pending closed")
	}

	if !ed25519.Verify(sliceTo32Byte(ch.OpeningTx.Pubkey1), ev.Payload, sliceTo64Byte(ev.Signature1)) ||
		!ed25519.Verify(sliceTo32Byte(ch.OpeningTx.Pubkey2), ev.Payload, sliceTo64Byte(ev.Signature1)) {
		return errors.New("signature invalid")
	}

	ful := wire.Fulfillment{}
	err := proto.Unmarshal(ev.Payload, &ful)
	if err != nil {
		return err
	}

	ch.Fulfillments = append(ch.Fulfillments, &ful)
	return nil
}
Esempio n. 19
0
// Verify attempts to verify a signature on a message with a key.
func Verify(vk, message []byte, signature []byte) bool {
	key, err := ToByteArray32(vk)
	if err != nil {
		return false
	}
	sig, err := ToByteArray64(signature)
	if err != nil {
		return false
	}
	return ed25519.Verify(key, message, sig)
}
Esempio n. 20
0
func (ek *Ed25519PublicKey) Verify(message []byte, signature *ssh.Signature) error {
	if signature.Format != ek.Type() {
		return fmt.Errorf("edssh: signature type %s for key type %s", signature.Format, ek.Type())
	}
	sig := new([ed25519.SignatureSize]byte)
	copy(sig[:], signature.Blob)
	if ok := ed25519.Verify(ek.bytes, message, sig); !ok {
		return errors.New("edssh: invalid signature for given message")
	}
	return nil
}
Esempio n. 21
0
// VerifyHash uses a public key and input data to verify a signature.
func VerifyHash(data Hash, pk PublicKey, sig Signature) (err error) {
	pkNorm := [PublicKeySize]byte(pk)
	sigNorm := [SignatureSize]byte(sig)
	verifies := ed25519.Verify(&pkNorm, data[:], &sigNorm)
	if !verifies {
		err = ErrInvalidSignature
		return
	}

	return
}
Esempio n. 22
0
func (p *RawPacket) Validate(pubk *[ed25519.PublicKeySize]byte) bool {
	if p.Signature == nil {
		return false
	}
	length := uint16(len(p.Payload))
	buf := make([]byte, length+4)
	binary.BigEndian.PutUint16(buf, length)
	binary.BigEndian.PutUint16(buf[2:], p.Frametype)
	copy(buf[4:], p.Payload)
	return ed25519.Verify(pubk, buf, p.Signature)
}
Esempio n. 23
0
func (e *edDSAkey) Verify(payload []byte, r parsedMPI, s parsedMPI) bool {
	var key [ed25519.PublicKeySize]byte
	var sig [ed25519.SignatureSize]byte

	// note(mnk): I'm not entirely sure why we need to ignore the first byte.
	copy(key[:], e.p.bytes[1:])
	n := copy(sig[:], r.bytes)
	copy(sig[n:], s.bytes)

	return ed25519.Verify(&key, payload, &sig)
}
Esempio n. 24
0
// VerifySignature returns true iff sig is a valid signature of message by
// verifier.
// pk, message, sig : &const // none of the inputs are modified
func VerifySignature(pk *proto.PublicKey, message []byte, sig []byte) bool {
	switch {
	case pk.Ed25519 != nil:
		var edpk [32]byte
		var edsig [64]byte
		copy(edpk[:], pk.Ed25519[:])
		copy(edsig[:], sig)
		return ed25519.Verify(&edpk, message, &edsig)
	default:
		return false
	}
}
Esempio n. 25
0
// VerifyUpdateTxProposal
func (ch *Channel) VerifyUpdateTxProposal(ev *wire.Envelope) (uint32, error) {
	if ch.State != schema.Channel_Open {
		return 0, errors.New("channel must be open")
	}

	var pubkey [32]byte
	var sig [64]byte

	// Read signature from correct slot
	// Copy signature and pubkey
	switch ch.Me {
	case 1:
		pubkey = *sliceTo32Byte(ch.OpeningTx.Pubkey2)
		sig = *sliceTo64Byte(ev.Signature2)
	case 2:
		pubkey = *sliceTo32Byte(ch.OpeningTx.Pubkey1)
		sig = *sliceTo64Byte(ev.Signature1)
	}

	// Check signature
	if !ed25519.Verify(&pubkey, ev.Payload, &sig) {
		return 0, errors.New("invalid signature")
	}

	utx := wire.UpdateTx{}
	err := proto.Unmarshal(ev.Payload, &utx)
	if err != nil {
		return 0, err
	}

	// Check ChannelID
	if utx.ChannelID != ch.OpeningTx.ChannelID {
		return 0, errors.New("")
	}

	lst := ch.LastUpdateTx

	// Check last sequence number
	if lst.SequenceNumber+1 != utx.SequenceNumber {
		return 0, errors.New("invalid sequence number")
	}

	// Get amount depending on if we are party 1 or party 2
	var amt uint32
	switch ch.Me {
	case 1:
		amt = uint32(lst.NetTransfer - utx.NetTransfer)
	case 2:
		amt = uint32(utx.NetTransfer - lst.NetTransfer)
	}

	return amt, nil
}
Esempio n. 26
0
// GetVerifyList requests a list of known issuer keys from the lookup service
func (klc LookupClient) GetVerifyList() ([][ed25519.PublicKeySize]byte, error) {
	var sig [ed25519.SignatureSize]byte
	var pk [ed25519.PublicKeySize]byte
	method := "PublicService.VerifyKeys"
	client, err := klc.ClientFactory(ServiceURL, klc.ServiceGuardCA)
	if err != nil {
		return nil, err
	}
	data, err := client.JSONRPCRequest(method, nil)
	if err != nil {
		return nil, err
	}
	if _, ok := data["PublicKey"]; !ok {
		return nil, ErrParams
	}
	if _, ok := data["Signature"]; !ok {
		return nil, ErrParams
	}
	if _, ok := data["KeyList"]; !ok {
		return nil, ErrParams
	}
	pubKey, err := hex.DecodeString(data["PublicKey"].(string))
	if err != nil {
		return nil, ErrParams
	}
	copy(pk[:], pubKey)
	if pk != *klc.PubKey {
		return nil, ErrBadSigner
	}

	signature, err := hex.DecodeString(data["Signature"].(string))
	if err != nil {
		return nil, ErrParams
	}
	copy(sig[:], signature)
	keylist := data["KeyList"].(string)
	ok := ed25519.Verify(klc.PubKey, []byte(keylist), &sig)
	if !ok {
		return nil, ErrBadSignature
	}
	keylistSlice := strings.Split(keylist, ", ")
	keylistRet := make([][ed25519.PublicKeySize]byte, 0, len(keylistSlice))
	for _, keyS := range keylistSlice {
		var keyA [ed25519.PublicKeySize]byte
		dk, err := hex.DecodeString(keyS)
		if err != nil {
			return nil, err
		}
		copy(keyA[:], dk)
		keylistRet = append(keylistRet, keyA)
	}
	return keylistRet, nil
}
Esempio n. 27
0
func (s *sigPubKey) Verify(message []byte, signature []byte) error {
	if len(signature) != ed25519.SignatureSize {
		return fmt.Errorf("signature size: %d, expected %d", len(signature), ed25519.SignatureSize)
	}
	var fixed [ed25519.SignatureSize]byte
	copy(fixed[:], signature)

	if !ed25519.Verify(&s.key, message, &fixed) {
		return ErrBadSignature
	}
	return nil
}
Esempio n. 28
0
// ValidateED25519Signature return true when the ED25519 signature is a valid signature of the data based on the key, otherwise false.
func ValidateED25519Signature(key, data, signature []byte) bool {
	if len(key) != ed25519.PublicKeySize || len(signature) != ed25519.SignatureSize {
		return false
	}

	var k [ed25519.PublicKeySize]byte
	var s [ed25519.SignatureSize]byte
	copy(k[:], key)
	copy(s[:], signature)

	return ed25519.Verify(&k, data, &s)
}
Esempio n. 29
0
// VerifySignature returns true iff sig is a valid signature of message by
// verifier.
// pk, message, sig : &const // none of the inputs are modified
func VerifySignature(pk *proto.PublicKey, message []byte, sig []byte) bool {
	switch pk.PubkeyType.(type) {
	case *proto.PublicKey_Ed25519:
		var edpk [32]byte
		var edsig [64]byte
		copy(edpk[:], pk.PubkeyType.(*proto.PublicKey_Ed25519).Ed25519[:])
		copy(edsig[:], sig)
		return ed25519.Verify(&edpk, message, &edsig)
	default:
		return false
	}
}
Esempio n. 30
0
File: client.go Progetto: nico/pond
func (contact *Contact) processKeyExchange(kxsBytes []byte, testing bool) error {
	var kxs pond.SignedKeyExchange
	if err := proto.Unmarshal(kxsBytes, &kxs); err != nil {
		return err
	}

	var sig [64]byte
	if len(kxs.Signature) != len(sig) {
		return errors.New("invalid signature length")
	}
	copy(sig[:], kxs.Signature)

	var kx pond.KeyExchange
	if err := proto.Unmarshal(kxs.Signed, &kx); err != nil {
		return err
	}

	if len(kx.PublicKey) != len(contact.theirPub) {
		return errors.New("invalid public key")
	}
	copy(contact.theirPub[:], kx.PublicKey)

	if !ed25519.Verify(&contact.theirPub, kxs.Signed, &sig) {
		return errors.New("invalid signature")
	}

	contact.theirServer = *kx.Server
	if _, _, err := parseServer(contact.theirServer, testing); err != nil {
		return err
	}

	group, ok := new(bbssig.Group).Unmarshal(kx.Group)
	if !ok {
		return errors.New("invalid group")
	}
	if contact.myGroupKey, ok = new(bbssig.MemberKey).Unmarshal(group, kx.GroupKey); !ok {
		return errors.New("invalid group key")
	}

	if len(kx.IdentityPublic) != len(contact.theirIdentityPublic) {
		return errors.New("invalid public identity")
	}
	copy(contact.theirIdentityPublic[:], kx.IdentityPublic)

	if len(kx.Dh) != len(contact.theirCurrentDHPublic) {
		return errors.New("invalid public DH value")
	}
	copy(contact.theirCurrentDHPublic[:], kx.Dh)

	contact.generation = *kx.Generation

	return nil
}