From b6bb1336d1cc92b12d215a78df7d7f8cf4682e8f Mon Sep 17 00:00:00 2001
From: "Richard T. Carback III" <rick.carback@gmail.com>
Date: Fri, 3 Dec 2021 17:48:41 +0000
Subject: [PATCH] Add SIDH util functions with some corresponding tests

---
 storage/utility/sidH.go      |  45 -----------
 storage/utility/sidh.go      | 149 +++++++++++++++++++++++++++++++++++
 storage/utility/sidh_test.go | 146 ++++++++++++++++++++++++++++++++++
 3 files changed, 295 insertions(+), 45 deletions(-)
 delete mode 100644 storage/utility/sidH.go
 create mode 100644 storage/utility/sidh.go
 create mode 100644 storage/utility/sidh_test.go

diff --git a/storage/utility/sidH.go b/storage/utility/sidH.go
deleted file mode 100644
index 85a23c9cb..000000000
--- a/storage/utility/sidH.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package utility
-
-import (
-	"fmt"
-	"github.com/cloudflare/circl/dh/sidh"
-	sidhinterface "gitlab.com/elixxir/client/interfaces/sidh"
-	"gitlab.com/elixxir/client/storage/versioned"
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/netTime"
-)
-
-const currentSidHPubKeyAVersion = 0
-
-func StoreSidHPubKeyA(kv *versioned.KV, id *id.ID, sidH *sidh.PublicKey) error {
-	now := netTime.Now()
-
-	sidHBytes := make([]byte, sidH.Size())
-	sidH.Export(sidHBytes)
-
-	obj := versioned.Object{
-		Version:   currentSidHPubKeyAVersion,
-		Timestamp: now,
-		Data:      sidHBytes,
-	}
-
-	return kv.Set(makeSidHtKeyA(id), currentSidHPubKeyAVersion, &obj)
-}
-
-func LoadSidHPubKeyA(kv *versioned.KV, cid *id.ID) (*sidh.PublicKey, error) {
-	vo, err := kv.Get(makeSidHtKeyA(cid), currentSidHPubKeyAVersion)
-	if err != nil {
-		return nil, err
-	}
-
-	sidHPubkey := sidh.NewPublicKey(sidhinterface.SidHKeyId, sidh.KeyVariantSidhA)
-	return sidHPubkey, sidHPubkey.Import(vo.Data)
-}
-
-func DeleteSidHPubKeyA(kv *versioned.KV, cid *id.ID) error {
-	return kv.Delete(makeSidHtKeyA(cid), currentSidHPubKeyAVersion)
-}
-
-func makeSidHtKeyA(cid *id.ID) string {
-	return fmt.Sprintf("SidKPubKeyA:%s", cid)
-}
diff --git a/storage/utility/sidh.go b/storage/utility/sidh.go
new file mode 100644
index 000000000..684b65901
--- /dev/null
+++ b/storage/utility/sidh.go
@@ -0,0 +1,149 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package utility
+
+import (
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/xx_network/primitives/netTime"
+	"github.com/cloudflare/circl/dh/sidh"
+	"encoding/base64"
+	sidhinterface "gitlab.com/elixxir/client/interfaces/sidh"
+	"gitlab.com/xx_network/primitives/id"
+	"fmt"
+)
+
+const currentSIDHVersion = 0
+
+// NewSIDHPUblicKey is a helper which returns a proper new SIDH public key
+// Right now this is set to Fp434 but it could change.
+func NewSIDHPublicKey(variant sidh.KeyVariant) *sidh.PublicKey {
+	return sidh.NewPublicKey(sidhinterface.KeyId, variant)
+}
+
+// NewSIDHPUblicKey is a helper which returns a proper new SIDH public key
+// Right now this is set to Fp434 but it could change.
+func NewSIDHPrivateKey(variant sidh.KeyVariant) *sidh.PrivateKey {
+	return sidh.NewPrivateKey(sidhinterface.KeyId, variant)
+}
+
+// GetSIDHVariant returns the variant opposite the otherVariant
+func GetSIDHVariant(otherVariant sidh.KeyVariant) sidh.KeyVariant {
+	// Note -- this is taken from inside the sidh lib to look for the A flag
+	if (otherVariant & sidh.KeyVariantSidhA) == sidh.KeyVariantSidhA {
+		return sidh.KeyVariantSidhB
+	}
+	return sidh.KeyVariantSidhA
+}
+
+// String interface impl to dump the contents of the public key as b64 string
+func StringSIDHPubKey(k *sidh.PublicKey) string {
+	kBytes := make([]byte, k.Size())
+	k.Export(kBytes)
+	return base64.StdEncoding.EncodeToString(kBytes)
+}
+
+// String interface to dump the contents of the public key as b64 string
+// NOTE: public key, not the private. We don't ever want to drop a
+// private key into a log somewhere.
+func StringSIDHPrivKey(k *sidh.PrivateKey) string {
+	pubK := NewSIDHPublicKey(k.Variant())
+	k.GeneratePublicKey(pubK)
+	return StringSIDHPubKey(pubK)
+}
+
+
+
+////
+// Public Key Storage utility functions
+////
+
+const currentSIDHPubKeyVersion = 0
+
+// StoreSIDHPubKeyA is a helper to store the requestor public key (which is
+// always of type A)
+func StoreSIDHPublicKey(kv *versioned.KV, sidH *sidh.PublicKey, key string) error {
+	now := netTime.Now()
+
+	sidHBytes := make([]byte, sidH.Size()+1)
+	sidHBytes[0] = byte(sidH.Variant())
+	sidH.Export(sidHBytes[1:])
+
+	obj := versioned.Object{
+		Version:   currentSIDHPubKeyVersion,
+		Timestamp: now,
+		Data:      sidHBytes,
+	}
+
+	return kv.Set(key, currentSIDHPubKeyVersion, &obj)
+}
+
+// LoadSIDHPubKeyA loads a public key from storage.
+func LoadSIDHPublicKey(kv *versioned.KV, key string) (*sidh.PublicKey, error) {
+	vo, err := kv.Get(key, currentSIDHPubKeyVersion)
+	if err != nil {
+		return nil, err
+	}
+
+	variant := sidh.KeyVariant(vo.Data[0])
+	sidHPubkey := NewSIDHPublicKey(variant)
+	return sidHPubkey, sidHPubkey.Import(vo.Data[1:])
+}
+
+// DeleteSIDHPubKey removes the key from the store
+func DeleteSIDHPublicKey(kv *versioned.KV, key string) error {
+	return kv.Delete(key, currentSIDHPubKeyVersion)
+}
+
+func makeSIDHPublicKey(cid *id.ID) string {
+	return fmt.Sprintf("SIDHPubKey:%s", cid)
+}
+
+////
+// Private Key Storage utility functions
+////
+
+const currentSIDHPrivKeyVersion = 0
+
+// StoreSIDHPrivateKeyA is a helper to store the requestor public key (which is
+// always of type A)
+func StoreSIDHPrivateKey(kv *versioned.KV, sidH *sidh.PrivateKey, key string) error {
+	now := netTime.Now()
+
+	sidHBytes := make([]byte, sidH.Size()+1)
+	sidHBytes[0] = byte(sidH.Variant())
+	sidH.Export(sidHBytes[1:])
+
+	obj := versioned.Object{
+		Version:   currentSIDHPrivKeyVersion,
+		Timestamp: now,
+		Data:      sidHBytes,
+	}
+
+	return kv.Set(key, currentSIDHPrivKeyVersion, &obj)
+}
+
+// LoadSIDHPrivateKeyA loads a public key from storage.
+func LoadSIDHPrivateKey(kv *versioned.KV, key string) (*sidh.PrivateKey, error) {
+	vo, err := kv.Get(key, currentSIDHPrivKeyVersion)
+	if err != nil {
+		return nil, err
+	}
+
+	variant := sidh.KeyVariant(vo.Data[0])
+	sidHPrivkey := NewSIDHPrivateKey(variant)
+	return sidHPrivkey, sidHPrivkey.Import(vo.Data[1:])
+}
+
+// DeleteSIDHPrivateKey removes the key from the store
+func DeleteSIDHPrivateKey(kv *versioned.KV, key string) error {
+	return kv.Delete(key, currentSIDHPrivKeyVersion)
+}
+
+func makeSIDHPrivateKey(cid *id.ID) string {
+	return fmt.Sprintf("SIDHPrivKey:%s", cid)
+}
diff --git a/storage/utility/sidh_test.go b/storage/utility/sidh_test.go
new file mode 100644
index 000000000..f2245cd86
--- /dev/null
+++ b/storage/utility/sidh_test.go
@@ -0,0 +1,146 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package utility
+
+import (
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/elixxir/ekv"
+	"testing"
+	"github.com/cloudflare/circl/dh/sidh"
+)
+
+// TestStoreLoadDeleteSIDHPublicKey tests the load/store/delete functions
+// for SIDH Public Keys
+func TestStoreLoadDeleteSIDHPublicKey(t *testing.T) {
+	kv := make(ekv.Memstore)
+	vkv := versioned.NewKV(kv)
+	rng := fastRNG.NewStreamGenerator(1, 3, csprng.NewSystemRNG)
+	myRng := rng.GetStream()
+	x1 := NewSIDHPublicKey(sidh.KeyVariantSidhA)
+	p1 := NewSIDHPrivateKey(sidh.KeyVariantSidhA)
+	p1.Generate(myRng)
+	p1.GeneratePublicKey(x1)
+
+	k1 := "testKey1"
+	err := StoreSIDHPublicKey(vkv, x1, k1)
+	if err != nil {
+		t.Errorf("Failed to store key: %+v", err)
+	}
+	loaded1, err := LoadSIDHPublicKey(vkv, k1)
+	if err != nil {
+		t.Errorf("Failed to load key: %+v", err)
+	}
+	if StringSIDHPubKey(x1) != StringSIDHPubKey(loaded1) {
+		t.Errorf("Stored key did not match loaded:\n\t%s\n\t%s\n",
+			StringSIDHPubKey(x1), StringSIDHPubKey(loaded1))
+	}
+	err = DeleteSIDHPublicKey(vkv, k1)
+	if err != nil {
+		t.Fatalf("DeleteSIDHPublicKey returned an error: %v", err)
+	}
+	_, err = LoadSIDHPublicKey(vkv, k1)
+	if err == nil {
+		t.Errorf("Should not load deleted key: %+v", err)
+	}
+
+	// Now do the same for Type B keys
+
+	x2 := NewSIDHPublicKey(sidh.KeyVariantSidhB)
+	p2 := NewSIDHPrivateKey(sidh.KeyVariantSidhB)
+	p2.Generate(myRng)
+	p2.GeneratePublicKey(x2)
+
+	k2 := "testKey2"
+	err = StoreSIDHPublicKey(vkv, x2, k2)
+	if err != nil {
+		t.Errorf("Failed to store key: %+v", err)
+	}
+	loaded2, err := LoadSIDHPublicKey(vkv, k2)
+	if err != nil {
+		t.Errorf("Failed to load key: %+v", err)
+	}
+	if StringSIDHPubKey(x2) != StringSIDHPubKey(loaded2) {
+		t.Errorf("Stored key did not match loaded:\n\t%s\n\t%s\n",
+			StringSIDHPubKey(x2), StringSIDHPubKey(loaded2))
+	}
+	err = DeleteSIDHPublicKey(vkv, k2)
+	if err != nil {
+		t.Fatalf("DeleteSIDHPublicKey returned an error: %v", err)
+	}
+	_, err = LoadSIDHPublicKey(vkv, k2)
+	if err == nil {
+		t.Errorf("Should not load deleted key: %+v", err)
+	}
+
+	myRng.Close()
+}
+
+
+// TestStoreLoadDeleteSIDHPublicKey tests the load/store/delete functions
+// for SIDH Private Keys
+func TestStoreLoadDeleteSIDHPrivateKey(t *testing.T) {
+	kv := make(ekv.Memstore)
+	vkv := versioned.NewKV(kv)
+	rng := fastRNG.NewStreamGenerator(1, 3, csprng.NewSystemRNG)
+	myRng := rng.GetStream()
+	p1 := NewSIDHPrivateKey(sidh.KeyVariantSidhA)
+	p1.Generate(myRng)
+
+	k1 := "testKey1"
+	err := StoreSIDHPrivateKey(vkv, p1, k1)
+	if err != nil {
+		t.Errorf("Failed to store key: %+v", err)
+	}
+	loaded1, err := LoadSIDHPrivateKey(vkv, k1)
+	if err != nil {
+		t.Errorf("Failed to load key: %+v", err)
+	}
+	if StringSIDHPrivKey(p1) != StringSIDHPrivKey(loaded1) {
+		t.Errorf("Stored key did not match loaded:\n\t%s\n\t%s\n",
+			StringSIDHPrivKey(p1), StringSIDHPrivKey(loaded1))
+	}
+	err = DeleteSIDHPrivateKey(vkv, k1)
+	if err != nil {
+		t.Fatalf("DeleteSIDHPrivateKey returned an error: %v", err)
+	}
+	_, err = LoadSIDHPrivateKey(vkv, k1)
+	if err == nil {
+		t.Errorf("Should not load deleted key: %+v", err)
+	}
+
+	// Now do the same for Type B keys
+
+	p2 := NewSIDHPrivateKey(sidh.KeyVariantSidhB)
+	p2.Generate(myRng)
+
+	k2 := "testKey2"
+	err = StoreSIDHPrivateKey(vkv, p2, k2)
+	if err != nil {
+		t.Errorf("Failed to store key: %+v", err)
+	}
+	loaded2, err := LoadSIDHPrivateKey(vkv, k2)
+	if err != nil {
+		t.Errorf("Failed to load key: %+v", err)
+	}
+	if StringSIDHPrivKey(p2) != StringSIDHPrivKey(loaded2) {
+		t.Errorf("Stored key did not match loaded:\n\t%s\n\t%s\n",
+			StringSIDHPrivKey(p2), StringSIDHPrivKey(loaded2))
+	}
+	err = DeleteSIDHPrivateKey(vkv, k2)
+	if err != nil {
+		t.Fatalf("DeleteSIDHPrivateKey returned an error: %v", err)
+	}
+	_, err = LoadSIDHPrivateKey(vkv, k2)
+	if err == nil {
+		t.Errorf("Should not load deleted key: %+v", err)
+	}
+
+	myRng.Close()
+}
-- 
GitLab