Skip to content
Snippets Groups Projects
Commit 372c23f8 authored by Benjamin Wenger's avatar Benjamin Wenger
Browse files

Merge branch 'XX-3077/partnerRelationshipFingerprint' into 'release'

XX-3077/ Relationship Fingerprint

See merge request !624
parents 282de08b bced126a
No related branches found
No related tags found
1 merge request!23Release
......@@ -125,3 +125,17 @@ func (c *Client) MakePrecannedContact(precannedID uint) contact.Contact {
Facts: make([]fact.Fact, 0),
}
}
// GetRelationshipFingerprint returns a unique 15 character fingerprint for an
// E2E relationship. An error is returned if no relationship with the partner
// is found.
func (c *Client) GetRelationshipFingerprint(partner *id.ID) (string, error) {
m, err := c.storage.E2e().GetPartner(partner)
if err != nil {
return "", errors.Errorf("could not get partner %s: %+v", partner, err)
} else if m == nil {
return "", errors.Errorf("manager for partner %s is nil.", partner)
}
return m.GetRelationshipFingerprint(), nil
}
......@@ -11,6 +11,7 @@ import (
"errors"
"fmt"
"gitlab.com/elixxir/crypto/contact"
"gitlab.com/xx_network/primitives/id"
)
// Create an insecure e2e relationship with a precanned user
......@@ -123,3 +124,15 @@ func (c *Client) VerifyOwnership(receivedMarshaled, verifiedMarshaled []byte) (b
return c.api.VerifyOwnership(received, verified), nil
}
// GetRelationshipFingerprint returns a unique 15 character fingerprint for an
// E2E relationship. An error is returned if no relationship with the partner
// is found.
func (c *Client) GetRelationshipFingerprint(partnerID []byte) (string, error) {
partner, err := id.Unmarshal(partnerID)
if err != nil {
return "", err
}
return c.api.GetRelationshipFingerprint(partner)
}
......@@ -8,6 +8,8 @@
package e2e
import (
"bytes"
"encoding/base64"
"fmt"
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
......@@ -17,6 +19,8 @@ import (
"gitlab.com/elixxir/crypto/cyclic"
dh "gitlab.com/elixxir/crypto/diffieHellman"
"gitlab.com/xx_network/primitives/id"
"golang.org/x/crypto/blake2b"
"sort"
)
const managerPrefix = "Manager{partner:%s}"
......@@ -198,3 +202,24 @@ func (m *Manager) GetMyOriginPrivateKey() *cyclic.Int {
func (m *Manager) GetPartnerOriginPublicKey() *cyclic.Int {
return m.originPartnerPubKey.DeepCopy()
}
const relationshipFpLength = 15
// GetRelationshipFingerprint returns a unique fingerprint for an E2E
// relationship. The fingerprint is a base 64 encoded hash of of the two
// relationship fingerprints truncated to 15 characters.
func (m *Manager) GetRelationshipFingerprint() string {
// Sort fingerprints
fps := [][]byte{m.receive.fingerprint, m.send.fingerprint}
less := func(i, j int) bool { return bytes.Compare(fps[i], fps[j]) == -1 }
sort.Slice(fps, less)
// Hash fingerprints
h, _ := blake2b.New256(nil)
for _, fp := range fps {
h.Write(fp)
}
// Base 64 encode hash and truncate
return base64.StdEncoding.EncodeToString(h.Sum(nil))[:relationshipFpLength]
}
......@@ -9,12 +9,14 @@ package e2e
import (
"bytes"
"encoding/base64"
"fmt"
"gitlab.com/elixxir/client/interfaces/params"
"gitlab.com/elixxir/client/storage/versioned"
"gitlab.com/elixxir/ekv"
"gitlab.com/xx_network/primitives/id"
"gitlab.com/xx_network/primitives/netTime"
"golang.org/x/crypto/blake2b"
"math/rand"
"reflect"
"testing"
......@@ -283,3 +285,65 @@ func managersEqual(expected, received *Manager, t *testing.T) bool {
return equal
}
// Unit test of Manager.GetRelationshipFingerprint.
func TestManager_GetRelationshipFingerprint(t *testing.T) {
m, _ := newTestManager(t)
m.receive.fingerprint = []byte{5}
m.send.fingerprint = []byte{10}
h, _ := blake2b.New256(nil)
h.Write(append(m.receive.fingerprint, m.send.fingerprint...))
expected := base64.StdEncoding.EncodeToString(h.Sum(nil))[:relationshipFpLength]
fp := m.GetRelationshipFingerprint()
if fp != expected {
t.Errorf("GetRelationshipFingerprint did not return the expected "+
"fingerprint.\nexpected: %s\nreceived: %s", expected, fp)
}
// Flip the order and show that the output is the same.
m.receive.fingerprint, m.send.fingerprint = m.send.fingerprint, m.receive.fingerprint
fp = m.GetRelationshipFingerprint()
if fp != expected {
t.Errorf("GetRelationshipFingerprint did not return the expected "+
"fingerprint.\nexpected: %s\nreceived: %s", expected, fp)
}
}
// Tests the consistency of the output of Manager.GetRelationshipFingerprint.
func TestManager_GetRelationshipFingerprint_Consistency(t *testing.T) {
m, _ := newTestManager(t)
prng := rand.New(rand.NewSource(42))
expectedFps := []string{
"GmeTCfxGOqRqeID", "gbpJjHd3tIe8BKy", "2/ZdG+WNzODJBiF",
"+V1ySeDLQfQNSkv", "23OMC+rBmCk+gsu", "qHu5MUVs83oMqy8",
"kuXqxsezI0kS9Bc", "SlEhsoZ4BzAMTtr", "yG8m6SPQfV/sbTR",
"j01ZSSm762TH7mj", "SKFDbFvsPcohKPw", "6JB5HK8DHGwS4uX",
"dU3mS1ujduGD+VY", "BDXAy3trbs8P4mu", "I4HoXW45EwWR0oD",
"661YH2l2jfOkHbA", "cSS9ZyTOQKVx67a", "ojfubzDIsMNYc/t",
"2WrEw83Yz6Rhq9I", "TQILxBIUWMiQS2j", "rEqdieDTXJfCQ6I",
}
for i, expected := range expectedFps {
prng.Read(m.receive.fingerprint)
prng.Read(m.send.fingerprint)
fp := m.GetRelationshipFingerprint()
if fp != expected {
t.Errorf("GetRelationshipFingerprint did not return the expected "+
"fingerprint (%d).\nexpected: %s\nreceived: %s", i, expected, fp)
}
// Flip the order and show that the output is the same.
m.receive.fingerprint, m.send.fingerprint = m.send.fingerprint, m.receive.fingerprint
fp = m.GetRelationshipFingerprint()
if fp != expected {
t.Errorf("GetRelationshipFingerprint did not return the expected "+
"fingerprint (%d).\nexpected: %s\nreceived: %s", i, expected, fp)
}
// fmt.Printf("\"%s\",\n", fp) // Uncomment to reprint expected values
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment