From 1d434a4ca852e83ba27dc0a7a72f19f444d2ee67 Mon Sep 17 00:00:00 2001
From: joshemb <josh@elixxir.io>
Date: Tue, 24 Jan 2023 13:11:08 -0800
Subject: [PATCH] Revert "Propagate moving of rsa/cyclic/hash packages"

This reverts commit 9f11137488138301add52508ee7819a90d677868.
---
 authorize/authorize.go                       |    2 +-
 authorize/authorize_test.go                  |    8 +-
 authorize/certRequest.go                     |    4 +-
 authorize/certRequest_test.go                |    2 +-
 backup/backup.go                             |    2 +-
 broadcast/asymmetric.go                      |    2 +-
 broadcast/asymmetric_test.go                 |    2 +-
 broadcast/channel.go                         |    2 +-
 broadcast/channel_test.go                    |    2 +-
 broadcast/exportPrivateKey.go                |    2 +-
 broadcast/intermediary.go                    |    2 +-
 broadcast/intermediary_test.go               |    2 +-
 broadcast/keysize.go                         |    2 +-
 broadcast/keysize_test.go                    |    2 +-
 broadcast/mac.go                             |    2 +-
 broadcast/symmetric_test.go                  |    2 +-
 channel/database.go                          |    2 +-
 channel/request.go                           |    2 +-
 channel/request_test.go                      |    2 +-
 cmix/clientGateway.go                        |    4 +-
 cmix/encryptDecrypt.go                       |    2 +-
 cmix/key.go                                  |    4 +-
 cmix/key_test.go                             |    2 +-
 cmix/kmac.go                                 |    2 +-
 cmix/kmac_test.go                            |   14 +-
 cmix/setGroupBits.go                         |    2 +-
 codename/identity.go                         |    2 +-
 contact/contact.go                           |    2 +-
 contact/contact_test.go                      |    2 +-
 contact/unmarshalVersion.go                  |    2 +-
 cyclic/buffer.go                             |   66 +
 cyclic/buffer_test.go                        |  206 ++
 cyclic/group.go                              |  638 ++++++
 cyclic/group_test.go                         | 2069 ++++++++++++++++++
 cyclic/int.go                                |  262 +++
 cyclic/int_test.go                           |  363 +++
 diffieHellman/dhkx.go                        |    2 +-
 diffieHellman/dhkx_test.go                   |    8 +-
 dm/selfCipher.go                             |    2 +-
 e2e/auth/encryptDecrypt.go                   |    4 +-
 e2e/auth/keygen.go                           |    4 +-
 e2e/auth/mac.go                              |    2 +-
 e2e/auth/negotiationFingerprint.go           |    4 +-
 e2e/auth/negotiationFingerprint_test.go      |    2 +-
 e2e/auth/ownership.go                        |    4 +-
 e2e/auth/ownership_test.go                   |    2 +-
 e2e/auth/requestFP.go                        |    8 +-
 e2e/dummykeygen.go                           |    4 +-
 e2e/dummykeygen_test.go                      |    2 +-
 e2e/encryptionChecker.go                     |    2 +-
 e2e/encryptionChecker_test.go                |    2 +-
 e2e/keys.go                                  |    2 +-
 e2e/keys_test.go                             |    8 +-
 e2e/messageID.go                             |    2 +-
 e2e/relationshipFingerprint.go               |    4 +-
 e2e/relationshipFingerprint_test.go          |    4 +-
 e2e/residue.go                               |    2 +-
 e2e/singleUse/mac.go                         |    2 +-
 e2e/singleUse/mac_test.go                    |    2 +-
 e2e/singleUse/recipientID.go                 |    4 +-
 e2e/singleUse/recipientID_test.go            |    2 +-
 e2e/singleUse/requestFingerprint.go          |    4 +-
 e2e/singleUse/requestFingerprint_test.go     |    2 +-
 e2e/singleUse/requestKey.go                  |    4 +-
 e2e/singleUse/requestKey_test.go             |    2 +-
 e2e/singleUse/requestPartFingerprint.go      |    4 +-
 e2e/singleUse/requestPartFingerprint_test.go |    2 +-
 e2e/singleUse/requestPartKey.go              |    4 +-
 e2e/singleUse/requestPartKey_test.go         |    2 +-
 e2e/singleUse/responseFingerprint.go         |    4 +-
 e2e/singleUse/responseFingerprint_test.go    |    2 +-
 e2e/singleUse/responseKey.go                 |    4 +-
 e2e/singleUse/responseKey_test.go            |    2 +-
 e2e/singleUse/tagFingerprint.go              |    2 +-
 e2e/ttl.go                                   |    2 +-
 fileTransfer/fingerprint.go                  |    2 +-
 fileTransfer/keyGen.go                       |    2 +-
 fileTransfer/mac.go                          |    2 +-
 go.mod                                       |    2 +-
 go.sum                                       |    2 -
 group/mac.go                                 |    4 +-
 group/membership.go                          |    2 +-
 group/membership_test.go                     |    2 +-
 hash/hash.go                                 |   65 +
 hash/hash_test.go                            |   64 +
 hash/keys.go                                 |   43 +
 hash/keys_test.go                            |   81 +
 message/id.go                                |    2 +-
 nike/dh/dh.go                                |    2 +-
 registration/hmac_test.go                    |    2 +-
 registration/keygen.go                       |    2 +-
 registration/keygen_test.go                  |    4 +-
 92 files changed, 3975 insertions(+), 120 deletions(-)
 create mode 100644 cyclic/buffer.go
 create mode 100644 cyclic/buffer_test.go
 create mode 100644 cyclic/group.go
 create mode 100644 cyclic/group_test.go
 create mode 100644 cyclic/int.go
 create mode 100644 cyclic/int_test.go
 create mode 100644 hash/hash.go
 create mode 100644 hash/hash_test.go
 create mode 100644 hash/keys.go
 create mode 100644 hash/keys_test.go

diff --git a/authorize/authorize.go b/authorize/authorize.go
index a196344a..e8901755 100644
--- a/authorize/authorize.go
+++ b/authorize/authorize.go
@@ -13,7 +13,7 @@ package authorize
 import (
 	"encoding/binary"
 	"github.com/pkg/errors"
-	"gitlab.com/xx_network/crypto/rsa"
+	"gitlab.com/elixxir/crypto/rsa"
 	oldRsa "gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/crypto/xx"
 	"gitlab.com/xx_network/primitives/id"
diff --git a/authorize/authorize_test.go b/authorize/authorize_test.go
index eeb99204..3d89f2dd 100644
--- a/authorize/authorize_test.go
+++ b/authorize/authorize_test.go
@@ -11,7 +11,7 @@ import (
 	"bytes"
 	"crypto/rand"
 	"fmt"
-	"gitlab.com/xx_network/crypto/rsa"
+	"gitlab.com/elixxir/crypto/rsa"
 	"gitlab.com/xx_network/crypto/xx"
 	"gitlab.com/xx_network/primitives/id"
 	"strconv"
@@ -70,7 +70,7 @@ func TestSignVerify_Consistency(t *testing.T) {
 	}
 
 	// Sign data
-	sig, err := Sign(notRand, testTime, serverPrivKey.GetOldRSA())
+	sig, err := Sign(notRand, testTime, serverPrivKey)
 	if err != nil {
 		t.Fatalf("SignVerify error: "+
 			"Could not sign data: %v", err.Error())
@@ -151,7 +151,7 @@ func TestSignVerify(t *testing.T) {
 			"Could not generate key: %v", err.Error())
 	}
 
-	sig, err := Sign(rand.Reader, testTime, serverPrivKey.GetOldRSA())
+	sig, err := Sign(rand.Reader, testTime, serverPrivKey)
 	if err != nil {
 		t.Fatalf("SignVerify error: "+
 			"Could not sign data: %v", err.Error())
@@ -193,7 +193,7 @@ func TestVerify_Error(t *testing.T) {
 	// use insecure seeded rng to reproduce key
 	notRand := &CountingReader{count: uint8(0)}
 
-	sig, err := Sign(notRand, signedTime, serverPrivKey.GetOldRSA())
+	sig, err := Sign(notRand, signedTime, serverPrivKey)
 	if err != nil {
 		t.Fatalf("SignVerify error: "+
 			"Could not sign data: %v", err.Error())
diff --git a/authorize/certRequest.go b/authorize/certRequest.go
index 84cb9586..630ffa52 100644
--- a/authorize/certRequest.go
+++ b/authorize/certRequest.go
@@ -9,8 +9,8 @@ package authorize
 
 import (
 	"encoding/binary"
-	"gitlab.com/xx_network/crypto/hash"
-	"gitlab.com/xx_network/crypto/rsa"
+	"gitlab.com/elixxir/crypto/hash"
+	"gitlab.com/elixxir/crypto/rsa"
 	"io"
 	"time"
 )
diff --git a/authorize/certRequest_test.go b/authorize/certRequest_test.go
index b4ddba25..ea40daa3 100644
--- a/authorize/certRequest_test.go
+++ b/authorize/certRequest_test.go
@@ -2,8 +2,8 @@ package authorize
 
 import (
 	"bytes"
+	"gitlab.com/elixxir/crypto/rsa"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/rsa"
 	"testing"
 	"time"
 )
diff --git a/backup/backup.go b/backup/backup.go
index 95f8cf88..d4d98642 100644
--- a/backup/backup.go
+++ b/backup/backup.go
@@ -13,9 +13,9 @@ import (
 	"encoding/json"
 
 	"github.com/pkg/errors"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
 )
diff --git a/broadcast/asymmetric.go b/broadcast/asymmetric.go
index b4297af6..3a3ad300 100644
--- a/broadcast/asymmetric.go
+++ b/broadcast/asymmetric.go
@@ -11,9 +11,9 @@ import (
 	"bytes"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/rsa"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/rsa"
 )
 
 // IsPublicKey returns true if the passed public key is the public key for the
diff --git a/broadcast/asymmetric_test.go b/broadcast/asymmetric_test.go
index d3ba6a91..07c18c03 100644
--- a/broadcast/asymmetric_test.go
+++ b/broadcast/asymmetric_test.go
@@ -10,8 +10,8 @@ package broadcast
 import (
 	"bytes"
 	"gitlab.com/elixxir/crypto/cmix"
+	"gitlab.com/elixxir/crypto/rsa"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/rsa"
 	"gitlab.com/xx_network/primitives/netTime"
 	"testing"
 )
diff --git a/broadcast/channel.go b/broadcast/channel.go
index cb6fd948..2dd2bc8e 100644
--- a/broadcast/channel.go
+++ b/broadcast/channel.go
@@ -28,7 +28,7 @@ import (
 
 	"gitlab.com/elixxir/crypto/broadcast/escape"
 	"gitlab.com/elixxir/crypto/cmix"
-	"gitlab.com/xx_network/crypto/rsa"
+	"gitlab.com/elixxir/crypto/rsa"
 )
 
 const (
diff --git a/broadcast/channel_test.go b/broadcast/channel_test.go
index 29cfda4a..bdadc78e 100644
--- a/broadcast/channel_test.go
+++ b/broadcast/channel_test.go
@@ -11,8 +11,8 @@ import (
 	"bytes"
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/crypto/cmix"
+	"gitlab.com/elixxir/crypto/rsa"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/rsa"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
 	"reflect"
diff --git a/broadcast/exportPrivateKey.go b/broadcast/exportPrivateKey.go
index 29dbbf5a..531f52f2 100644
--- a/broadcast/exportPrivateKey.go
+++ b/broadcast/exportPrivateKey.go
@@ -14,7 +14,7 @@ import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/crypto/backup"
-	"gitlab.com/xx_network/crypto/rsa"
+	"gitlab.com/elixxir/crypto/rsa"
 	"gitlab.com/xx_network/primitives/id"
 	"golang.org/x/crypto/argon2"
 	"golang.org/x/crypto/blake2b"
diff --git a/broadcast/intermediary.go b/broadcast/intermediary.go
index 17539ec6..9f8583f6 100644
--- a/broadcast/intermediary.go
+++ b/broadcast/intermediary.go
@@ -3,7 +3,7 @@ package broadcast
 import (
 	"encoding/binary"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/xx_network/crypto/rsa"
+	"gitlab.com/elixxir/crypto/rsa"
 	"hash"
 	"time"
 )
diff --git a/broadcast/intermediary_test.go b/broadcast/intermediary_test.go
index 09107bd5..2b058d82 100644
--- a/broadcast/intermediary_test.go
+++ b/broadcast/intermediary_test.go
@@ -3,7 +3,7 @@ package broadcast
 import (
 	"bytes"
 	"encoding/hex"
-	"gitlab.com/xx_network/crypto/rsa"
+	"gitlab.com/elixxir/crypto/rsa"
 	"gitlab.com/xx_network/primitives/netTime"
 	"hash"
 	"io"
diff --git a/broadcast/keysize.go b/broadcast/keysize.go
index 0251fe70..4bdf50da 100644
--- a/broadcast/keysize.go
+++ b/broadcast/keysize.go
@@ -2,7 +2,7 @@ package broadcast
 
 import (
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/xx_network/crypto/rsa"
+	"gitlab.com/elixxir/crypto/rsa"
 )
 
 // calculateKeySize finds the optimal key size and number of sub-packets smaller
diff --git a/broadcast/keysize_test.go b/broadcast/keysize_test.go
index 88304c26..d20b9cec 100644
--- a/broadcast/keysize_test.go
+++ b/broadcast/keysize_test.go
@@ -1,7 +1,7 @@
 package broadcast
 
 import (
-	"gitlab.com/xx_network/crypto/rsa"
+	"gitlab.com/elixxir/crypto/rsa"
 	"testing"
 )
 
diff --git a/broadcast/mac.go b/broadcast/mac.go
index d0c2dafe..a071a90e 100644
--- a/broadcast/mac.go
+++ b/broadcast/mac.go
@@ -10,7 +10,7 @@ package broadcast
 import (
 	"crypto/hmac"
 
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/hash"
 )
 
 // makeMAC returns the MAC for the given payload. It is an HMAC with proper H
diff --git a/broadcast/symmetric_test.go b/broadcast/symmetric_test.go
index 93c040b5..0022f175 100644
--- a/broadcast/symmetric_test.go
+++ b/broadcast/symmetric_test.go
@@ -11,7 +11,7 @@ import (
 	"bytes"
 	"encoding/base64"
 	"gitlab.com/elixxir/crypto/cmix"
-	"gitlab.com/xx_network/crypto/rsa"
+	"gitlab.com/elixxir/crypto/rsa"
 	oldRsa "gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
diff --git a/channel/database.go b/channel/database.go
index f47b5dbf..697029be 100644
--- a/channel/database.go
+++ b/channel/database.go
@@ -12,7 +12,7 @@ import (
 	"encoding/json"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/hash"
 	"io"
 )
 
diff --git a/channel/request.go b/channel/request.go
index b3b9319f..13b0474c 100644
--- a/channel/request.go
+++ b/channel/request.go
@@ -8,7 +8,7 @@ import (
 	"io"
 	"time"
 
-	"gitlab.com/xx_network/crypto/rsa"
+	"gitlab.com/elixxir/crypto/rsa"
 )
 
 var (
diff --git a/channel/request_test.go b/channel/request_test.go
index b3fe8047..e03c684b 100644
--- a/channel/request_test.go
+++ b/channel/request_test.go
@@ -2,8 +2,8 @@ package channel
 
 import (
 	"crypto/ed25519"
+	"gitlab.com/elixxir/crypto/rsa"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/rsa"
 	"testing"
 	"time"
 )
diff --git a/cmix/clientGateway.go b/cmix/clientGateway.go
index a923b8ba..22514b70 100644
--- a/cmix/clientGateway.go
+++ b/cmix/clientGateway.go
@@ -17,8 +17,8 @@ package cmix
 
 import (
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 )
 
 // GenerateClientGatewayKey hashes the symmetric key between client and the node
diff --git a/cmix/encryptDecrypt.go b/cmix/encryptDecrypt.go
index 466cb358..fbf4e2f9 100644
--- a/cmix/encryptDecrypt.go
+++ b/cmix/encryptDecrypt.go
@@ -17,8 +17,8 @@ package cmix
 
 import (
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"gitlab.com/xx_network/primitives/id"
 	"golang.org/x/crypto/blake2b"
 )
diff --git a/cmix/key.go b/cmix/key.go
index c0375680..fac18a25 100644
--- a/cmix/key.go
+++ b/cmix/key.go
@@ -13,8 +13,8 @@ package cmix
 import (
 	"crypto/sha256"
 	"encoding/binary"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/xx_network/primitives/id"
 	goHash "hash"
 )
diff --git a/cmix/key_test.go b/cmix/key_test.go
index fb67b65d..e1dda9de 100644
--- a/cmix/key_test.go
+++ b/cmix/key_test.go
@@ -8,7 +8,7 @@
 package cmix
 
 import (
-	"gitlab.com/xx_network/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/primitives/id"
 	"testing"
diff --git a/cmix/kmac.go b/cmix/kmac.go
index bd8c33fb..3cbb9347 100644
--- a/cmix/kmac.go
+++ b/cmix/kmac.go
@@ -14,7 +14,7 @@ import (
 	"encoding/binary"
 	"hash"
 
-	"gitlab.com/xx_network/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/primitives/id"
 )
 
diff --git a/cmix/kmac_test.go b/cmix/kmac_test.go
index 2b18412d..d142fb5a 100644
--- a/cmix/kmac_test.go
+++ b/cmix/kmac_test.go
@@ -8,9 +8,9 @@
 package cmix
 
 import (
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
 	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/primitives/id"
 	"math/rand"
@@ -18,7 +18,7 @@ import (
 	"testing"
 )
 
-// Tests that the kmac function outputs wha
+//Tests that the kmac function outputs wha
 func TestGenerateKMAC_Consistency(t *testing.T) {
 
 	grp := grpTest()
@@ -56,7 +56,7 @@ func TestGenerateKMAC_Consistency(t *testing.T) {
 	}
 }
 
-// Tests that the kmac function outputs wha
+//Tests that the kmac function outputs wha
 func TestGenerateKMACs_Consistency(t *testing.T) {
 
 	grp := grpTest()
@@ -101,7 +101,7 @@ func TestGenerateKMACs_Consistency(t *testing.T) {
 	}
 }
 
-// Happy path
+//Happy path
 func TestVerifyKMAC(t *testing.T) {
 	grp := grpTest()
 
@@ -137,7 +137,7 @@ func TestVerifyKMAC(t *testing.T) {
 	}
 }
 
-// Error path
+//Error path
 func TestVerifyKMAC_WrongExpectedKmac(t *testing.T) {
 
 	grp := grpTest()
@@ -172,7 +172,7 @@ func TestVerifyKMAC_WrongExpectedKmac(t *testing.T) {
 
 }
 
-// Error path
+//Error path
 func TestVerifyKACY_Mismatch(t *testing.T) {
 	grp := grpTest()
 
diff --git a/cmix/setGroupBits.go b/cmix/setGroupBits.go
index 23b77d2d..c15a1777 100644
--- a/cmix/setGroupBits.go
+++ b/cmix/setGroupBits.go
@@ -9,9 +9,9 @@ package cmix
 
 import (
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/cyclic"
 )
 
 // SetGroupBits takes a message and a cyclic group and randomly sets
diff --git a/codename/identity.go b/codename/identity.go
index 37fd7d6d..b41d5b90 100644
--- a/codename/identity.go
+++ b/codename/identity.go
@@ -15,7 +15,7 @@ import (
 
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/hash"
 	"golang.org/x/crypto/blake2b"
 )
 
diff --git a/contact/contact.go b/contact/contact.go
index f526da5f..4f08eee3 100644
--- a/contact/contact.go
+++ b/contact/contact.go
@@ -17,8 +17,8 @@ import (
 
 	"github.com/pkg/errors"
 	"github.com/skip2/go-qrcode"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/primitives/fact"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"gitlab.com/xx_network/primitives/id"
 	"golang.org/x/crypto/blake2b"
 )
diff --git a/contact/contact_test.go b/contact/contact_test.go
index 253e51bc..a8db2b9b 100644
--- a/contact/contact_test.go
+++ b/contact/contact_test.go
@@ -20,9 +20,9 @@ import (
 
 	"github.com/liyue201/goqr"
 	"github.com/skip2/go-qrcode"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/primitives/id"
 )
diff --git a/contact/unmarshalVersion.go b/contact/unmarshalVersion.go
index 003c9672..756d1d9b 100644
--- a/contact/unmarshalVersion.go
+++ b/contact/unmarshalVersion.go
@@ -18,8 +18,8 @@ import (
 	"encoding/binary"
 
 	"github.com/pkg/errors"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/primitives/fact"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"gitlab.com/xx_network/primitives/id"
 )
 
diff --git a/cyclic/buffer.go b/cyclic/buffer.go
new file mode 100644
index 00000000..bf742089
--- /dev/null
+++ b/cyclic/buffer.go
@@ -0,0 +1,66 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+// Package cyclic wraps our large.Int structure.  It is designed to be used in
+// conjunction with the cyclic.Group object. The cyclic.Group object
+// will provide implementations of various modular operations within the group.
+// A cyclic.IntBuffer type will be created to store large batches of groups.
+package cyclic
+
+import (
+	"gitlab.com/xx_network/crypto/large"
+)
+
+// Store the same group fingerprint for multiple values
+type IntBuffer struct {
+	values      []large.Int
+	fingerprint uint64
+}
+
+// Get gets the cyclic int at a specific index in the int buffer
+func (ib *IntBuffer) Get(index uint32) *Int {
+	return &Int{&ib.values[index], ib.fingerprint}
+}
+
+// GetSubBuffer get an intBuffer representing a specific region in the int buffer
+func (ib *IntBuffer) GetSubBuffer(begin, end uint32) *IntBuffer {
+	return &IntBuffer{
+		values:      ib.values[begin:end],
+		fingerprint: ib.fingerprint}
+}
+
+// DeepCopy gets a deep copy of an intBuffer
+func (ib *IntBuffer) DeepCopy() *IntBuffer {
+	newBuffer := IntBuffer{make([]large.Int, len(ib.values)), ib.fingerprint}
+	for i := range newBuffer.values {
+		(&newBuffer.values[i]).Set(&ib.values[i])
+	}
+	return &newBuffer
+}
+
+// Len gets the length of the int buffer
+func (ib *IntBuffer) Len() int {
+	return len(ib.values)
+}
+
+// GetFingerprint gets the int buffer's group fingerprint
+func (ib *IntBuffer) GetFingerprint() uint64 {
+	return ib.fingerprint
+}
+
+// Contains checks that the index is within the amount of the values slice
+func (ib *IntBuffer) Contains(index uint32) bool {
+	return index < uint32(len(ib.values))
+}
+
+// Erase overwrites all underlying data from an IntBuffer by setting its values
+// slice to nil and its fingerprint to zero. All underlying released data will
+// be removed by the garbage collector.
+func (ib *IntBuffer) Erase() {
+	ib.values = nil
+	ib.fingerprint = 0
+}
diff --git a/cyclic/buffer_test.go b/cyclic/buffer_test.go
new file mode 100644
index 00000000..5b966dfd
--- /dev/null
+++ b/cyclic/buffer_test.go
@@ -0,0 +1,206 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+package cyclic
+
+import (
+	"gitlab.com/xx_network/crypto/large"
+	"testing"
+)
+
+//Tests that getting and interacting with the intbuffer is correct
+func TestIntBuffer_Get(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	buf := grp.NewIntBuffer(5, nil)
+
+	// Set an int
+	grp.SetUint64(buf.Get(2), 322)
+
+	// Ensure that overwriting a large int in the buffer doesn't overwrite any of
+	// the things it shouldn't overwrite
+	shouldStillBePSub1 := buf.Get(0)
+	if shouldStillBePSub1.Cmp(grp.NewInt(1000000010101111110)) != 0 {
+		t.Error("Setting the buffer element also set another element of the" +
+			" buffer (probably aliased)")
+	}
+	shouldAlsoStillBePSub1 := grp.GetPSub1()
+	if shouldAlsoStillBePSub1.value.Cmp(large.NewInt(1000000010101111110)) != 0 {
+		t.Error("Setting the buffer element also set PSub1 (probably aliased)")
+	}
+
+	// Ensure that when you get an int that you've set,
+	// it has the value that you set it to
+	shouldBe322 := buf.Get(2)
+	if shouldBe322.Cmp(grp.NewInt(322)) != 0 {
+		t.Error("The buffer item that should have been set to 322 wasn't")
+	}
+}
+
+//Tests that len works correctly
+func TestIntBuffer_Len(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	for i := 0; i < 1000; i++ {
+		ib := grp.NewIntBuffer(uint32(i), nil)
+		if ib.Len() != i {
+			t.Errorf("IntBuffer.Len: returned incorrect len, Expected: %v, Received: %v", i, ib.Len())
+		}
+	}
+}
+
+//Tests that GetFingerprint returns the correct fingerprint
+func TestIntBuffer_GetFingerprint(t *testing.T) {
+	p1 := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp1 := NewGroup(p1, g)
+
+	ib1 := grp1.NewIntBuffer(5, nil)
+
+	if ib1.GetFingerprint() != grp1.GetFingerprint() {
+		t.Errorf("IntBuffer.GetFingerprint: returned incorrect fingerprint,"+
+			"Expected: %v, Received: %v", grp1.GetFingerprint(), ib1.fingerprint)
+	}
+
+	p2 := large.NewInt(1000000010101111011)
+	grp2 := NewGroup(p2, g)
+
+	ib2 := grp2.NewIntBuffer(5, nil)
+
+	if ib2.GetFingerprint() != grp2.GetFingerprint() {
+		t.Errorf("IntBuffer.GetFingerprint: returned incorrect fingerprint,"+
+			"Expected: %v, Received: %v", grp2.GetFingerprint(), ib2.fingerprint)
+	}
+
+}
+
+//Tests that getting a region in the intbuffer works correctly
+func TestIntBuffer_GetRegion(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	intBuffLen := uint32(20)
+
+	buf := grp.NewIntBuffer(intBuffLen, nil)
+
+	// Set all ints
+	for i := uint32(0); i < intBuffLen; i++ {
+		grp.SetUint64(buf.Get(i), uint64(i))
+	}
+
+	begin := uint32(3)
+	end := uint32(17)
+
+	//Get a region of the int buffer
+	bufSub := buf.GetSubBuffer(begin, end)
+
+	//check that the length is correct
+	if bufSub.Len() != int(end-begin) {
+		t.Errorf("IntBuffer.GetSubBuffer: Size of region of incorrect,"+
+			"Expected: %v, Received: %v", end-begin, bufSub.Len())
+	}
+
+	for i := begin; i < end; i++ {
+		//check that the copy is exact
+		bufint := bufSub.Get(i - begin)
+		if bufint.GetLargeInt().Int64() != int64(i) {
+			t.Errorf("IntBuffer.GetSubBuffer: Region mapped incorrectly,"+
+				"Expected: %v, Received: %v", i, bufint.GetLargeInt().Int64())
+		}
+		//check that when editing one, the other is edited
+		grp.SetUint64(bufint, uint64(100-i))
+		if buf.Get(i).GetLargeInt().Int64() != int64(100-i) {
+			t.Errorf("IntBuffer.GetSubBuffer: Region not connected to originator,"+
+				"Expected: %v, Received: %v", 100-i, buf.Get(i).GetLargeInt().Int64())
+		}
+	}
+}
+
+//Tests that deep copy of an int buffer copies correctly
+func TestIntBuffer_DeepCopy(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	intBuffLen := uint32(20)
+
+	buf := grp.NewIntBuffer(intBuffLen, nil)
+
+	// Set all ints
+	for i := uint32(0); i < intBuffLen; i++ {
+		grp.SetUint64(buf.Get(i), uint64(i))
+	}
+
+	//Get a deep copy of the int buffer
+	bufCpy := buf.DeepCopy()
+
+	if bufCpy.Len() != buf.Len() {
+		t.Errorf("IntBuffer.DeepCopy: Size of region of incorrect,"+
+			"Expected: %v, Received: %v", buf.Len(), bufCpy.Len())
+	}
+
+	for i := uint32(0); i < intBuffLen; i++ {
+		//check that the copy is the same as the original
+		bufint := bufCpy.Get(i)
+		if bufint.GetLargeInt().Int64() != int64(i) {
+			t.Errorf("IntBuffer.DeepCopy: Copy not equal to original at %v,"+
+				"Expected: %v, Received: %v", i, i, bufint.GetLargeInt().Int64())
+		}
+		//check that editing one does not edit the other
+		grp.SetUint64(bufint, uint64(100-i))
+		if buf.Get(i).GetLargeInt().Int64() == int64(100-i) {
+			t.Errorf("IntBuffer.DeepCopy: Region connected to originator,"+
+				"Expected: %v, Received: %v", 100-i, buf.Get(i).GetLargeInt().Int64())
+		}
+	}
+}
+
+func TestIntBuffer_Contains(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	b := grp.NewIntBuffer(15, nil)
+
+	for i := 0; i < b.Len(); i++ {
+		if !b.Contains(uint32(i)) {
+			t.Errorf("IntBuffer.Contains: Does not contain index %v when it does", i)
+		}
+	}
+
+	if b.Contains(uint32(b.Len())) {
+		t.Errorf("IntBuffer.Contains: Contains index %v when it doesnt", b.Len())
+	}
+
+	if b.Contains(uint32(b.Len() + 1)) {
+		t.Errorf("IntBuffer.Contains: Contains index %v when it doesnt", b.Len()+1)
+	}
+}
+
+// Tests that Erase() removes all underlying data from the IntBuffer.
+func TestIntBuffer_Erase(t *testing.T) {
+	ib := grp.NewIntBuffer(uint32(20), nil)
+
+	ib.Erase()
+
+	if ib.values != nil {
+		t.Errorf("Erase() did not properly delete the IntBuffer's "+
+			"underlying value\n\treceived: %v\n\texpected: %v",
+			ib.values, nil)
+	}
+
+	if ib.fingerprint != 0 {
+		t.Errorf("Erase() did not properly delete the IntBuffer's "+
+			"underlying fingerprint\n\treceived: %v\n\texpected: %v",
+			ib.fingerprint, 0)
+	}
+}
diff --git a/cyclic/group.go b/cyclic/group.go
new file mode 100644
index 00000000..4568b59c
--- /dev/null
+++ b/cyclic/group.go
@@ -0,0 +1,638 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+// Package cyclic wraps our large.Int structure.  It is designed to be used in
+// conjunction with the cyclic.Group object. The cyclic.Group object
+// will provide implementations of various modular operations within the group.
+// A cyclic.IntBuffer type will be created to store large batches of groups.
+package cyclic
+
+import (
+	"bytes"
+	"crypto/sha256"
+	"encoding/base64"
+	"encoding/binary"
+	"encoding/gob"
+	"encoding/json"
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/crypto/large"
+)
+
+// Groups provide cyclic int operations that keep the return values confined to
+// a finite field under modulo p
+type Group struct {
+	psub1       *large.Int
+	psub2       *large.Int
+	psub3       *large.Int
+	prime       *large.Int
+	psub1factor *large.Int
+	zero        *large.Int
+	one         *large.Int
+	two         *large.Int
+	gen         *large.Int
+	rng         csprng.Source
+	random      []byte
+	fingerprint uint64
+	primeBytes  []byte
+}
+
+const GroupFingerprintSize = 8
+
+// NewGroup returns a group with the given prime and generator
+func NewGroup(p, g *large.Int) *Group {
+	h := sha256.New()
+	h.Write(p.Bytes())
+	h.Write(g.Bytes())
+	hashVal := h.Sum(nil)[:GroupFingerprintSize]
+	value := large.NewIntFromBytes(hashVal)
+	return &Group{
+		prime:       p,
+		psub1:       large.NewInt(1).Sub(p, large.NewInt(1)),
+		psub2:       large.NewInt(1).Sub(p, large.NewInt(2)),
+		psub3:       large.NewInt(1).Sub(p, large.NewInt(3)),
+		psub1factor: large.NewInt(1).RightShift(large.NewInt(1).Sub(p, large.NewInt(1)), 1),
+
+		zero:        large.NewInt(0),
+		one:         large.NewInt(1),
+		two:         large.NewInt(2),
+		gen:         g,
+		rng:         csprng.NewSystemRNG(),
+		random:      make([]byte, (p.BitLen()+7)/8),
+		fingerprint: value.Uint64(),
+		primeBytes:  p.Bytes(),
+	}
+}
+
+// -------------- Constructors -------------- //
+
+// NewIntBuffer is a constructor for IntBuffer
+// if defaultValue is nil, it is set to the max value possible in the group, p-1
+func (g *Group) NewIntBuffer(length uint32, defaultValue *Int) *IntBuffer {
+	var defaultValueLarge *large.Int
+
+	if defaultValue == nil {
+		defaultValueLarge = g.psub1.DeepCopy()
+	} else {
+		g.checkInts(defaultValue)
+		defaultValueLarge = defaultValue.value.DeepCopy()
+	}
+
+	newBuffer := IntBuffer{make([]large.Int, length), g.fingerprint}
+	for i := range newBuffer.values {
+		(&newBuffer.values[i]).Set(defaultValueLarge)
+	}
+	return &newBuffer
+}
+
+// NewInt creates a new cyclicInt in the group from an int64 value
+func (g *Group) NewInt(x int64) *Int {
+	val := large.NewInt(x)
+	n := &Int{value: val, fingerprint: g.fingerprint}
+	if !g.Inside(n.value) {
+		jww.FATAL.Panic("NewInt: Attempted creation of cyclic outside of group")
+	}
+	return n
+}
+
+// NewIntFromLargeInt creates a new cyclicInt in the group from a large.Int value
+func (g *Group) NewIntFromLargeInt(x *large.Int) *Int {
+	n := &Int{value: x, fingerprint: g.fingerprint}
+	if !g.Inside(n.value) {
+		jww.FATAL.Panic("NewIntFromLargeInt: Attempted creation of cyclic outside of group")
+	}
+	return n
+}
+
+// NewIntFromBytes creates a new cyclicInt in the group from a byte buffer
+func (g *Group) NewIntFromBytes(buf []byte) *Int {
+	val := large.NewIntFromBytes(buf)
+	n := &Int{value: val, fingerprint: g.fingerprint}
+	if !g.Inside(n.value) {
+		jww.FATAL.Panic("NewIntFromBytes: Attempted creation of cyclic outside of group")
+	}
+	return n
+}
+
+// NewIntFromString creates a new cyclicInt in the group from a string using the passed base
+// returns nil if string cannot be parsed
+func (g *Group) NewIntFromString(str string, base int) *Int {
+	val := large.NewIntFromString(str, base)
+	if val == nil {
+		return nil
+	}
+	n := &Int{value: val, fingerprint: g.fingerprint}
+	if !g.Inside(n.value) {
+		jww.FATAL.Panic("NewIntFromString: Attempted creation of cyclic outside of group")
+	}
+	return n
+}
+
+// NewMaxInt creates a new cyclicInt in the group at the max group value
+func (g *Group) NewMaxInt() *Int {
+	n := &Int{value: g.psub1, fingerprint: g.fingerprint}
+	return n.DeepCopy()
+}
+
+// NewIntFromUInt creates a new cyclicInt in the group from an uint64 value
+func (g *Group) NewIntFromUInt(i uint64) *Int {
+	val := large.NewIntFromUInt(i)
+	n := &Int{value: val, fingerprint: g.fingerprint}
+	if !g.Inside(n.value) {
+		jww.FATAL.Panic("NewIntFromUInt: Attempted creation of cyclic outside of group")
+	}
+	return n
+}
+
+// NewIntFromBits creates a new cyclic int from a words array
+// This method doesn't copy the bits array, so if you need a copy, copy the array before passing it in
+func (g *Group) NewIntFromBits(b large.Bits) *Int {
+	val := large.NewIntFromBits(b)
+	n := &Int{
+		value:       val,
+		fingerprint: g.fingerprint,
+	}
+	if !g.Inside(n.value) {
+		jww.FATAL.Panic("NewIntFromBits: Attempted creation of cyclic outside of group")
+	}
+	return n
+}
+
+// Check if all cyclic Ints belong to the group and panic otherwise
+func (g *Group) checkInts(ints ...*Int) {
+	for _, i := range ints {
+		if i.GetGroupFingerprint() != g.fingerprint {
+			// The error is created separately to ensure that the stack trace is
+			// printed on panic
+			err := errors.Errorf("cyclicInt being used in wrong group! "+
+				"Group fingerprint is %d and cyclicInt has %d",
+				g.fingerprint, i.GetGroupFingerprint())
+			jww.FATAL.Panicf("%+v", err)
+		}
+	}
+}
+
+// GetFingerprint gets the group's fingerprint
+func (g *Group) GetFingerprint() uint64 {
+	return g.fingerprint
+}
+
+func (g *Group) GetFingerprintText() string {
+	buf := make([]byte, 8)
+	binary.BigEndian.PutUint64(buf, g.fingerprint)
+	fullText := base64.StdEncoding.EncodeToString(buf)
+	return fullText[:8] + "..."
+}
+
+// -------------- Setters -------------- //
+
+// Set sets x to y in the group and returns x
+func (g *Group) Set(x, y *Int) *Int {
+	g.checkInts(x, y)
+	x.value.Set(y.value)
+	return x
+}
+
+// SetLargeInt sets x's value to y s.t. y is inside the group
+func (g *Group) SetLargeInt(x *Int, y *large.Int) *Int {
+	success := g.Inside(y)
+
+	if !success {
+		return nil
+	}
+
+	x.value.Set(y)
+
+	return x
+}
+
+// SetBits sets x in the group to bits and returns x
+// This method does not copy. If you need to set the number to a copy, please copy the bits outside of this.
+func (g *Group) SetBits(x *Int, b large.Bits) *Int {
+	x.value.SetBits(b)
+	g.checkInts(x)
+	return x
+}
+
+// OverwriteBits copies b over x. If there isn't enough memory
+// available in x already, it allocates a new slice with enough memory
+// Under no circumstance will b be the backing memory of the returned Int
+// This is important for our usage of CGBN, which constantly overwrites the output memory
+func (g *Group) OverwriteBits(x *Int, b large.Bits) *Int {
+	bits := x.Bits()
+	if cap(bits) >= len(b) {
+		// Existing int is big enough; copying over existing bits is OK
+		bits = bits[:cap(bits)]
+		copy(bits, b)
+		x.value.SetBits(bits[:len(b)])
+	} else {
+		// A new slice is needed, since the existing int isn't big enough
+		newBits := make(large.Bits, len(b))
+		copy(newBits, b)
+		x.value.SetBits(newBits)
+	}
+	g.checkInts(x)
+	return x
+}
+
+// SetBytes sets x in the group to bytes and returns x
+func (g *Group) SetBytes(x *Int, buf []byte) *Int {
+	x.value.SetBytes(buf)
+	g.checkInts(x)
+	return x
+}
+
+// SetString sets x in the group to string and returns x
+// or nil if error parsing the string
+func (g *Group) SetString(x *Int, s string, base int) *Int {
+	g.checkInts(x)
+	_, ret := x.value.SetString(s, base)
+	if ret == false {
+		return nil
+	}
+	return x
+}
+
+// SetMaxInt sets x in the group to Max4KInt value and returns x
+func (g *Group) SetMaxInt(x *Int) *Int {
+	g.checkInts(x)
+	x.value.Set(g.psub1)
+	return x
+}
+
+// SetUint64 sets x in the group to uint64 value and returns x
+func (g *Group) SetUint64(x *Int, u uint64) *Int {
+	g.checkInts(x)
+	x.value.SetUint64(u)
+	return x
+}
+
+// Mul multiplies a and b within the group, putting the result in c
+// and returning c
+func (g *Group) Mul(a, b, c *Int) *Int {
+	g.checkInts(a, b, c)
+	c.value.Mod(c.value.Mul(a.value, b.value), g.prime)
+	return c
+}
+
+// Inside returns true of the Int is within the group, false if it isn't
+func (g *Group) Inside(a *large.Int) bool {
+	return a.Cmp(g.zero) == 1 && a.Cmp(g.prime) == -1
+}
+
+// bytesInside returns true of the all the Ints represented by the byte slices
+// are within the group, false if it isn't
+func (g *Group) BytesInside(buffers ...[]byte) bool {
+	inside := true
+
+	for _, buf := range buffers {
+		inside = inside && g.singleBytesInside(buf)
+	}
+
+	return inside
+}
+
+// BytesInside returns true of the Int represented by the byte slice is within the group, false if it isn't
+func (g *Group) singleBytesInside(buf []byte) bool {
+	return csprng.InGroup(buf, g.primeBytes)
+}
+
+// ModP sets z ≡ x mod prime within the group and returns z.
+func (g Group) ModP(x *large.Int, z *Int) *Int {
+	g.checkInts(z)
+	z.value.Mod(x, g.prime)
+	return z
+}
+
+// Inverse sets b equal to the inverse of a within the group and returns b
+func (g *Group) Inverse(a, b *Int) *Int {
+	g.checkInts(a, b)
+	b.value.ModInverse(a.value, g.prime)
+	return b
+}
+
+// Random securely generates a random number in the group: 2 <= rand <= p-1
+// Sets r to the number and returns it
+func (g *Group) Random(r *Int) *Int {
+	g.checkInts(r)
+	rng := g.rng
+	r.value.Set(g.one)
+	for g.one.Cmp(r.value) == 0 {
+		b, err := csprng.GenerateInGroup(g.primeBytes,
+			len(g.primeBytes), rng)
+		if err != nil {
+			jww.FATAL.Panicf("Could not generate random number in group: %s", err)
+		}
+		r.value.SetBytes(b)
+	}
+	return r
+}
+
+// GetP returns a copy of the group's prime
+func (g *Group) GetP() *large.Int {
+	n := large.NewInt(1)
+	n.Set(g.prime)
+	return n
+}
+
+// GetG returns a copy of the group's generator
+func (g *Group) GetG() *large.Int {
+	n := large.NewInt(1)
+	n.Set(g.gen)
+	return n
+}
+
+// GetGCyclic returns a new cyclicInt with the group's generator
+func (g *Group) GetGCyclic() *Int {
+	return g.NewIntFromLargeInt(g.gen)
+}
+
+// GetPBytes returns a copy of the group's prime bytes
+func (g *Group) GetPBytes() []byte {
+	pCopy := make([]byte, len(g.primeBytes))
+	copy(pCopy, g.primeBytes)
+	return pCopy
+}
+
+// GetPSub1 returns a copy of the group's p-1
+func (g *Group) GetPSub1() *Int {
+	n := large.NewInt(1)
+	n.Set(g.psub1)
+	return &Int{n, g.fingerprint}
+}
+
+// GetPSub1Cyclic returns a new cyclicInt with the group's p-1
+func (g *Group) GetPSub1Cyclic() *Int {
+	return g.NewIntFromLargeInt(g.psub1)
+}
+
+// GetPSub1Factor returns a copy of the group's (p-1)/2
+func (g *Group) GetPSub1Factor() *large.Int {
+	n := large.NewInt(1)
+	n.Set(g.psub1factor)
+	return n
+}
+
+// GetPSub1FactorCyclic returns a new cyclicInt with the group's (p-1)/2
+func (g *Group) GetPSub1FactorCyclic() *Int {
+	return g.NewIntFromLargeInt(g.psub1factor)
+}
+
+// FullBytes gets cyclicInt left-padded to the size of the prime
+func (g *Group) FullBytes(x *Int) []byte {
+	return x.value.LeftpadBytes(uint64(g.prime.BitLen() >> 3))
+}
+
+// GroupMul Multiplies all ints in the passed slice slc together and
+// places the result in c
+func (g Group) MulMulti(c *Int, ints ...*Int) *Int {
+
+	g.checkInts(append(ints, c)...)
+	c.value.SetInt64(1)
+
+	for _, islc := range ints {
+		g.Mul(c, islc, c)
+	}
+
+	return c
+}
+
+// Exp sets z = x**y mod p, and returns z.
+func (g Group) Exp(x, y, z *Int) *Int {
+	g.checkInts(x, y, z)
+	z.value.Exp(x.value, y.value, g.prime)
+	return z
+}
+
+// ExpG sets z = g**y mod p, and returns z.
+func (g Group) ExpG(y, z *Int) *Int {
+	g.checkInts(y, z)
+	z.value.Exp(g.gen, y.value, g.prime)
+	return z
+}
+
+// RandomCoprime randomly generates coprimes in the group (coprime
+// against g.prime-1)
+func (g *Group) RandomCoprime(r *Int) *Int {
+	g.checkInts(r)
+	var err error
+	for r.value.Set(g.psub1); !r.value.IsCoprime(g.psub1); {
+		g.random, err = csprng.GenerateInGroup(g.prime.Bytes(), len(g.psub1.Bytes()), g.rng)
+		if err != nil {
+			jww.FATAL.Panicf("Could not generate random "+
+				"Coprime number in group: %v", err.Error())
+		}
+		r.value.SetBytes(g.random)
+		r.value.Mod(r.value, g.psub3)
+		r.value.Add(r.value, g.two)
+	}
+	return r
+}
+
+// RootCoprime sets tmp = y√x mod p, and returns tmp. Only works with y's
+// coprime with g.prime-1 (g.psub1)
+func (g Group) RootCoprime(x, y, z *Int) *Int {
+	g.checkInts(x, y, z)
+	tmp := g.NewInt(1)
+	tmp.value.ModInverse(y.value, g.psub1)
+	g.Exp(x, tmp, z)
+	return z
+}
+
+// Finds a number coprime with p-1 and who's modular exponential inverse is
+// the number of prescribed bits value. Bits must be greater than 1.
+// Only works when the prime is safe or strong
+// Using a smaller bytes length is acceptable because modular logarithm algorithm's
+// complexities derive primarily from the size of the prime defining the group
+// not the size of the exponent.  More information can be found here:
+// TODO: add link to doc
+// The function will panic if bits >= log2(g.prime), so the caller MUST use
+// a correct value of bits
+
+func (g Group) FindSmallCoprimeInverse(z *Int, bitLen uint32) *Int {
+	if bitLen >= uint32(g.prime.BitLen()) {
+		jww.FATAL.Panicf("Requested bits: %d is greater than"+
+			" or equal to group's prime: %d", bitLen, g.prime.BitLen())
+	}
+
+	g.checkInts(z)
+	// RNG that ensures the output is an odd number between 2 and 2^bitLen
+	// that is not equal to p-1/2.  This must occur because for a proper
+	// modular inverse to exist within a group a number must have no common
+	// factors with the number that defines the group.  Normally that would not
+	// be a problem because the number that defines the group normally is a prime,
+	// but we are inverting within a group defined by the even number p-1 to find the
+	// modular exponential inverse, so the number must be chozen from a different set
+
+	// In order to generate the number in the range
+	// the following steps are taken:
+	// 1. max = 2^(bitLen)-2
+	// 2. gen rand num by reading from rng
+	// 3. rand mod max : giving a range of 0 - 2^(bitLen)-3
+	// 4. rand + 2: range: 2 - 2^(bitLen)-1
+	// 5. rand ^ 1: range: 3 - 2^(bitLen)-1, odd number
+	max := large.NewInt(1).Sub(
+		large.NewInt(1).LeftShift(
+			g.one,
+			uint(bitLen)),
+		g.two)
+
+	zinv := large.NewInt(1)
+
+	for true {
+		n, err := g.rng.Read(g.random)
+		if err != nil || n != len(g.random) {
+			jww.FATAL.Panicf("Could not generate random "+
+				"number in group: %v", err.Error())
+		}
+		zinv.SetBytes(g.random)
+		zinv.Mod(zinv, max)
+		zinv.Add(zinv, g.two)
+		zinv.Xor(zinv, g.one)
+
+		// p-1 has one odd factor, (p-1)/2,  we must check that the generated number is not that
+		if zinv.Cmp(g.psub1factor) == 0 {
+			continue
+		}
+
+		// Modulo inverse zinv and check that the inverse exists
+		if z.value.ModInverse(zinv, g.psub1) == nil {
+			continue
+		}
+
+		zbytes := z.Bytes()
+
+		// Checks if the lowest bit is 1, implying the value is odd.
+		// Due to the fact that p is a safe prime, this means the value is
+		// coprime with p minus 1 because its only has one odd factor, which is
+		// also checked
+
+		if zbytes[len(zbytes)-1]&0x01 == 1 {
+			if zinv.Cmp(g.psub1factor) != 0 {
+				break
+			}
+		}
+
+	}
+
+	return z
+}
+
+// GobEncode returns a byte slice representing the encoding of Group for the
+// transmission to a GobDecode().
+func (g *Group) GobEncode() ([]byte, error) {
+	// Anonymous structure that flattens nested structures
+	s := struct {
+		P []byte
+		G []byte
+	}{
+		g.prime.Bytes(),
+		g.gen.Bytes(),
+	}
+
+	var buf bytes.Buffer
+
+	// Create new encoder that will transmit the buffer
+	enc := gob.NewEncoder(&buf)
+
+	// Transmit the data
+	err := enc.Encode(s)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return buf.Bytes(), nil
+}
+
+// GobDecode overwrites the receiver, which must be a pointer, with Group
+// represented by the byte slice, which was written by GobEncode().
+func (g *Group) GobDecode(b []byte) error {
+	// Anonymous, empty, flat structure
+	s := struct {
+		P []byte
+		G []byte
+	}{
+		[]byte{},
+		[]byte{},
+	}
+
+	var buf bytes.Buffer
+
+	// Write bytes to the buffer
+	buf.Write(b)
+
+	// Create new decoder that reads from the buffer
+	dec := gob.NewDecoder(&buf)
+
+	// Receive and decode data
+	err := dec.Decode(&s)
+
+	if err != nil {
+		return err
+	}
+
+	// Convert decoded bytes and put into empty structure
+	prime := large.NewIntFromBytes(s.P)
+	gen := large.NewIntFromBytes(s.G)
+
+	*g = *NewGroup(prime, gen)
+
+	return nil
+}
+
+// MarshalJSON extracts prime, gen and primeQ to a json object.
+// Returns the json object as a byte slice.
+func (g *Group) MarshalJSON() ([]byte, error) {
+
+	// Get group parameters
+	prime := g.GetP()
+	gen := g.GetG()
+
+	// Create json object
+	base := 16
+	jsonObj := map[string]string{
+		"prime": prime.TextVerbose(base, 0),
+		"gen":   gen.TextVerbose(base, 0),
+	}
+
+	// Marshal json object into byte slice
+	b, err := json.Marshal(&jsonObj)
+	if err != nil {
+		return nil, err
+	}
+
+	return b, nil
+}
+
+// Overwrites the receiver, which must be a pointer, with Group
+// represented by the byte slice which contains encoded JSON data
+func (g *Group) UnmarshalJSON(b []byte) error {
+
+	// Initialize json object to contain max sized group params
+	base := 16
+	max := large.NewMaxInt().TextVerbose(base, 0)
+	jsonObj := map[string]string{
+		"prime": max,
+		"gen":   max,
+	}
+
+	// Unmarshal byte slice into json object
+	err := json.Unmarshal(b, &jsonObj)
+
+	if err != nil {
+		return err
+	}
+
+	// Get group params from json object and put into receiver
+	prime := large.NewIntFromString(jsonObj["prime"], base)
+	gen := large.NewIntFromString(jsonObj["gen"], base)
+	*g = *NewGroup(prime, gen)
+
+	return nil
+}
diff --git a/cyclic/group_test.go b/cyclic/group_test.go
new file mode 100644
index 00000000..7b25e8ee
--- /dev/null
+++ b/cyclic/group_test.go
@@ -0,0 +1,2069 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+package cyclic
+
+import (
+	"bytes"
+	"crypto/sha256"
+	"errors"
+	"gitlab.com/xx_network/crypto/large"
+	"math/rand"
+	"reflect"
+	"testing"
+)
+
+// Tests NewGroup functionality
+func TestNewGroup(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	actual := NewGroup(p, g)
+
+	type testStruct struct {
+		prime *large.Int
+		g     *large.Int
+	}
+	expected := testStruct{p, g}
+	if actual.prime.Cmp(expected.prime) != 0 {
+		t.Errorf("TestNewGroup failed to initialize prime, expected: '%v',"+
+			" got: '%v'", expected.prime.Text(10), actual.prime.Text(10))
+	} else if actual.gen.Cmp(expected.g) != 0 {
+		t.Errorf("TestNewGroup failed to initialize generator, expected: '%v',"+
+			" got: '%v'", expected.g.Text(10), actual.gen.Text(10))
+	}
+}
+
+// Test creation of cyclicInt in the group from int64
+func TestNewInt(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	expected := large.NewInt(42)
+	actual := grp.NewInt(42)
+
+	if actual.value.Cmp(expected) != 0 {
+		t.Errorf("NewInt creation failed, expected: %v,"+
+			"got: %v", expected, actual.value)
+	} else if actual.GetGroupFingerprint() != grp.GetFingerprint() {
+		t.Errorf("NewInt is not in the group, expected group fingerprint: %v,"+
+			"got: %v", grp.GetFingerprint(), actual.GetGroupFingerprint())
+	}
+}
+
+//Tests creation and properties of an IntBuffer
+func TestGroup_NewIntBuffer(t *testing.T) {
+
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	//test that the size is correct and the default value is set correctly
+	rng := rand.New(rand.NewSource(42))
+
+	tests := 100
+
+	for i := 0; i < tests; i++ {
+		defaultInt := grp.Random(grp.NewInt(1))
+		size := rng.Uint32() % 10000
+		buf := grp.NewIntBuffer(size, defaultInt)
+
+		//test that the length is correct
+		if len(buf.values) != int(size) {
+			t.Errorf("NewIntBuffer did not generate buffer of the correct size: "+
+				"Expected %v, Recieved: %v", size, len(buf.values))
+		}
+
+		pass := true
+
+		defaultIntLarge := defaultInt.GetLargeInt()
+
+		//test that the default value is set correctly
+		for _, i := range buf.values {
+			if i.Cmp(defaultIntLarge) != 0 {
+				pass = false
+			}
+		}
+
+		if !pass {
+			t.Errorf("NewIntBuffer internal values not equal to default value")
+		}
+	}
+
+	//test that when passed default int is nil values are set to prime-1
+	buf := grp.NewIntBuffer(10, nil)
+
+	for _, i := range buf.values {
+		if i.Cmp(grp.psub1) != 0 {
+			t.Errorf("NewIntBuffer internal values not equal to psub1 when nill passed")
+		}
+	}
+
+}
+
+// Test creation of cyclicInt in the group from int64 fails when outside the group
+func TestNewInt_Panic(t *testing.T) {
+	defer func() {
+		if r := recover(); r != nil {
+			return
+		}
+	}()
+
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	grp.NewInt(0)
+
+	t.Errorf("NewInt created even when outside of the group")
+}
+
+// Test creation of cyclicInt in the group from large.Int
+func TestNewIntFromLargeInt(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	expected := large.NewInt(42)
+	actual := grp.NewIntFromLargeInt(expected)
+
+	if actual.value.Cmp(expected) != 0 {
+		t.Errorf("NewIntFromLargeInt creation failed, expected: %v,"+
+			"got: %v", expected, actual.value)
+	} else if actual.GetGroupFingerprint() != grp.GetFingerprint() {
+		t.Errorf("NewIntFromLargeInt is not in the group, expected group fingerprint: %v,"+
+			"got: %v", grp.GetFingerprint(), actual.GetGroupFingerprint())
+	}
+}
+
+// Test creation of cyclicInt in the group from large.Int fails when outside the group
+func TestNewIntFromLargeInt_Panic(t *testing.T) {
+	defer func() {
+		if r := recover(); r != nil {
+			return
+		}
+	}()
+
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	grp.NewIntFromLargeInt(large.NewInt(0))
+
+	t.Errorf("NewIntFromLargeInt created even when outside of the group")
+}
+
+// Test creation of cyclicInt in the group from byte array
+func TestNewIntFromBytes(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	expected := large.NewInt(42)
+	value := []byte{0x2A}
+	actual := grp.NewIntFromBytes(value)
+
+	if actual.value.Cmp(expected) != 0 {
+		t.Errorf("NewIntFromBytes creation failed, expected: %v,"+
+			"got: %v", expected, actual.value)
+	} else if actual.GetGroupFingerprint() != grp.GetFingerprint() {
+		t.Errorf("NewIntFromBytes is not in the group, expected group fingerprint: %v,"+
+			"got: %v", grp.GetFingerprint(), actual.GetGroupFingerprint())
+	}
+}
+
+// Test creation of cyclicInt in the group from bytes fails when outside the group
+func TestNewIntFromBytes_Panic(t *testing.T) {
+	defer func() {
+		if r := recover(); r != nil {
+			return
+		}
+	}()
+
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	grp.NewIntFromBytes([]byte{0})
+
+	t.Errorf("NewIntFromBytes created even when outside of the group")
+}
+
+// Test creation of cyclicInt in the group from string
+// Also confirm that if the string can't be converted, nil is returned
+func TestNewIntFromString(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	expected := large.NewInt(42)
+	value := "42"
+	actual := grp.NewIntFromString(value, 10)
+
+	if actual.value.Cmp(expected) != 0 {
+		t.Errorf("NewIntFromString creation failed, expected: %v,"+
+			"got: %v", expected, actual.value)
+	} else if actual.GetGroupFingerprint() != grp.GetFingerprint() {
+		t.Errorf("NewIntFromString is not in the group, expected group fingerprint: %v,"+
+			"got: %v", grp.GetFingerprint(), actual.GetGroupFingerprint())
+	}
+
+	errVal := grp.NewIntFromString("185", 5)
+
+	if errVal != nil {
+		t.Errorf("NewIntFromString should return nil when error occurs decoding string")
+	}
+}
+
+// Test creation of cyclicInt in the group from string fails when outside the group
+func TestNewIntFromString_Panic(t *testing.T) {
+	defer func() {
+		if r := recover(); r != nil {
+			return
+		}
+	}()
+
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	grp.NewIntFromString("0", 16)
+
+	t.Errorf("NewIntFromString created even when outside of the group")
+}
+
+// Show that NewIntFromBits fails when outside of group
+func TestGroup_NewIntFromBits_Panic(t *testing.T) {
+	defer func() {
+		if r := recover(); r != nil {
+			return
+		}
+	}()
+
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	grp.NewIntFromBits(large.Bits{0})
+
+	t.Errorf("NewIntFromBits created even when outside of the group")
+}
+
+// Show that NewIntFromBits makes a big int from a word string
+func TestGroup_NewIntFromBits(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	expected := grp.NewIntFromString("123456", 16)
+	i := grp.NewIntFromBits(large.Bits{0x123456})
+	t.Log(i.TextVerbose(16, 0))
+
+	if expected.Cmp(i) != 0 {
+		t.Errorf("Expected int to be %v, got %v", expected.Text(16), i.Text(16))
+	}
+}
+
+// Test creation of cyclicInt in the group from Max4KInt value
+func TestNewMaxInt(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	expected := grp.psub1
+	actual := grp.NewMaxInt()
+
+	if actual.value.Cmp(expected) != 0 {
+		t.Errorf("NewMaxInt creation failed, expected: %v,"+
+			"got: %v", expected, actual.value)
+	} else if actual.GetGroupFingerprint() != grp.GetFingerprint() {
+		t.Errorf("NewMaxInt is not in the group, expected group fingerprint: %v,"+
+			"got: %v", grp.GetFingerprint(), actual.GetGroupFingerprint())
+	}
+}
+
+// Test creation of cyclicInt in the group from uint64
+func TestNewIntFromUInt(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	expected := large.NewInt(42)
+	actual := grp.NewIntFromUInt(uint64(42))
+
+	if actual.value.Cmp(expected) != 0 {
+		t.Errorf("NewIntFromUInt creation failed, expected: %v,"+
+			"got: %v", expected, actual.value)
+	} else if actual.GetGroupFingerprint() != grp.GetFingerprint() {
+		t.Errorf("NewIntFromUInt is not in the group, expected group fingerprint: %v,"+
+			"got: %v", grp.GetFingerprint(), actual.GetGroupFingerprint())
+	}
+}
+
+// Test creation of cyclicInt in the group from uint64 fails when outside the group
+func TestNewIntFromUInt_Panic(t *testing.T) {
+	defer func() {
+		if r := recover(); r != nil {
+			return
+		}
+	}()
+
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	grp.NewIntFromUInt(0)
+
+	t.Errorf("NewIntFromUInt created even when outside of the group")
+}
+
+// Test group fingerprint getter
+func TestGetFingerprint(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	h := sha256.New()
+	h.Write(p.Bytes())
+	h.Write(g.Bytes())
+	expected := large.NewIntFromBytes(h.Sum(nil)[:GroupFingerprintSize]).Uint64()
+
+	if grp.GetFingerprint() != expected {
+		t.Errorf("GetFingerprint returned wrong value, expected: %v,"+
+			" got: %v", expected, grp.GetFingerprint())
+	}
+}
+
+// Test group fingerprint getter
+func TestGetFingerprintText(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	expected := "ln9lzlk2..."
+
+	if grp.GetFingerprintText() != expected {
+		t.Errorf("GetFingerprintText returned wrong value, expected: %v,"+
+			" got: %v", expected, grp.GetFingerprintText())
+	}
+}
+
+// Test setting cyclicInt to another from the same group
+func TestSet(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	expected := grp.NewInt(int64(42))
+	actual := grp.NewInt(int64(69))
+
+	if actual.Cmp(expected) == 0 {
+		t.Errorf("Original Ints should be different to test Set")
+	}
+
+	grp.Set(actual, expected)
+
+	result := actual.Cmp(expected)
+
+	if result != 0 {
+		t.Errorf("Test of Set failed, expected: '0', got: '%v'",
+			result)
+	}
+}
+
+// Test that Set panics if cyclicInt doesn't belong to the group
+func TestSet_Panic(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	grp2 := NewGroup(p, g2)
+
+	expected := grp.NewInt(int64(42))
+	actual := grp2.NewInt(int64(69))
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("Set should panic when one of involved " +
+				"cyclicInts doesn't belong to the group")
+		}
+	}()
+
+	grp.Set(actual, expected)
+}
+
+// TestSetLargeInt tests if the value is properly copied
+func TestSetLargeInt(t *testing.T) {
+	p := large.NewInt(17)
+	g := large.NewInt(7)
+	group := NewGroup(p, g)
+
+	inputs := []int64{2, 1, 12, 17, 18}
+
+	for i := 0; i < len(inputs); i++ {
+		tmp := group.NewInt(5)
+		v := tmp.value
+		exp := group.NewInt(inputs[i%3])
+		li := large.NewInt(inputs[i])
+		if group.SetLargeInt(tmp, li) != nil {
+			if i >= 3 {
+				t.Errorf("TestLargeInt set value outside "+
+					"of group: %d", inputs[i])
+			}
+		}
+		if i < 3 && (tmp.Cmp(exp) != 0 || v.Cmp(li) != 0) {
+			t.Errorf("TestSetFromLargeInt failed at index %v", i)
+		}
+	}
+}
+
+// Test setting cyclicInt in the same group from bytes
+func TestSetBytes(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	expected := []*Int{
+		grp.NewInt(42),
+		grp.NewInt(6553522),
+		grp.NewInt(2)}
+	testBytes := [][]byte{
+		{0x2A},             // 42
+		{0x63, 0xFF, 0xB2}, // 6553522
+		{0x02}}
+
+	actual := grp.NewInt(55)
+
+	for i, testi := range testBytes {
+		actual = grp.SetBytes(actual, testi)
+		if actual.Cmp(expected[i]) != 0 {
+			t.Errorf("Test of SetBytes failed at index %v, expected: '%v', "+
+				"actual: %v", i, expected[i].Text(10), actual.Text(10))
+		}
+	}
+
+}
+
+// Test that SetBytes panics if cyclicInt doesn't belong to the group
+func TestSetBytes_Panic(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	grp2 := NewGroup(p, g2)
+
+	actual := grp2.NewInt(int64(42))
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("SetBytes should panic when " +
+				"cyclicInt doesn't belong to the group")
+		}
+	}()
+
+	grp.SetBytes(actual, []byte("TEST"))
+}
+
+// Shows that setting bits results in a different integer
+func TestGroup_SetBits(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	expected := grp.NewInt(2)
+	newInt := grp.NewInt(1)
+	grp.SetBits(newInt, large.Bits{2})
+	if expected.Cmp(newInt) != 0 {
+		t.Errorf("Setbits didn't set to the expected int result. Got %v, expected %v", newInt.Text(16), expected.Text(16))
+	}
+}
+
+// Shows that setting bits with a different group from the original integer panics
+func TestGroup_SetBits_Panic(t *testing.T) {
+	defer func() {
+		if r := recover(); r != nil {
+			return
+		}
+	}()
+
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	grp2 := NewGroup(p, g2)
+
+	i := grp.NewInt(1)
+	grp2.SetBits(i, large.Bits{123456})
+
+	t.Errorf("SetBits worked even when another group was used")
+}
+
+// OverwriteBits is a higher-level method that copies a bits slice into an integer
+// or allocates a new slice if necessary
+// Shows that OverwriteBits never uses the passed bits slice to back the new integer
+// Shows that the results are as expected, even in cases where the lengths aren't equal
+func TestGroup_OverwriteBits(t *testing.T) {
+	// We need a bigger group than the other tests, because for this test to be meaningful
+	// the prime needs to take up more than one word
+	// Using modp1536
+	p := large.NewIntFromString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	// Case 1: enough space in the existing int for the overwriting int to exist
+	existing := grp.NewMaxInt()
+	existingStart := &existing.Bits()[0]
+	t.Log("existing cap:", cap(existing.Bits()))
+	expected := grp.NewIntFromString("1234567890abcdef1234567890abcdef1234567890abcdef123", 16)
+	t.Log("expected len:", len(expected.Bits()))
+	grp.OverwriteBits(existing, expected.Bits())
+
+	// Start of backing bits slice should be the same
+	if existingStart != &existing.Bits()[0] {
+		t.Errorf("start of existing changed. had %v, got %v", existingStart, &existing.Bits()[0])
+	}
+	// Should get expected number in existing
+	if existing.Cmp(expected) != 0 {
+		t.Errorf("actual differed from expected. actual: %v, expected %v", existing, expected)
+	}
+
+	// Case 2: not enough space in the existing int for the overwriting int to exist
+	newAlloc := grp.NewInt(1)
+	newAllocStart := &newAlloc.Bits()[0]
+	t.Log("newAlloc cap:", cap(newAlloc.Bits()))
+	grp.OverwriteBits(newAlloc, expected.Bits())
+
+	// Start of backing bits slice should be different
+	if newAllocStart == &newAlloc.Bits()[0] {
+		t.Errorf("start of newAlloc didn't change. had %v, got %v", newAllocStart, &newAlloc.Bits()[0])
+	}
+	// It should also be different from the backing bits slice of expected
+	if &newAlloc.Bits()[0] == &existing.Bits()[0] {
+		t.Errorf("newAlloc uses same backing memory as existing! bad!!")
+	}
+	// Of course, the int should be equal to existing
+	if expected.Cmp(newAlloc) != 0 {
+		t.Errorf("actual differed from expected. actual: %v, expected %v", newAlloc, expected)
+	}
+}
+
+// Is it possible to trigger the panic?
+func TestGroup_OverwriteBits_Panic(t *testing.T) {
+	defer func() {
+		if r := recover(); r != nil {
+			return
+		}
+	}()
+
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	grp2 := NewGroup(p, g2)
+
+	i := grp.NewInt(1)
+	grp2.OverwriteBits(i, large.Bits{123456})
+
+	t.Errorf("OverwriteBits worked with a different group")
+}
+
+// Test setting cyclicInt in the same group from string
+func TestSetString(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	type testStructure struct {
+		str  string
+		base int
+	}
+
+	testStructs := []testStructure{
+		{"42", 0},
+		{"100000000", 0},
+		{"5", 0},
+		{"1", 0},
+		{"f", 0},
+		{"182", 5},
+		{"10", 2},
+	}
+
+	expected := []*Int{
+		grp.NewInt(42),
+		grp.NewInt(100000000),
+		grp.NewInt(5),
+		grp.NewInt(1),
+		nil,
+		nil,
+		grp.NewInt(2),
+	}
+
+	actual := grp.NewInt(1)
+
+	for i, testi := range testStructs {
+		ret := grp.SetString(actual, testi.str, testi.base)
+
+		// Test invalid input making sure it occurs when expected
+		if ret == nil {
+			if expected[i] != nil {
+				t.Error("Test of SetString() failed at index:", i,
+					"Function didn't handle invalid input correctly")
+			}
+		} else {
+			if actual.Cmp(expected[i]) != 0 {
+				t.Errorf("Test of SetString() failed at index: %v Expected: %v;"+
+					" Actual: %v", i, expected[i].Text(10), actual.Text(10))
+			}
+		}
+	}
+
+}
+
+// Test that SetString panics if cyclicInt doesn't belong to the group
+func TestSetString_Panic(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	grp2 := NewGroup(p, g2)
+
+	actual := grp2.NewInt(int64(42))
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("SetString should panic when " +
+				"cyclicInt doesn't belong to the group")
+		}
+	}()
+
+	grp.SetString(actual, "1234", 10)
+}
+
+// Test setting cyclicInt in the same group to Max4KInt value
+func TestSetMaxInt(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	expected := grp.GetPSub1()
+	actual := grp.NewInt(int64(69))
+
+	if actual.Cmp(expected) == 0 {
+		t.Errorf("Original Ints should be different to test SetMaxInt")
+	}
+
+	grp.SetMaxInt(actual)
+
+	result := actual.Cmp(expected)
+
+	if result != 0 {
+		t.Errorf("Test of SetMaxInt failed, expected: '0', got: '%v'",
+			result)
+	}
+}
+
+// Test that Set panics if cyclicInt doesn't belong to the group
+func TestSetMaxInt_Panic(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	grp2 := NewGroup(p, g2)
+
+	actual := grp2.NewInt(int64(69))
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("SetMaxInt should panic when " +
+				"cyclicInt doesn't belong to the group")
+		}
+	}()
+
+	grp.SetMaxInt(actual)
+}
+
+// Test setting cyclicInt in the same group to uint64 value
+func TestSetUint64(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	expected := grp.NewInt(int64(42))
+	actual := grp.NewInt(int64(69))
+
+	if actual.Cmp(expected) == 0 {
+		t.Errorf("Original Ints should be different to test SetUint64")
+	}
+
+	grp.SetUint64(actual, uint64(42))
+
+	result := actual.Cmp(expected)
+
+	if result != 0 {
+		t.Errorf("Test of SetUint64 failed, expected: '0', got: '%v'",
+			result)
+	}
+}
+
+// Test that Set panics if cyclicInt doesn't belong to the group
+func TestSetUint64_Panic(t *testing.T) {
+	p := large.NewInt(1000000010101111111)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	grp2 := NewGroup(p, g2)
+
+	actual := grp2.NewInt(int64(69))
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("SetUint64 should panic when " +
+				"cyclicInt doesn't belong to the group")
+		}
+	}()
+
+	grp.SetUint64(actual, uint64(0))
+}
+
+// Test multiplication under the group
+func TestMul(t *testing.T) {
+	prime := int64(107)
+	p := large.NewInt(prime)
+	g := large.NewInt(5)
+	group := NewGroup(p, g)
+
+	actual := []*Int{
+		group.Mul(group.NewInt(20), group.NewInt(11), group.NewInt(1)),
+		group.Mul(group.NewInt(1), group.NewInt(10), group.NewInt(1)),
+	}
+	expected := []*Int{
+		group.NewInt((20 * 11) % prime),
+		group.NewInt(10),
+	}
+
+	for i := 0; i < len(actual); i++ {
+		if actual[i].value.Cmp(expected[i].value) != 0 {
+			t.Errorf("TestMulForGroup failed at index:%v, expected:%v, got:%v",
+				i, expected[i].value.Text(10), actual[i].value.Text(10))
+		}
+	}
+
+}
+
+// Test left padded bytes getter
+func TestFullBytes(t *testing.T) {
+
+	expected := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A}
+
+	actual := grp.NewInt(int64(42))
+
+	actualbytes := grp.FullBytes(actual)
+
+	if !bytes.Equal(actualbytes, expected) {
+		t.Errorf("Test of FullBytes failed, expected: '%v', got: '%v'",
+			actualbytes, expected)
+	}
+}
+
+// Test that mul panics if cyclicInt doesn't belong to the group
+func TestMul_Panic(t *testing.T) {
+	prime := int64(107)
+	p := large.NewInt(prime)
+	g := large.NewInt(5)
+	group := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	group2 := NewGroup(p, g2)
+
+	a := group.NewInt(20)
+	b := group2.NewInt(11)
+	c := group.NewInt(1)
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("Mul should panic when one of involved " +
+				"cyclicInts doesn't belong to the group")
+		}
+	}()
+
+	group.Mul(a, b, c)
+}
+
+// Test Inside that checks if a number is inside the group
+func TestInside(t *testing.T) {
+	p := large.NewInt(17)
+	g := large.NewInt(7)
+	group := NewGroup(p, g)
+	expected := []bool{
+		false,
+		true,
+		false,
+		false,
+		true,
+	}
+	actual := []bool{
+		group.Inside(large.NewInt(0)),
+		group.Inside(large.NewInt(1)),
+		group.Inside(large.NewInt(17)),
+		group.Inside(large.NewInt(18)),
+		group.Inside(large.NewInt(12)),
+	}
+
+	for i := 0; i < len(expected); i++ {
+		if actual[i] != expected[i] {
+			t.Errorf("TestInside failed at index:%v, expected:%v, got:%v",
+				i, expected[i], actual[i])
+		}
+	}
+}
+
+// Test Inside that checks if a number is inside the group
+func TestSingleBytesInside(t *testing.T) {
+	p := large.NewInt(1023)
+	g := large.NewInt(7)
+	group := NewGroup(p, g)
+	expected := []bool{
+		false,
+		false,
+		true,
+		true,
+		true,
+		true,
+		false,
+		false,
+	}
+	actual := []bool{
+		group.singleBytesInside([]byte{0}),
+		group.singleBytesInside(large.NewInt(0).Bytes()),
+		group.singleBytesInside(large.NewInt(1).Bytes()),
+		group.singleBytesInside(large.NewInt(17).Bytes()),
+		group.singleBytesInside(large.NewInt(70).Bytes()),
+		group.singleBytesInside(large.NewInt(1022).Bytes()),
+		group.singleBytesInside(large.NewInt(1111).Bytes()),
+		group.singleBytesInside(large.NewInt(100000).Bytes()),
+	}
+
+	for i := 0; i < len(expected); i++ {
+		if actual[i] != expected[i] {
+			t.Errorf("TestBytesInside failed at index:%v, expected:%v, got:%v",
+				i, expected[i], actual[i])
+		}
+	}
+}
+
+// Test Inside that checks if a number is inside the group
+func TestBytesInside(t *testing.T) {
+	p := large.NewInt(1023)
+	g := large.NewInt(7)
+	group := NewGroup(p, g)
+	expected := []bool{
+		true,
+		true,
+		false,
+		false,
+	}
+	actual := []bool{
+		group.BytesInside(large.NewInt(1).Bytes()),
+		group.BytesInside(large.NewInt(1).Bytes(), large.NewInt(1000).Bytes(), large.NewInt(300).Bytes()),
+		group.BytesInside(large.NewInt(1).Bytes(), large.NewInt(1000).Bytes(), large.NewInt(300).Bytes(), large.NewInt(2000).Bytes()),
+		group.BytesInside(large.NewInt(0).Bytes(), large.NewInt(1100).Bytes(), large.NewInt(30000000).Bytes(), large.NewInt(400900).Bytes()),
+	}
+
+	for i := 0; i < len(expected); i++ {
+		if actual[i] != expected[i] {
+			t.Errorf("TestBytesInside failed at index:%v, expected:%v, got:%v",
+				i, expected[i], actual[i])
+		}
+	}
+}
+
+// Test modulus under the group
+func TestModP(t *testing.T) {
+	p := []*large.Int{large.NewInt(17), large.NewIntFromString("717190887961", 10),
+		large.NewIntFromString("717190905917", 10)}
+	g := large.NewInt(13)
+
+	group := make([]*Group, 0, len(p))
+	for i := 0; i < len(p); i++ {
+		group = append(group, NewGroup(p[i], g))
+	}
+
+	expected := []*large.Int{large.NewInt(2), large.NewIntFromString("269673339004", 10),
+		large.NewIntFromString("623940771224", 10)}
+	a := []*large.Int{large.NewInt(5000), large.NewIntFromString("beefbeecafe80386", 16),
+		large.NewIntFromString("77777777777777777777", 16)}
+	actual := make([]*Int, len(expected))
+	for i := 0; i < len(expected); i++ {
+		actual[i] = group[i].NewInt(1)
+		group[i].ModP(a[i], actual[i])
+	}
+
+	for i := 0; i < len(expected); i++ {
+		if actual[i].value.Cmp(expected[i]) != 0 {
+			t.Errorf("TestModP failed, expected: '%v', got: '%v'",
+				expected[i].Text(10), actual[i].value.Text(10))
+		}
+	}
+
+}
+
+// Test that inside panics if cyclicInt doesn't belong to the group
+func TestModP_Panic(t *testing.T) {
+	prime := int64(107)
+	p := large.NewInt(prime)
+	g := large.NewInt(5)
+	group := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	group2 := NewGroup(p, g2)
+
+	a := large.NewInt(20)
+	b := group2.NewInt(1)
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("ModP should panic when one of involved " +
+				"cyclicInts doesn't belong to the group")
+		}
+	}()
+
+	group.ModP(a, b)
+}
+
+// Test Inverse under the group
+func TestInverse(t *testing.T) {
+	p := large.NewInt(17)
+	g := large.NewInt(13)
+	group := NewGroup(p, g)
+	x := group.NewInt(13) //message
+	a := group.NewInt(10) //encryption key
+	inv := group.NewInt(1)
+	inv = group.Inverse(a, inv)             //decryption key
+	a = group.Mul(x, a, a)                  // encrypted message
+	c := group.Mul(inv, a, group.NewInt(1)) //decrypted message (x)
+
+	if c.value.Cmp(x.value) != 0 {
+		t.Errorf("TestInverse failed, expected: '%v', got: '%v'",
+			x.value.Text(10), c.value.Text(10))
+	}
+}
+
+// Test that inverse panics if cyclicInt doesn't belong to the group
+func TestInverse_Panic(t *testing.T) {
+	prime := int64(107)
+	p := large.NewInt(prime)
+	g := large.NewInt(5)
+	group := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	group2 := NewGroup(p, g2)
+
+	a := group.NewInt(20)
+	b := group2.NewInt(1)
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("Inverse should panic when one of involved " +
+				"cyclicInts doesn't belong to the group")
+		}
+	}()
+
+	group.Inverse(a, b)
+}
+
+// Test Random multiple times to check if
+// the number generated is ever outside the group
+func TestRandom(t *testing.T) {
+	p := large.NewInt(107)
+	g := large.NewInt(4)
+	group := NewGroup(p, g)
+	for i := 0; i < 100000; i++ {
+		if !group.Inside(group.Random(group.NewInt(1)).GetLargeInt()) {
+			t.Errorf("Generated number is not inside the group!")
+		}
+	}
+}
+
+// Test that Random panics if cyclicInt doesn't belong to the group
+func TestRandom_Panic(t *testing.T) {
+	p := large.NewInt(107)
+	g := large.NewInt(4)
+	group := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	group2 := NewGroup(p, g2)
+
+	a := group2.NewInt(20)
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("Random should panic when " +
+				"cyclicInt doesn't belong to the group")
+		}
+	}()
+
+	group.Random(a)
+}
+
+type AlwaysErrorReader struct{}
+
+func (r AlwaysErrorReader) Read(b []byte) (int, error) {
+	return 1, errors.New("testing reader error")
+}
+
+func (r AlwaysErrorReader) SetSeed(seed []byte) error {
+	return nil
+}
+
+// This test forces random to panic by overwriting the CSPRNG inside the group
+func TestRandom_PanicReadErr(t *testing.T) {
+	p := large.NewInt(107)
+	g := large.NewInt(4)
+	group := NewGroup(p, g)
+
+	// Overwrite CSPRNG
+	group.rng = AlwaysErrorReader{}
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("Random should panic on read error")
+		}
+	}()
+
+	group.Random(group.NewInt(1))
+}
+
+func TestGen(t *testing.T) {
+	// setup test group and generator
+	p := large.NewInt(17)
+	g := large.NewInt(29)
+	group := NewGroup(p, g)
+
+	// setup array to keep track of frequency of random values
+	r := group.NewInt(1)
+	rng := make([]int, int(p.Int64()))
+
+	tests := 500
+	thresh := 0.3
+
+	// generate randoms
+	for i := 0; i < tests; i++ {
+		rng[int(group.Random(r).value.Int64())]++
+	}
+
+	// make sure 0 and 1 were not generated
+	if rng[0] > 0 {
+		t.Errorf("TestGen() failed, 0 is outside of the required range")
+	}
+	if rng[1] > 0 {
+		t.Errorf("TestGen() failed, 1 is outside of the required range")
+	}
+
+	// check that frequency doesn't exceed threshold
+	for i := 0; i < len(rng); i++ {
+		if float64(rng[i])/float64(tests) > thresh {
+			t.Errorf("TestGen() failed, insufficiently random, value: %v"+
+				" occured: %v out of %v tests", i, rng[i], tests)
+		}
+	}
+
+}
+
+// Test prime getter from the group
+func TestGetP(t *testing.T) {
+	// setup test group and generator
+	p := large.NewInt(17)
+	g := large.NewInt(29)
+	group := NewGroup(p, g)
+	actual := group.GetP()
+
+	if actual.Cmp(p) != 0 {
+		t.Errorf("TestGetP failed, expected: '%v', got: '%v'",
+			p.Text(10), actual.Text(10))
+	}
+}
+
+//Tests the prime byte getter from the group
+//Tests the old manual call against the implementation (p.Bytes() vs grp.GetPBytes())
+//P is never nil, so no edge case there
+func TestGetPBytes(t *testing.T) {
+	// setup test group and generator
+	p := large.NewInt(17)
+	g := large.NewInt(29)
+	group := NewGroup(p, g)
+	actual := group.GetPBytes()
+
+	if bytes.Compare(p.Bytes(), actual) != 0 {
+		t.Errorf("TestGetPBytes failed, expected: '%v', got: '%v'",
+			p.Text(10), actual)
+	}
+
+}
+
+// Test generator getter from the group
+func TestGetG(t *testing.T) {
+	// setup test group and generator
+	p := large.NewInt(17)
+	g := large.NewInt(29)
+	group := NewGroup(p, g)
+	actual := group.GetG()
+
+	if actual.Cmp(g) != 0 {
+		t.Errorf("TestGetP failed, expected: '%v', got: '%v'",
+			g.Text(10), actual.Text(10))
+	}
+}
+
+// Test generator getter from the group cyclic version
+func TestGetGCyclic(t *testing.T) {
+	// setup test group and generator
+	p := large.NewInt(33)
+	g := large.NewInt(29)
+	group := NewGroup(p, g)
+	actual := group.GetGCyclic()
+
+	if actual.value.Cmp(g) != 0 {
+		t.Errorf("TestGetGCyclic failed, expected: '%v', got: '%v'",
+			g.Text(10), actual.value.Text(10))
+	}
+}
+
+// Test prime-1 getter from the group
+func TestGetPSub1(t *testing.T) {
+	// setup test group and generator
+	p := large.NewInt(17)
+	g := large.NewInt(29)
+	group := NewGroup(p, g)
+	actual := group.GetPSub1()
+	ps1 := large.NewInt(16)
+
+	if actual.value.Cmp(ps1) != 0 {
+		t.Errorf("TestGetPSub1 failed, expected: '%v', got: '%v'",
+			ps1.Text(10), actual.Text(10))
+	}
+}
+
+// Test prime-1 getter from the group cyclic version
+func TestGetPSub1Cyclic(t *testing.T) {
+	// setup test group and generator
+	p := large.NewInt(17)
+	g := large.NewInt(29)
+	group := NewGroup(p, g)
+	actual := group.GetPSub1Cyclic()
+	ps1 := large.NewInt(16)
+
+	if actual.value.Cmp(ps1) != 0 {
+		t.Errorf("TestGetPSub1Cyclic failed, expected: '%v', got: '%v'",
+			ps1.Text(10), actual.value.Text(10))
+	}
+
+}
+
+// Test (prime-1)/2 getter from the group
+func TestGetPSub1Factor(t *testing.T) {
+	// setup test group and generator
+	p := large.NewInt(17)
+	g := large.NewInt(29)
+	group := NewGroup(p, g)
+	actual := group.GetPSub1Factor()
+	pfactor := large.NewInt(8)
+
+	if actual.Cmp(pfactor) != 0 {
+		t.Errorf("TestGetPSub1Factor failed, expected: '%v', got: '%v'",
+			pfactor.Text(10), actual.Text(10))
+	}
+}
+
+// Test (prime-1)/2 getter from the group cyclic version
+func TestGetPSub1FactorCyclic(t *testing.T) {
+	// setup test group and generator
+	p := large.NewInt(17)
+	g := large.NewInt(29)
+	group := NewGroup(p, g)
+	actual := group.GetPSub1FactorCyclic()
+	pfactor := large.NewInt(8)
+
+	if actual.value.Cmp(pfactor) != 0 {
+		t.Errorf("TestGetPSub1FactorCyclic failed, expected: '%v', got: '%v'",
+			pfactor.Text(10), actual.value.Text(10))
+	}
+}
+
+// Test array multiplication under the group
+func TestArrayMul(t *testing.T) {
+	p := large.NewInt(11)
+	g := large.NewInt(7)
+	grp := NewGroup(p, g)
+
+	expected := large.NewInt(10)
+
+	slc := []*Int{
+		grp.NewInt(2),
+		grp.NewInt(3),
+		grp.NewInt(4),
+		grp.NewInt(5),
+	}
+
+	c := grp.NewInt(1)
+	actual := grp.MulMulti(c, slc...)
+
+	if actual.value.Cmp(expected) != 0 {
+		t.Errorf("TestArrayMul failed, expected: '%v', got: '%v'",
+			expected, actual)
+	}
+
+}
+
+// Test that ArrayMult panics if cyclicInt doesn't belong to the group
+func TestArrayMult_Panic(t *testing.T) {
+	prime := int64(107)
+	p := large.NewInt(prime)
+	g := large.NewInt(5)
+	group := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	group2 := NewGroup(p, g2)
+
+	slc := []*Int{
+		group.NewInt(2),
+		group2.NewInt(3),
+		group.NewInt(4),
+		group.NewInt(5),
+	}
+	a := group.NewInt(20)
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("ArrayMult should panic when one of involved " +
+				"cyclicInts doesn't belong to the group")
+		}
+	}()
+
+	group.MulMulti(a, slc...)
+}
+
+// Test exponentiation under the group
+func TestExp(t *testing.T) {
+	p := large.NewInt(117)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	type testStructure struct {
+		x *Int
+		y *Int
+		z *Int
+	}
+
+	testStrings := [][]string{
+		{"42", "41", "9"},
+		{"42", "63", "27"},
+		{"69", "42", "27"},
+		{"99", "81", "99"},
+	}
+
+	var testStructs []testStructure
+
+	for i, strs := range testStrings {
+		var ts testStructure
+
+		ts.x = grp.NewIntFromString(strs[0], 10)
+
+		if ts.x == nil {
+			t.Errorf("Setup for Test of Exp() for Group failed at 'x' phase of index: %v", i)
+		}
+
+		ts.y = grp.NewIntFromString(strs[1], 10)
+
+		if ts.y == nil {
+			t.Errorf("Setup for Test of Exp() for Group failed at 'y' phase of index: %v", i)
+		}
+
+		ts.z = grp.NewIntFromString(strs[2], 10)
+
+		if ts.z == nil {
+			t.Errorf("Setup for Test of Exp() for Group failed at 'z' phase of index: %v", i)
+		}
+
+		testStructs = append(testStructs, ts)
+	}
+
+	tests := len(testStructs)
+	pass := 0
+
+	expected := 0
+
+	for i, testi := range testStructs {
+		actual := grp.NewInt(1)
+		actual = grp.Exp(testi.x, testi.y, actual)
+
+		result := actual.value.Cmp(testi.z.value)
+
+		if result != expected {
+			t.Errorf("Test of Exp() for Group failed at index: %v Expected: %v, %v; Actual: %v, %v",
+				i, expected, testi.z.value.Text(10), result, actual.value.Text(10))
+		} else {
+			pass += 1
+		}
+	}
+	println("Exp() for Group", pass, "out of", tests, "tests passed.")
+
+}
+
+// Test exponentiation of the generator in the group
+func TestExpG(t *testing.T) {
+	p := large.NewInt(117)
+	g := large.NewInt(5)
+	grp := NewGroup(p, g)
+
+	type testStructure struct {
+		y *Int
+		z *Int
+	}
+
+	testStrings := [][]string{
+		{"42", "64"},
+		{"69", "44"},
+		{"43", "86"},
+		{"2", "25"},
+	}
+
+	var testStructs []testStructure
+
+	for i, strs := range testStrings {
+		var ts testStructure
+
+		ts.y = grp.NewIntFromString(strs[0], 10)
+
+		if ts.y == nil {
+			t.Errorf("Setup for Test of Exp() for Group failed at 'y' phase of index: %v", i)
+		}
+
+		ts.z = grp.NewIntFromString(strs[1], 10)
+
+		if ts.z == nil {
+			t.Errorf("Setup for Test of Exp() for Group failed at 'z' phase of index: %v", i)
+		}
+
+		testStructs = append(testStructs, ts)
+	}
+
+	expected := 0
+
+	for i, testi := range testStructs {
+		actual := grp.NewInt(1)
+		actual = grp.ExpG(testi.y, actual)
+
+		result := actual.value.Cmp(testi.z.value)
+
+		if result != expected {
+			t.Errorf("Test of Exp() for Group failed at index: %v Expected: %v; Actual: %v",
+				i, testi.z.value.Text(10), actual.value.Text(10))
+		}
+	}
+
+}
+
+// Test that Exp panics if cyclicInt doesn't belong to the group
+func TestExp_Panic(t *testing.T) {
+	prime := int64(107)
+	p := large.NewInt(prime)
+	g := large.NewInt(5)
+	group := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	group2 := NewGroup(p, g2)
+
+	a := group2.NewInt(20)
+	b := group.NewInt(11)
+	c := group.NewInt(1)
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("Exp should panic when one of involved " +
+				"cyclicInts doesn't belong to the group")
+		}
+	}()
+
+	group.Exp(a, b, c)
+}
+
+// Test random Coprime number generation under the group
+func TestRandomCoprime(t *testing.T) {
+	// setup test group and generator
+	p := large.NewInt(17)
+	g := large.NewInt(29)
+	group := NewGroup(p, g)
+
+	// setup array to keep track of frequency of random values
+	r := group.NewInt(1)
+	rng := make([]int, int(p.Int64()))
+
+	tests := 500
+
+	thresh := 0.3
+
+	// generate randoms
+	for i := 0; i < tests; i++ {
+		rng[int(group.RandomCoprime(r).value.Int64())]++
+	}
+
+	// make sure 0 and 1 were not generated
+	if rng[0] > 0 {
+		t.Errorf("TestRandomeCoprime() failed, 0 is outside of the required range")
+	}
+	if rng[1] > 0 {
+		t.Errorf("TestRandomeCoprime() failed, 1 is outside of the required range")
+	}
+
+	// check that frequency doesn't exceed threshold
+	for i := 0; i < len(rng); i++ {
+		if float64(rng[i])/float64(tests) > thresh {
+			t.Errorf("TestRandomCoprime() failed, insufficiently random, value: %v"+
+				" occured: %v out of %v tests", i, rng[i], tests)
+		}
+	}
+}
+
+// Test that RandomCoprime panics if cyclicInt doesn't belong to the group
+func TestRandomCoprime_Panic(t *testing.T) {
+	prime := int64(107)
+	p := large.NewInt(prime)
+	g := large.NewInt(5)
+	group := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	group2 := NewGroup(p, g2)
+
+	a := group2.NewInt(20)
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("RandomCoprime should panic when " +
+				"cyclicInt doesn't belong to the group")
+		}
+	}()
+
+	group.RandomCoprime(a)
+}
+
+// This test forces RandomCoprime to panic by overwriting the CSPRNG inside the group
+func TestRandomCoprime_PanicReadErr(t *testing.T) {
+	p := large.NewInt(5)
+	g := large.NewInt(4)
+	group := NewGroup(p, g)
+
+	// Overwrite CSPRNG
+	group.rng = AlwaysErrorReader{}
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("RandomCoprime should panic on read error")
+		}
+	}()
+
+	group.RandomCoprime(group.NewInt(1))
+}
+
+//Tests whether the z value is prematurely overwritten in the group after RootCoprime is run
+//Tests z value after rootcoprime against a value it's known to be given this input
+func TestRootCoprime_ZVal(t *testing.T) {
+	p := large.NewInt(17)
+	g := large.NewInt(29)
+
+	group := NewGroup(p, g)
+
+	x := group.NewInt(12)
+	z := group.NewInt(12)
+
+	//tmp in rootCoPrime is 1 in this case, so z=x**1
+	group.RootCoprime(x, z, z)
+	if z.value.Cmp(x.value) != 0 {
+		t.Errorf("RootCoprime overwrote z value")
+	}
+
+}
+
+// You pass a value x = a^y to the RootCoprime function, where y is (supposed to be) coprime with (p-1).
+// If y is coprime, then the function returns the value of a
+func TestRootCoprime(t *testing.T) {
+	tests := 2
+	pass := 0
+
+	p := large.NewInt(17)
+	g := large.NewInt(29)
+
+	group := NewGroup(p, g)
+
+	a := []*Int{group.NewInt(5), group.NewInt(4), group.NewInt(15)}
+	x := group.NewInt(1)
+	y := []*Int{group.NewInt(5), group.NewInt(11), group.NewInt(2)}
+	z := []*Int{group.NewInt(1), group.NewInt(1), group.NewInt(1)}
+
+	passing := []bool{true, true, false}
+
+	for i := 0; i < 2; i++ {
+		group.Exp(a[i], y[i], x)
+
+		tmp := group.RootCoprime(x, y[i], z[i])
+		if tmp.value.Cmp(a[i].value) != 0 && passing[i] { //this is wrong, why would z change?
+			t.Errorf("RootCoprime Error: Function did not output expected value! a: %v z: %v", a[i].value.Text(16), z[i].value.Text(16))
+		} else {
+			pass++
+		}
+
+	}
+
+	println("RootCoprime", pass, "out of", tests, "tests passed.")
+}
+
+// Test that RootCoprime panics if cyclicInt doesn't belong to the group
+func TestRootCoprime_Panic(t *testing.T) {
+	prime := int64(107)
+	p := large.NewInt(prime)
+	g := large.NewInt(5)
+	group := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	group2 := NewGroup(p, g2)
+
+	a := group.NewInt(20)
+	b := group.NewInt(11)
+	c := group2.NewInt(1)
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("RootCoprime should panic when one of involved " +
+				"cyclicInts doesn't belong to the group")
+		}
+	}()
+
+	group.RootCoprime(a, b, c)
+}
+
+// Test finding a small coprime inverse number in the group
+func TestFindSmallCoprimeInverse(t *testing.T) {
+	primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+		"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+		"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+		"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+		"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+		"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+		"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+		"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+		"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+		"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+		"15728E5A8AACAA68FFFFFFFFFFFFFFFF"
+
+	p := large.NewIntFromString(primeString, 16)
+	g := large.NewInt(2)
+	group := NewGroup(p, g)
+
+	num := 1000
+
+	totalBitLen := 0
+
+	bits := uint32(256)
+
+	for i := 0; i < num; i++ {
+		z := group.NewInt(1)
+
+		base := group.Random(group.NewInt(1))
+
+		group.FindSmallCoprimeInverse(z, bits)
+
+		zinv := large.NewInt(1).ModInverse(z.value, group.psub1)
+
+		totalBitLen += len(zinv.Bytes()) * 8
+
+		if len(zinv.Bytes())*8 > int(bits) {
+			t.Errorf("FindSmallExponent Error: Inverse too large on "+
+				"attempt %v; Expected: <%v, Recieved: %v", i, bits,
+				uint32(len(zinv.Bytes())*8))
+		}
+
+		baseZ := group.NewInt(1)
+
+		group.Exp(base, z, baseZ)
+
+		basecalc := group.NewInt(1)
+
+		basecalc = group.RootCoprime(baseZ, z, basecalc)
+
+		if base.value.Cmp(basecalc.value) != 0 {
+			t.Errorf("FindSmallExponent Error: Result incorrect"+
+				" on attempt %v; Expected: %s, Recieved: %s", i, base.value.Text(10),
+				basecalc.value.Text(10))
+		}
+	}
+
+	avgBitLen := float32(totalBitLen) / float32(num)
+
+	if float32(avgBitLen) < 0.98*float32(bits) {
+		t.Errorf("FindSmallExponent Error: Inverses are not the correct length on average "+
+			"; Expected: ~%v, Recieved: %v", 0.95*float32(bits), avgBitLen)
+	}
+
+}
+
+// Test finding a small coprime inverse in a group with small p
+// This will hit the case where the generated number equals (p-1)/2
+func TestFindSmallCoprimeInverse_SmallGroup(t *testing.T) {
+	p := large.NewInt(107)
+	g := large.NewInt(2)
+
+	group := NewGroup(p, g)
+	one := large.NewInt(1)
+	num := 1000
+
+	bits := uint32(p.BitLen() - 1)
+
+	for i := 0; i < num; i++ {
+		z := group.NewInt(1)
+
+		base := group.Random(group.NewInt(1))
+
+		// z will be unchanged if a number with no inverse is returned
+		for z.value.Cmp(one) == 0 {
+			group.FindSmallCoprimeInverse(z, bits)
+		}
+
+		zinv := large.NewInt(1).ModInverse(z.value, group.psub1)
+
+		if zinv.BitLen() > int(bits) {
+			t.Errorf("FindSmallExponent Error: Inverse too large on "+
+				"attempt %v; Expected: <%v, Recieved: %v", i, bits,
+				zinv.BitLen())
+		}
+
+		baseZ := group.NewInt(1)
+
+		group.Exp(base, z, baseZ)
+
+		basecalc := group.NewInt(1)
+
+		basecalc = group.RootCoprime(baseZ, z, basecalc)
+
+		if base.value.Cmp(basecalc.value) != 0 {
+			t.Errorf("FindSmallExponent Error: Result incorrect"+
+				" on attempt %v; Expected: %s, Recieved: %s", i, base.value.Text(10),
+				basecalc.value.Text(10))
+		}
+	}
+}
+
+// Test finding a small coprime inverse in an unsafe group, meaning
+// that some numbers don't have an inverse
+func TestFindSmallCoprimeInverse_UnsafeGroup(t *testing.T) {
+	p := large.NewInt(101)
+	g := large.NewInt(2)
+
+	group := NewGroup(p, g)
+	one := large.NewInt(1)
+	num := 1000
+
+	bits := uint32(6)
+
+	for i := 0; i < num; i++ {
+		z := group.NewInt(1)
+
+		base := group.Random(group.NewInt(1))
+
+		// z will be unchanged if a number with no inverse is returned
+		for z.value.Cmp(one) == 0 {
+			group.FindSmallCoprimeInverse(z, bits)
+		}
+
+		zinv := large.NewInt(1).ModInverse(z.value, group.psub1)
+
+		if zinv.BitLen() > int(bits) {
+			t.Errorf("FindSmallExponent Error: Inverse too large on "+
+				"attempt %v; Expected: <%v, Recieved: %v", i, bits,
+				zinv.BitLen())
+		}
+
+		baseZ := group.NewInt(1)
+
+		group.Exp(base, z, baseZ)
+
+		basecalc := group.NewInt(1)
+
+		basecalc = group.RootCoprime(baseZ, z, basecalc)
+
+		if base.value.Cmp(basecalc.value) != 0 {
+			t.Errorf("FindSmallExponent Error: Result incorrect"+
+				" on attempt %v; Expected: %s, Recieved: %s", i, base.value.Text(10),
+				basecalc.value.Text(10))
+		}
+	}
+}
+
+// Test that FindSmallCoprimeInverse panics when number of bits is >= log2(p)
+func TestFindSmallCoprimeInverse_Panic(t *testing.T) {
+	p := large.NewInt(107)
+	g := large.NewInt(2)
+
+	group := NewGroup(p, g)
+	z := group.NewInt(1)
+
+	bits := uint32(7)
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("FindSmallCoprimeInverse should panic on bits >= log2(g.prime)")
+		}
+	}()
+
+	group.FindSmallCoprimeInverse(z, bits)
+}
+
+// Test that FindSmallCoprimeInverse panics if cyclicInt doesn't belong to the group
+func TestFindSmallCoprimeInverse_PanicArgs(t *testing.T) {
+	prime := int64(107)
+	p := large.NewInt(prime)
+	g := large.NewInt(5)
+	group := NewGroup(p, g)
+	g2 := large.NewInt(2)
+	group2 := NewGroup(p, g2)
+
+	a := group2.NewInt(20)
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("RootCoprime should panic when " +
+				"cyclicInt doesn't belong to the group")
+		}
+	}()
+
+	group.FindSmallCoprimeInverse(a, uint32(p.BitLen()-1))
+}
+
+// This test forces FindSmallCoprimeInverse to panic by overwriting the CSPRNG inside the group
+func TestFindSmallCoprimeInverse_PanicReadErr(t *testing.T) {
+	p := large.NewInt(107)
+	g := large.NewInt(2)
+
+	group := NewGroup(p, g)
+
+	bits := uint32(p.BitLen() - 1)
+
+	// Overwrite CSPRNG
+	group.rng = AlwaysErrorReader{}
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("FindSmallCoprimeInverse should panic on read error")
+		}
+	}()
+
+	group.FindSmallCoprimeInverse(group.NewInt(1), bits)
+}
+
+// Tests that a Group structure that is encoded and then decoded, as a
+// gob has the same values.
+func TestGroup_GobEncode_GobDecode(t *testing.T) {
+
+	prime := large.NewInt(1000000010101111111)
+	gen := large.NewInt(5)
+	grp1 := NewGroup(prime, gen)
+
+	b, _ := grp1.GobEncode()
+
+	grp2 := Group{}
+	_ = grp2.GobDecode(b)
+
+	if !reflect.DeepEqual(*grp1, grp2) {
+		t.Errorf("GobDecode() did not produce the the same original undecoded data\n\treceived: %v\n\texpected: %v", grp1, grp2)
+	}
+}
+
+// Tests that a Group structure can be marshaled to JSON and unmarshaled to recreate equivalent group
+func TestGroup_MarshalJSON_IsValid(t *testing.T) {
+
+	prime := large.NewInt(1000000010101111111)
+	gen := large.NewInt(5)
+	grp1 := NewGroup(prime, gen)
+
+	// Marshall to bytes
+	b, err := grp1.MarshalJSON()
+
+	if err != nil {
+		t.Errorf("MarshalJSON() failed to serialize the group: %v", grp1)
+	}
+
+	// Unmarshal from bytes
+	grp2 := Group{}
+	err = grp2.UnmarshalJSON(b)
+
+	if err != nil {
+		t.Errorf("UnmarshalJSON() failed to serialize the group: %v", grp1)
+	}
+
+	if !reflect.DeepEqual(*grp1, grp2) {
+		t.Errorf("UnmarshalJSON() did not produce the the same original undecoded data\n\treceived: %v\n\texpected: %v", grp1, grp2)
+	}
+}
+
+// BENCHMARKS
+
+func BenchmarkExpForGroup2k(b *testing.B) {
+	primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+		"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+		"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+		"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+		"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+		"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+		"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+		"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+		"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+		"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+		"15728E5A8AACAA68FFFFFFFFFFFFFFFF"
+
+	p := large.NewIntFromString(primeString, 16)
+	g := large.NewInt(2)
+	grp := NewGroup(p, g)
+
+	//prebake inputs
+	z := grp.NewInt(1)
+	G := grp.GetGCyclic()
+
+	var inputs []*Int
+	var outputs []*Int
+
+	for i := 0; i < b.N; i++ {
+		nint := grp.Random(grp.NewInt(1))
+		inputs = append(inputs, nint)
+		outputs = append(outputs, grp.NewInt(1))
+	}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		grp.Exp(G, inputs[i], z)
+	}
+}
+
+func BenchmarkExpForGroup4k(b *testing.B) {
+	primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+		"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+		"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+		"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+		"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+		"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+		"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+		"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+		"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+		"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+		"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" +
+		"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" +
+		"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" +
+		"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
+		"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" +
+		"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" +
+		"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" +
+		"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" +
+		"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" +
+		"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" +
+		"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" +
+		"FFFFFFFFFFFFFFFF"
+
+	p := large.NewIntFromString(primeString, 16)
+	g := large.NewInt(2)
+	grp := NewGroup(p, g)
+
+	//prebake inputs
+	z := grp.NewInt(1)
+	G := grp.GetGCyclic()
+
+	var inputs []*Int
+	var outputs []*Int
+
+	for i := 0; i < b.N; i++ {
+		nint := grp.Random(grp.NewInt(1))
+		inputs = append(inputs, nint)
+		outputs = append(outputs, grp.NewInt(1))
+	}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		grp.Exp(G, inputs[i], z)
+	}
+}
+
+func BenchmarkMulForGroup2k(b *testing.B) {
+	primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+		"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+		"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+		"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+		"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+		"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+		"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+		"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+		"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+		"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+		"15728E5A8AACAA68FFFFFFFFFFFFFFFF"
+
+	p := large.NewIntFromString(primeString, 16)
+	g := large.NewInt(2)
+	grp := NewGroup(p, g)
+
+	//prebake inputs
+	z := grp.NewInt(1)
+
+	var inputA []*Int
+	var inputB []*Int
+	var outputs []*Int
+
+	for i := 0; i < b.N; i++ {
+		nint := grp.Random(grp.NewInt(1))
+		inputA = append(inputA, nint)
+		mint := grp.Random(grp.NewInt(1))
+		inputB = append(inputB, mint)
+		outputs = append(outputs, grp.NewInt(1))
+	}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		grp.Mul(inputA[i], inputB[i], z)
+	}
+}
+
+func BenchmarkMulForGroup4k(b *testing.B) {
+	primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+		"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+		"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+		"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+		"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+		"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+		"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+		"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+		"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+		"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+		"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" +
+		"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" +
+		"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" +
+		"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
+		"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" +
+		"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" +
+		"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" +
+		"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" +
+		"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" +
+		"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" +
+		"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" +
+		"FFFFFFFFFFFFFFFF"
+
+	p := large.NewIntFromString(primeString, 16)
+	g := large.NewInt(2)
+	grp := NewGroup(p, g)
+
+	//prebake inputs
+	z := grp.NewInt(1)
+
+	var inputA []*Int
+	var inputB []*Int
+	var outputs []*Int
+
+	for i := 0; i < b.N; i++ {
+		nint := grp.Random(grp.NewInt(1))
+		inputA = append(inputA, nint)
+		mint := grp.Random(grp.NewInt(1))
+		inputB = append(inputB, mint)
+		outputs = append(outputs, grp.NewInt(1))
+	}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		grp.Mul(inputA[i], inputB[i], z)
+	}
+}
+
+func BenchmarkInverse2k(b *testing.B) {
+	primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+		"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+		"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+		"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+		"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+		"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+		"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+		"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+		"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+		"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+		"15728E5A8AACAA68FFFFFFFFFFFFFFFF"
+
+	p := large.NewIntFromString(primeString, 16)
+	g := large.NewInt(2)
+	grp := NewGroup(p, g)
+
+	//prebake inputs
+	z := grp.NewInt(1)
+	G := grp.GetGCyclic()
+
+	var inputs []*Int
+	var outputs []*Int
+
+	for i := 0; i < b.N; i++ {
+		nint := grp.Random(grp.NewInt(1))
+		nint = grp.Exp(G, nint, z)
+		inputs = append(inputs, nint)
+		outputs = append(outputs, grp.NewInt(1))
+	}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		grp.Inverse(inputs[i], outputs[i])
+	}
+}
+
+func BenchmarkInverse4k(b *testing.B) {
+	primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+		"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+		"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+		"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+		"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+		"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+		"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+		"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+		"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+		"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+		"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" +
+		"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" +
+		"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" +
+		"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
+		"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" +
+		"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" +
+		"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" +
+		"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" +
+		"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" +
+		"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" +
+		"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" +
+		"FFFFFFFFFFFFFFFF"
+
+	p := large.NewIntFromString(primeString, 16)
+	g := large.NewInt(2)
+	grp := NewGroup(p, g)
+
+	//prebake inputs
+	z := grp.NewInt(1)
+	G := grp.GetGCyclic()
+
+	var inputs []*Int
+	var outputs []*Int
+
+	for i := 0; i < b.N; i++ {
+		nint := grp.Random(grp.NewInt(1))
+		nint = grp.Exp(G, nint, z)
+		inputs = append(inputs, nint)
+		outputs = append(outputs, grp.NewInt(1))
+	}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		grp.Inverse(inputs[i], outputs[i])
+	}
+}
+
+func TestGroup_BytesInside(t *testing.T) {
+	test1 := []byte{5}
+	test2 := []byte{79}
+	test3 := []byte{17}
+	test4 := []byte{36}
+	grp := NewGroup(large.NewInt(107), large.NewInt(4))
+
+	if !grp.BytesInside(test1, test2, test3, test4) {
+		t.Errorf("BytesInside Failed!")
+	}
+}
diff --git a/cyclic/int.go b/cyclic/int.go
new file mode 100644
index 00000000..f0fc4663
--- /dev/null
+++ b/cyclic/int.go
@@ -0,0 +1,262 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+// Package cyclic wraps our large.Int structure.  It is designed to be used in
+// conjunction with the cyclic.Group object. The cyclic.Group object
+// will provide implementations of various modular operations within the group.
+// A cyclic.IntBuffer type will be created to store large batches of groups.
+package cyclic
+
+import (
+	"bytes"
+	"encoding/base64"
+	"encoding/binary"
+	"encoding/gob"
+	"encoding/json"
+	"github.com/pkg/errors"
+	"gitlab.com/xx_network/crypto/large"
+)
+
+// Create the cyclic.Int type as a wrapper of a large.Int
+// and group fingerprint
+type Int struct {
+	value       *large.Int
+	fingerprint uint64
+}
+
+// ByteLen gets the byte length of cyclic int
+func (z *Int) ByteLen() int {
+	byteLen := z.value.ByteLen()
+	return byteLen
+}
+
+// GetLargeInt gets a deepcopy of the largeInt from cyclicInt
+// This is necessary because otherwise the internal
+// value of the into could be edited and made to be
+// outside the group.
+func (z *Int) GetLargeInt() *large.Int {
+	r := large.NewInt(0)
+	r.Set(z.value)
+	return r
+}
+
+// GetGroupFingerprint gets the group fingerprint from cyclicInt
+func (z *Int) GetGroupFingerprint() uint64 {
+	return z.fingerprint
+}
+
+// Bits gets the underlying word slice of cyclic int
+// Use this for low-level functions where speed is critical
+// For speed reasons, I don't copy here. This could allow the int to be set outside of the group
+func (z *Int) Bits() large.Bits {
+	return z.value.Bits()
+}
+
+// Bytes gets the bytes of cyclicInt value
+func (z *Int) Bytes() []byte {
+	return z.value.Bytes()
+}
+
+// LeftpadBytes gets left padded bytes of cyclicInt value
+func (z *Int) LeftpadBytes(length uint64) []byte {
+	return z.value.LeftpadBytes(length)
+}
+
+// BitLen gets the length of the cyclic int
+func (z *Int) BitLen() int {
+	return z.value.BitLen()
+}
+
+// DeepCopy returns a complete copy of the cyclic int such that no
+// underlying data is linked
+func (z *Int) DeepCopy() *Int {
+	return &Int{
+		z.value.DeepCopy(),
+		z.fingerprint,
+	}
+}
+
+// Compare two cyclicInts
+// returns -2 if fingerprint differs
+// returns value.Cmp otherwise
+func (z *Int) Cmp(x *Int) int {
+	if z.fingerprint != x.fingerprint {
+		return -2
+	}
+	return z.value.Cmp(x.value)
+}
+
+// Reset cyclicInt to 1
+func (z *Int) Reset() {
+	z.value.SetInt64(1)
+}
+
+// Return truncated base64 encoded string of group fingerprint
+func (z *Int) textFingerprint(length int) string {
+	buf := make([]byte, 8)
+	binary.BigEndian.PutUint64(buf, z.fingerprint)
+	fullText := base64.StdEncoding.EncodeToString(buf)
+	if length == 0 || len(fullText) <= length {
+		return fullText
+	} else {
+		return fullText[:length] + "..."
+	}
+}
+
+// Text returns the string representation of z in the given base. Base
+// must be between 2 and 36, inclusive. The result uses the lower-case
+// letters 'a' to 'z' for digit values >= 10. No base prefix (such as
+// "0x") is added to the string.
+// Text truncates ints to a length of 10, appending an ellipsis
+// if the int is too long.
+// The group fingerprint is base64 encoded and also truncated
+// z is then represented as: value... in GRP: fingerprint...
+func (z *Int) Text(base int) string {
+	const intTextLen = 10
+	return z.TextVerbose(base, intTextLen)
+}
+
+// TextVerbose returns the string representation of z in the given base. Base
+// must be between 2 and 36, inclusive. The result uses the lower-case
+// letters 'a' to 'z' for digit values >= 10. No base prefix (such as
+// "0x") is added to the string.
+// TextVerbose truncates ints to a length of length in characters (not runes)
+// and append an ellipsis to indicate that the whole int wasn't returned,
+// unless len is 0, in which case it will return the whole int as a string.
+// The group fingerprint is base64 encoded and also truncated
+// z is then represented as: value... in GRP: fingerprint...
+func (z *Int) TextVerbose(base int, length int) string {
+	valueText := z.value.TextVerbose(base, length)
+	fingerprintText := z.textFingerprint(length)
+	return valueText + " in GRP: " + fingerprintText
+}
+
+// GOB decode bytes to cyclicInt
+func (z *Int) GobDecode(in []byte) error {
+	// anonymous structure
+	s := struct {
+		F []byte
+		V []byte
+	}{
+		make([]byte, 8),
+		[]byte{},
+	}
+
+	var buf bytes.Buffer
+
+	// Write bytes to the buffer
+	buf.Write(in)
+
+	// Create new decoder that reads from the buffer
+	dec := gob.NewDecoder(&buf)
+
+	// Receive and decode data
+	err := dec.Decode(&s)
+
+	if err != nil {
+		return err
+	}
+
+	// Convert decoded bytes and put into empty structure
+	z.value = large.NewIntFromBytes(s.V)
+	z.fingerprint = binary.BigEndian.Uint64(s.F)
+
+	return nil
+}
+
+// GOB encode cyclicInt to bytes
+func (z *Int) GobEncode() ([]byte, error) {
+	// Anonymous structure
+	s := struct {
+		F []byte
+		V []byte
+	}{
+		make([]byte, 8),
+		z.Bytes(),
+	}
+
+	binary.BigEndian.PutUint64(s.F, z.fingerprint)
+	var buf bytes.Buffer
+
+	// Create new encoder that will transmit the buffer
+	enc := gob.NewEncoder(&buf)
+
+	// Transmit the data
+	err := enc.Encode(s)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return buf.Bytes(), nil
+}
+
+// BinaryEncode encodes the Int into a compressed byte format.
+func (z *Int) BinaryEncode() []byte {
+	var buff bytes.Buffer
+	b := make([]byte, 8)
+
+	binary.LittleEndian.PutUint64(b, z.fingerprint)
+	buff.Write(b)
+	buff.Write(z.Bytes())
+
+	return buff.Bytes()
+}
+
+// BinaryDecode decompresses the encoded byte slice to an Int.
+func (z *Int) BinaryDecode(b []byte) error {
+	if len(b) < 8 {
+		return errors.Errorf("length of buffer %d != %d expected", len(b), 8)
+	}
+
+	buff := bytes.NewBuffer(b)
+	z.fingerprint = binary.LittleEndian.Uint64(buff.Next(8))
+	z.value = large.NewIntFromBytes(buff.Bytes())
+	return nil
+}
+
+// Erase overwrite all underlying data from a cyclic Int by setting its value
+// and fingerprint to zero. All underlying released data will be removed by the
+// garbage collector.
+func (z *Int) Erase() {
+	z.value.SetInt64(0)
+	z.fingerprint = 0
+}
+
+// -------------- Marshal Operators -------------- //
+// intData holds the value of a cyclic int in public fields to allow for
+// marshalling and unmarshalling.
+type intData struct {
+	Value       *large.Int
+	Fingerprint uint64
+}
+
+// MarshalJSON is a custom marshaling function for cyclic int. It is used when
+// json.Marshal is called on a large int.
+func (z *Int) MarshalJSON() ([]byte, error) {
+	data := intData{
+		Value:       z.value,
+		Fingerprint: z.fingerprint,
+	}
+
+	return json.Marshal(data)
+}
+
+// UnmarshalJSON is a custom unmarshalling function for cyclic int. It is used
+// when json.Unmarshal is called on a large int.
+func (z *Int) UnmarshalJSON(b []byte) error {
+	data := &intData{}
+	err := json.Unmarshal(b, data)
+	if err != nil {
+		return err
+	}
+
+	z.value = data.Value
+	z.fingerprint = data.Fingerprint
+
+	return nil
+}
diff --git a/cyclic/int_test.go b/cyclic/int_test.go
new file mode 100644
index 00000000..73d625c6
--- /dev/null
+++ b/cyclic/int_test.go
@@ -0,0 +1,363 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+package cyclic
+
+import (
+	"bytes"
+	"encoding/gob"
+	"errors"
+	"gitlab.com/xx_network/crypto/large"
+	"reflect"
+	"testing"
+)
+
+var p = large.NewInt(1000000010101111111)
+var g = large.NewInt(5)
+var grp = NewGroup(p, g)
+
+// Test largeInt getter and show it returns a copy
+func TestGetLargeInt(t *testing.T) {
+	expected := large.NewInt(42)
+
+	actual := grp.NewInt(42)
+
+	if actual.GetLargeInt().Cmp(expected) != 0 {
+		t.Errorf("Test of GetLargeInt failed, expected: '%v', got: '%v'",
+			actual.GetLargeInt(), expected)
+	}
+
+	li := actual.GetLargeInt()
+
+	li.SetInt64(33)
+
+	if actual.GetLargeInt().Cmp(expected) != 0 {
+		t.Errorf("Test of GetLargeInt failed, did not create deep copy")
+	}
+
+}
+
+// Test group fingeprint getter
+func TestGetGroupFingerprint(t *testing.T) {
+
+	expected := grp.GetFingerprint()
+
+	actual := grp.NewInt(int64(42))
+
+	if actual.GetGroupFingerprint() != expected {
+		t.Errorf("Test of GetGroupFingerprint failed, expected: '%v', got: '%v'",
+			actual.GetGroupFingerprint(), expected)
+	}
+}
+
+// Test bytes getter
+func TestBytes(t *testing.T) {
+	expected := []byte{0x2A}
+
+	actual := grp.NewInt(int64(42))
+
+	if !bytes.Equal(actual.Bytes(), expected) {
+		t.Errorf("Test of Bytes failed, expected: '%v', got: '%v'",
+			actual.Bytes(), expected)
+	}
+}
+
+// Test left padded bytes getter
+func TestLeftpadBytes(t *testing.T) {
+	expected := []byte{0x00, 0x00, 0x00, 0x2A}
+
+	actual := grp.NewInt(int64(42))
+
+	if !bytes.Equal(actual.LeftpadBytes(4), expected) {
+		t.Errorf("Test of LeftPadBytes failed, expected: '%v', got: '%v'",
+			actual.LeftpadBytes(4), expected)
+	}
+}
+
+//TestBitLen checks if BitLen works
+func TestBitLen(t *testing.T) {
+	testints := []*Int{
+		grp.NewInt(42),
+		grp.NewInt(6553522),
+		grp.NewInt(7777),
+		grp.NewInt(21234)}
+
+	expectedlens := []int{
+		6,
+		23,
+		13,
+		15}
+
+	for i, tsti := range testints {
+		actual := tsti.BitLen()
+		if actual != expectedlens[i] {
+			t.Errorf("Case %v of BitLen failed, got: '%v', expected: '%v'", i, actual,
+				expectedlens[i])
+		}
+	}
+}
+
+// Tests that the copy returned by deep copy is identical and that editing
+// one does not edit the other
+func TestInt_DeepCopy(t *testing.T) {
+	i := grp.NewInt(55)
+
+	cpy := i.DeepCopy()
+
+	if !reflect.DeepEqual(i, cpy) {
+		t.Errorf("Test of DeepCopy failed, fingerprints did not match "+
+			"expected: '%#v', got: '%#v'", i, cpy)
+	}
+
+	cpy.fingerprint = ^cpy.fingerprint
+
+	cpy.value.SetInt64(42)
+
+	if i.fingerprint == cpy.fingerprint {
+		t.Errorf("Test of DeepCopy failed, fingerprints matched after edit "+
+			"expected: '%#v', got: '%#v'", i.fingerprint, cpy.fingerprint)
+	}
+
+	if reflect.DeepEqual(i.value, cpy.value) {
+		t.Errorf("Test of DeepCopy failed, values matched after edit"+
+			"expected: '%#v', got: '%#v'", i.value.Text(16), cpy.value.Text(16))
+	}
+}
+
+// Test that Cmp works, and that it returns -2 when fingerprints differ
+func TestCmp(t *testing.T) {
+	val1 := grp.NewInt(int64(42))
+	val2 := grp.NewInt(int64(42))
+
+	ret := val1.Cmp(val2)
+
+	if ret != 0 {
+		t.Errorf("Test of Cmp failed, expected: 0, "+
+			"got: '%v'", ret)
+	}
+	// Overwrite group fingerprint and confirm Cmp returns -1
+	val2.fingerprint = uint64(1234)
+
+	ret = val1.Cmp(val2)
+
+	if ret != -2 {
+		t.Errorf("Test of Cmp failed, expected: -2, "+
+			"got: '%v'", ret)
+	}
+}
+
+// Test that Clear works by setting value to 1
+func TestReset(t *testing.T) {
+	actual := grp.NewInt(42)
+	expected := large.NewInt(42)
+
+	// Verify proper initialization to expected
+	if actual.value.Cmp(expected) != 0 {
+		t.Errorf("Value not initialized correctly")
+	}
+
+	// Call reset on cyclic Int
+	actual.Reset()
+	expected = large.NewInt(1)
+
+	// Ensure it is equal to 1
+	if actual.value.Cmp(expected) != 0 {
+		t.Errorf("Test of GetLargeInt failed, expected: '%v', got: '%v'",
+			actual.GetLargeInt(), expected)
+	}
+}
+
+// Test text representation (limited to length of 10)
+func TestText(t *testing.T) {
+	testints := []*Int{
+		grp.NewInt(42),
+		grp.NewInt(6553522),
+		grp.NewIntFromString("8675309182", 10),
+		grp.NewInt(43)}
+	expectedstrs := []string{
+		"42 in GRP: ln9lzlk21/...",
+		"6553522 in GRP: ln9lzlk21/...",
+		"8675309182 in GRP: ln9lzlk21/...",
+		"43 in GRP: ln9lzlk21/..."} // TODO: Should be <nil>, not -42
+
+	for i, tsti := range testints {
+		actual := tsti.Text(10)
+		expected := expectedstrs[i]
+		if actual != expected {
+			t.Errorf("Test of Text failed, got: '%v', expected: '%v'", actual,
+				expected)
+		}
+	}
+}
+
+// Test text verbose representation with different lengths
+func TestTextVerbose(t *testing.T) {
+	p_t := large.NewIntFromString("867530918239450598372829049587118723612836", 10)
+	g_t := large.NewInt(5)
+	group := NewGroup(p_t, g_t)
+
+	testInt := group.NewIntFromString("867530918239450598372829049587", 10)
+	lens := []int{3, 12, 16, 18, 0}
+	expected := []string{
+		"867... in GRP: XND...",
+		"867530918239... in GRP: XNDDRA8PF/4=",
+		"8675309182394505... in GRP: XNDDRA8PF/4=",
+		"867530918239450598... in GRP: XNDDRA8PF/4=",
+		"867530918239450598372829049587 in GRP: XNDDRA8PF/4="}
+
+	for i, testLen := range lens {
+		actual := testInt.TextVerbose(10, testLen)
+		if actual != expected[i] {
+			t.Errorf("Test of TextVerbose failed, got: %v,"+
+				"expected: %v", actual, expected[i])
+		}
+	}
+}
+
+//TestByteLen checks if the ByteLen placeholder exists
+func TestByteLen(t *testing.T) {
+	testints := []*Int{
+		grp.NewInt(1),       //1 bits -->  1 byte   (where +7 works)
+		grp.NewInt(8388608), //24 bits --> 3 bytes  (exactly)
+		grp.NewInt(7777),    //13 bits --> 2 bytes  (where +3 works)
+		grp.NewInt(1002),    //10 bits --> 2 bytes  (where +6 works)
+	}
+
+	expectedlens := []int{
+		1,
+		3,
+		2,
+		2,
+	}
+
+	for i, tsti := range testints {
+		actual := tsti.ByteLen()
+		if actual != expectedlens[i] {
+			t.Errorf("Case %v of ByteLen failed, got: '%v', expected: '%v'", i, actual,
+				expectedlens[i])
+		}
+	}
+}
+
+// Test GOB encoding/decoding
+func TestGob(t *testing.T) {
+	var byteBuf bytes.Buffer
+
+	enc := gob.NewEncoder(&byteBuf)
+	dec := gob.NewDecoder(&byteBuf)
+
+	inInt := grp.NewInt(42)
+
+	err := enc.Encode(inInt)
+
+	if err != nil {
+		t.Errorf("Error GOB Encoding Int: %s", err)
+	}
+
+	outInt := grp.NewInt(1)
+
+	err = dec.Decode(&outInt)
+
+	if err != nil {
+		t.Errorf("Error GOB Decoding Int: %s", err)
+	}
+
+	if inInt.Cmp(outInt) != 0 {
+		t.Errorf("GobEncoder/GobDecoder failed, "+
+			"Expected: %v; Received: %v ",
+			inInt.TextVerbose(10, 12),
+			outInt.TextVerbose(10, 12))
+	}
+}
+
+// Tests that GobDecode() for cyclicInt throws an error for a
+// malformed byte array
+func TestGobDecode_Error(t *testing.T) {
+	inInt := Int{}
+	err := inInt.GobDecode([]byte{})
+
+	if !reflect.DeepEqual(err, errors.New("EOF")) {
+		t.Errorf("GobDecode() did not produce the expected error\n\treceived: %v"+
+			"\n\texpected: %v", err, errors.New("EOF"))
+	}
+}
+
+// Tests that Erase() removes all underlying data from the Int.
+func TestInt_Erase(t *testing.T) {
+	cycInt := grp.NewInt(42)
+	zeroInt := large.NewInt(5).SetInt64(0)
+	cycInt.Erase()
+
+	if !reflect.DeepEqual(cycInt.value, zeroInt) {
+		t.Errorf("Erase() did not properly delete Int's underlying value"+
+			"\n\treceived: %#v\n\texpected: %#v",
+			cycInt.value, zeroInt)
+	}
+
+	if cycInt.fingerprint != 0 {
+		t.Errorf("Erase() did not properly delete Int's underlying fingerprint"+
+			"\n\treceived: %#v\n\texpected: %#v",
+			cycInt.fingerprint, 0)
+	}
+}
+
+// Happy path.
+func TestInt_MarshalJSON_UnmarshalJSON(t *testing.T) {
+	cycInt := grp.NewInt(42)
+	data, err := cycInt.MarshalJSON()
+	if err != nil {
+		t.Errorf("MarshalJSON() returned an error: %+v", err)
+	}
+	outInt := &Int{}
+	err = outInt.UnmarshalJSON(data)
+	if err != nil {
+		t.Errorf("UnmarshalJSON() returned an error: %+v", err)
+	}
+
+	if cycInt.Cmp(outInt) != 0 {
+		t.Errorf("Failed to correctly marshal and unmarshal cyclic int."+
+			"\n\texpected: %s\n\trecieved: %s", cycInt.Text(10), outInt.Text(10))
+	}
+}
+
+// Error path: invalid JSON data.
+func TestInt_UnmarshalJSON(t *testing.T) {
+	data := []byte("invalid JSON")
+	outInt := &Int{}
+	err := outInt.UnmarshalJSON(data)
+	if err == nil {
+		t.Errorf("UnmarshalJSON() did not return an error for invalid JSON.")
+	}
+}
+
+// Happy path.
+func TestInt_BinaryEncode_BinaryDecode(t *testing.T) {
+	cycInt := grp.NewInt(42)
+	buff := cycInt.BinaryEncode()
+	testInt := &Int{}
+	err := testInt.BinaryDecode(buff)
+	if err != nil {
+		t.Errorf("BinaryDecode() returned an error: %+v", err)
+	}
+
+	if cycInt.Cmp(testInt) != 0 {
+		t.Errorf("Failed to encode and decode Int."+
+			"\n\texpected: %s\n\treceived: %s",
+			cycInt.TextVerbose(10, 32), testInt.TextVerbose(10, 32))
+	}
+}
+
+// Error path: buffer not long enough
+func TestInt_BinaryDecode_BuffTooShortErr(t *testing.T) {
+	cycInt := grp.NewInt(42)
+	buff := cycInt.BinaryEncode()
+	testInt := &Int{}
+	err := testInt.BinaryDecode(buff[:2])
+	if err == nil {
+		t.Errorf("BinaryDecode() did not return an error on a buffer that is too short.")
+	}
+}
diff --git a/diffieHellman/dhkx.go b/diffieHellman/dhkx.go
index 89b4e5fa..d7cdf7eb 100644
--- a/diffieHellman/dhkx.go
+++ b/diffieHellman/dhkx.go
@@ -13,8 +13,8 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"io"
 
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/cyclic"
 )
 
 const DefaultPrivateKeyLengthBits = 256
diff --git a/diffieHellman/dhkx_test.go b/diffieHellman/dhkx_test.go
index 62f757b0..05e532ef 100644
--- a/diffieHellman/dhkx_test.go
+++ b/diffieHellman/dhkx_test.go
@@ -9,8 +9,8 @@ package diffieHellman
 
 import (
 	"encoding/hex"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"gitlab.com/xx_network/crypto/large"
 	"testing"
 )
@@ -56,7 +56,7 @@ func TestGeneratePrivateKey(t *testing.T) {
 	}
 }
 
-// tests public keys are generated correctly
+//tests public keys are generated correctly
 func TestGeneratePublicKey(t *testing.T) {
 	const numTests = 50
 
@@ -97,7 +97,7 @@ func TestGeneratePublicKey(t *testing.T) {
 	}
 }
 
-// tests Session keys are generated correctly
+//tests Session keys are generated correctly
 func TestGenerateSessionKey(t *testing.T) {
 	const numTests = 50
 
@@ -196,7 +196,7 @@ func TestCheckPublicKey(t *testing.T) {
 
 }
 
-// benchmarks session key creation
+//benchmarks session key creation
 func BenchmarkCreateDHSessionKey(b *testing.B) {
 	primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
 		"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
diff --git a/dm/selfCipher.go b/dm/selfCipher.go
index 66b08a1e..c774d333 100644
--- a/dm/selfCipher.go
+++ b/dm/selfCipher.go
@@ -13,10 +13,10 @@ import (
 
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/crypto/nike"
 	"gitlab.com/elixxir/crypto/nike/ecdh"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/hash"
 	"golang.org/x/crypto/chacha20poly1305"
 )
 
diff --git a/e2e/auth/encryptDecrypt.go b/e2e/auth/encryptDecrypt.go
index b63d31a5..a2a13865 100644
--- a/e2e/auth/encryptDecrypt.go
+++ b/e2e/auth/encryptDecrypt.go
@@ -8,7 +8,7 @@
 package auth
 
 import (
-	"gitlab.com/xx_network/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/cyclic"
 )
 
 // Encrypts the payload for use in authenticated channels and provides a MAC
@@ -17,7 +17,7 @@ func Encrypt(myPrivKey, partnerPubKey *cyclic.Int, payload []byte,
 	grp *cyclic.Group) (ecrPayload, mac []byte) {
 
 	// Generate the base key
-	authKey, vec := MakeAuthKey(myPrivKey, partnerPubKey, grp)
+	authKey, vec := MakeAuthKey(myPrivKey, partnerPubKey,grp)
 
 	// Encrypt the payload
 	ecrPayload = Crypt(authKey, vec, payload)
diff --git a/e2e/auth/keygen.go b/e2e/auth/keygen.go
index f99b6eb1..a81ff3fd 100644
--- a/e2e/auth/keygen.go
+++ b/e2e/auth/keygen.go
@@ -9,9 +9,9 @@ package auth
 
 import (
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/cyclic"
 	dh "gitlab.com/elixxir/crypto/diffieHellman"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/hash"
 )
 
 // Const string which gets hashed into the auth key
diff --git a/e2e/auth/mac.go b/e2e/auth/mac.go
index 0d311f4f..deff88eb 100644
--- a/e2e/auth/mac.go
+++ b/e2e/auth/mac.go
@@ -14,7 +14,7 @@ package auth
 import (
 	"crypto/hmac"
 
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/hash"
 )
 
 // MakeMac returns the MAC for the given payload.
diff --git a/e2e/auth/negotiationFingerprint.go b/e2e/auth/negotiationFingerprint.go
index 7ba99486..0faf390b 100644
--- a/e2e/auth/negotiationFingerprint.go
+++ b/e2e/auth/negotiationFingerprint.go
@@ -10,8 +10,8 @@ package auth
 import (
 	"github.com/cloudflare/circl/dh/sidh"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 )
 
 const NegotiationFingerprintLen = 32
diff --git a/e2e/auth/negotiationFingerprint_test.go b/e2e/auth/negotiationFingerprint_test.go
index e4a40794..e136f9e2 100644
--- a/e2e/auth/negotiationFingerprint_test.go
+++ b/e2e/auth/negotiationFingerprint_test.go
@@ -10,9 +10,9 @@ package auth
 import (
 	"encoding/base64"
 	"github.com/cloudflare/circl/dh/sidh"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"io"
 	"math/rand"
 	"testing"
diff --git a/e2e/auth/ownership.go b/e2e/auth/ownership.go
index fbe50b54..dd78f531 100644
--- a/e2e/auth/ownership.go
+++ b/e2e/auth/ownership.go
@@ -10,10 +10,10 @@ package auth
 import (
 	"crypto/hmac"
 
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
 )
 
 const ownershipVector = "ownershipVector"
diff --git a/e2e/auth/ownership_test.go b/e2e/auth/ownership_test.go
index 0f392bec..8d83d528 100644
--- a/e2e/auth/ownership_test.go
+++ b/e2e/auth/ownership_test.go
@@ -14,9 +14,9 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/require"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/elixxir/crypto/nike/dh"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"gitlab.com/xx_network/crypto/large"
 )
 
diff --git a/e2e/auth/requestFP.go b/e2e/auth/requestFP.go
index 7bf676aa..a34afe4f 100644
--- a/e2e/auth/requestFP.go
+++ b/e2e/auth/requestFP.go
@@ -8,9 +8,9 @@
 package auth
 
 import (
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
 )
 
 // the auth request fingerprint designates that a message is an auth request
@@ -18,7 +18,7 @@ import (
 
 const authRequestFingerprintVector = "authRequestFingerprintVector"
 
-// Sets the message as an authenticated channel creation message
+//Sets the message as an authenticated channel creation message
 func SetRequestFingerprint(m format.Message, partnerPublicKey *cyclic.Int) {
 
 	//get the key hash
@@ -28,7 +28,7 @@ func SetRequestFingerprint(m format.Message, partnerPublicKey *cyclic.Int) {
 	m.SetKeyFP(keyHash)
 }
 
-// creates a valid auth request fingerprint from a public key
+//creates a valid auth request fingerprint from a public key
 func MakeRequestFingerprint(publicKey *cyclic.Int) format.Fingerprint {
 	// Create new hash
 	//suppress because we just panic and a nil hash will panic anyhow
diff --git a/e2e/dummykeygen.go b/e2e/dummykeygen.go
index 2cd81d5c..8a497e4a 100644
--- a/e2e/dummykeygen.go
+++ b/e2e/dummykeygen.go
@@ -11,8 +11,8 @@ package e2e
 
 import (
 	"bytes"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/xx_network/primitives/id"
 	goHash "hash"
 )
diff --git a/e2e/dummykeygen_test.go b/e2e/dummykeygen_test.go
index 478736a3..9fceec39 100644
--- a/e2e/dummykeygen_test.go
+++ b/e2e/dummykeygen_test.go
@@ -8,7 +8,7 @@
 package e2e
 
 import (
-	"gitlab.com/xx_network/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/primitives/id"
 	"os"
diff --git a/e2e/encryptionChecker.go b/e2e/encryptionChecker.go
index 167f779b..e09bf5bf 100644
--- a/e2e/encryptionChecker.go
+++ b/e2e/encryptionChecker.go
@@ -13,8 +13,8 @@ import (
 	"crypto/hmac"
 
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/hash"
 	"gitlab.com/xx_network/primitives/id"
 )
 
diff --git a/e2e/encryptionChecker_test.go b/e2e/encryptionChecker_test.go
index 1c5ae752..04a6f611 100644
--- a/e2e/encryptionChecker_test.go
+++ b/e2e/encryptionChecker_test.go
@@ -12,8 +12,8 @@ import (
 	"math/rand"
 	"testing"
 
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/hash"
 	"gitlab.com/xx_network/primitives/id"
 )
 
diff --git a/e2e/keys.go b/e2e/keys.go
index 2afcf5dd..f6c4c5d4 100644
--- a/e2e/keys.go
+++ b/e2e/keys.go
@@ -11,8 +11,8 @@ package e2e
 
 import (
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"golang.org/x/crypto/blake2b"
 )
 
diff --git a/e2e/keys_test.go b/e2e/keys_test.go
index a01bd330..32a00338 100644
--- a/e2e/keys_test.go
+++ b/e2e/keys_test.go
@@ -11,14 +11,14 @@ import (
 	"bytes"
 	"encoding/base64"
 	"fmt"
-	"gitlab.com/xx_network/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/primitives/id"
 	"math/rand"
 	"reflect"
 	"testing"
 )
 
-// test consistency for DeriveKey
+//test consistency for DeriveKey
 func TestDeriveKey_Consistency(t *testing.T) {
 	expectedKeys := []string{
 		"2gQs27wW7ckb6zGUBibdyYs6/aBqJxK2YFW6hToO2EI=",
@@ -76,7 +76,7 @@ func TestDeriveKey_Consistency_doubleSalt(t *testing.T) {
 	deriveConsistencyTester(t, expectedKeys, d, "DeriveKey()")
 }
 
-// test consistency for DeriveKeyFingerprint
+//test consistency for DeriveKeyFingerprint
 func TestDeriveKeyFingerprint_Consistency(t *testing.T) {
 	expectedKeys := []string{
 		"biUwFTuy+udrvH9iMCjBfen4seZAC9Q/5yZMwtVVTyk=",
@@ -126,7 +126,7 @@ func deriveConsistencyTester(t *testing.T, expectedKeys []string, d func(dhkey *
 	}
 }
 
-// verifies that all derived fingerprints and keys are different
+//verifies that all derived fingerprints and keys are different
 func TestAllDifferent(t *testing.T) {
 	const numtests = 25
 
diff --git a/e2e/messageID.go b/e2e/messageID.go
index eddf72a5..31cf853f 100644
--- a/e2e/messageID.go
+++ b/e2e/messageID.go
@@ -12,7 +12,7 @@ import (
 	"encoding/binary"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/hash"
 )
 
 const MessageIDLen = 32
diff --git a/e2e/relationshipFingerprint.go b/e2e/relationshipFingerprint.go
index 2bfc2414..f2d8aa0e 100644
--- a/e2e/relationshipFingerprint.go
+++ b/e2e/relationshipFingerprint.go
@@ -9,8 +9,8 @@ package e2e
 
 import (
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/xx_network/primitives/id"
 )
 
diff --git a/e2e/relationshipFingerprint_test.go b/e2e/relationshipFingerprint_test.go
index 37dbd615..1ca37c58 100644
--- a/e2e/relationshipFingerprint_test.go
+++ b/e2e/relationshipFingerprint_test.go
@@ -9,13 +9,13 @@ package e2e
 
 import (
 	"bytes"
-	"gitlab.com/xx_network/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/primitives/id"
 	"testing"
 )
 
-// show that every input changes the output hash
+//show that every input changes the output hash
 func TestMakeRelationshipFingerprint(t *testing.T) {
 	grp := getGroup()
 
diff --git a/e2e/residue.go b/e2e/residue.go
index bddd20ff..29b1e3ad 100644
--- a/e2e/residue.go
+++ b/e2e/residue.go
@@ -10,7 +10,7 @@ package e2e
 import (
 	"encoding/base64"
 	"github.com/pkg/errors"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/hash"
 )
 
 // KeyResidue generation constants.
diff --git a/e2e/singleUse/mac.go b/e2e/singleUse/mac.go
index ab19c062..601b085e 100644
--- a/e2e/singleUse/mac.go
+++ b/e2e/singleUse/mac.go
@@ -10,7 +10,7 @@ package singleUse
 import (
 	"crypto/hmac"
 
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/hash"
 )
 
 const macSalt = "singleUseMacSalt"
diff --git a/e2e/singleUse/mac_test.go b/e2e/singleUse/mac_test.go
index b6cc5b97..c884a83f 100644
--- a/e2e/singleUse/mac_test.go
+++ b/e2e/singleUse/mac_test.go
@@ -9,7 +9,7 @@ package singleUse
 
 import (
 	"encoding/base64"
-	"gitlab.com/xx_network/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/crypto/large"
 	"math/rand"
 	"testing"
diff --git a/e2e/singleUse/recipientID.go b/e2e/singleUse/recipientID.go
index e5e52dc5..84c048b8 100644
--- a/e2e/singleUse/recipientID.go
+++ b/e2e/singleUse/recipientID.go
@@ -9,8 +9,8 @@ package singleUse
 
 import (
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/xx_network/primitives/id"
 )
 
diff --git a/e2e/singleUse/recipientID_test.go b/e2e/singleUse/recipientID_test.go
index e62c4b36..5a25c553 100644
--- a/e2e/singleUse/recipientID_test.go
+++ b/e2e/singleUse/recipientID_test.go
@@ -8,8 +8,8 @@
 package singleUse
 
 import (
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"gitlab.com/xx_network/primitives/id"
 	"math/rand"
 	"testing"
diff --git a/e2e/singleUse/requestFingerprint.go b/e2e/singleUse/requestFingerprint.go
index c9802757..73a02ce5 100644
--- a/e2e/singleUse/requestFingerprint.go
+++ b/e2e/singleUse/requestFingerprint.go
@@ -9,9 +9,9 @@ package singleUse
 
 import (
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
 )
 
 const requestFpSalt = "singleUseTransmitFingerprintSalt"
diff --git a/e2e/singleUse/requestFingerprint_test.go b/e2e/singleUse/requestFingerprint_test.go
index 4925809a..e90fa2e0 100644
--- a/e2e/singleUse/requestFingerprint_test.go
+++ b/e2e/singleUse/requestFingerprint_test.go
@@ -9,9 +9,9 @@ package singleUse
 
 import (
 	"encoding/base64"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"math/rand"
 	"testing"
 )
diff --git a/e2e/singleUse/requestKey.go b/e2e/singleUse/requestKey.go
index 00915546..d2ce4be1 100644
--- a/e2e/singleUse/requestKey.go
+++ b/e2e/singleUse/requestKey.go
@@ -9,8 +9,8 @@ package singleUse
 
 import (
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 )
 
 const requestKeySalt = "singleUseTransmitKeySalt"
diff --git a/e2e/singleUse/requestKey_test.go b/e2e/singleUse/requestKey_test.go
index 4333288a..e0162c5e 100644
--- a/e2e/singleUse/requestKey_test.go
+++ b/e2e/singleUse/requestKey_test.go
@@ -9,8 +9,8 @@ package singleUse
 
 import (
 	"encoding/base64"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"math/rand"
 	"testing"
 )
diff --git a/e2e/singleUse/requestPartFingerprint.go b/e2e/singleUse/requestPartFingerprint.go
index 1b9ae275..0990325f 100644
--- a/e2e/singleUse/requestPartFingerprint.go
+++ b/e2e/singleUse/requestPartFingerprint.go
@@ -10,9 +10,9 @@ package singleUse
 import (
 	"encoding/binary"
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
 )
 
 const requestPartFpSalt = "singleUseRequestFingerprintSalt"
diff --git a/e2e/singleUse/requestPartFingerprint_test.go b/e2e/singleUse/requestPartFingerprint_test.go
index 6a7e4361..4d91249f 100644
--- a/e2e/singleUse/requestPartFingerprint_test.go
+++ b/e2e/singleUse/requestPartFingerprint_test.go
@@ -9,9 +9,9 @@ package singleUse
 
 import (
 	"encoding/base64"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"math/rand"
 	"testing"
 )
diff --git a/e2e/singleUse/requestPartKey.go b/e2e/singleUse/requestPartKey.go
index 3334ade7..b984efe4 100644
--- a/e2e/singleUse/requestPartKey.go
+++ b/e2e/singleUse/requestPartKey.go
@@ -10,8 +10,8 @@ package singleUse
 import (
 	"encoding/binary"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 )
 
 const requestPartKeySalt = "singleUseRequestKeySalt"
diff --git a/e2e/singleUse/requestPartKey_test.go b/e2e/singleUse/requestPartKey_test.go
index 5bf5fc25..492751f9 100644
--- a/e2e/singleUse/requestPartKey_test.go
+++ b/e2e/singleUse/requestPartKey_test.go
@@ -9,8 +9,8 @@ package singleUse
 
 import (
 	"encoding/base64"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"math/rand"
 	"testing"
 )
diff --git a/e2e/singleUse/responseFingerprint.go b/e2e/singleUse/responseFingerprint.go
index 517c7d56..4f8273b5 100644
--- a/e2e/singleUse/responseFingerprint.go
+++ b/e2e/singleUse/responseFingerprint.go
@@ -10,9 +10,9 @@ package singleUse
 import (
 	"encoding/binary"
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
 )
 
 const responseFpSalt = "singleUseResponseFingerprintSalt"
diff --git a/e2e/singleUse/responseFingerprint_test.go b/e2e/singleUse/responseFingerprint_test.go
index 61f487c9..75bb22fa 100644
--- a/e2e/singleUse/responseFingerprint_test.go
+++ b/e2e/singleUse/responseFingerprint_test.go
@@ -9,9 +9,9 @@ package singleUse
 
 import (
 	"encoding/base64"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"math/rand"
 	"testing"
 )
diff --git a/e2e/singleUse/responseKey.go b/e2e/singleUse/responseKey.go
index 14dc3a2d..e89c3f6d 100644
--- a/e2e/singleUse/responseKey.go
+++ b/e2e/singleUse/responseKey.go
@@ -10,8 +10,8 @@ package singleUse
 import (
 	"encoding/binary"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 )
 
 const responseKeySalt = "singleUseResponseKeySalt"
diff --git a/e2e/singleUse/responseKey_test.go b/e2e/singleUse/responseKey_test.go
index 3fb8238d..3dcae7bb 100644
--- a/e2e/singleUse/responseKey_test.go
+++ b/e2e/singleUse/responseKey_test.go
@@ -9,8 +9,8 @@ package singleUse
 
 import (
 	"encoding/base64"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"math/rand"
 	"testing"
 )
diff --git a/e2e/singleUse/tagFingerprint.go b/e2e/singleUse/tagFingerprint.go
index dc80066f..0bc037f7 100644
--- a/e2e/singleUse/tagFingerprint.go
+++ b/e2e/singleUse/tagFingerprint.go
@@ -10,7 +10,7 @@ package singleUse
 import (
 	"encoding/base64"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/hash"
 )
 
 const tagFpSalt = "singleUseTagFingerprintSalt"
diff --git a/e2e/ttl.go b/e2e/ttl.go
index 845cf9bc..d671bbc8 100644
--- a/e2e/ttl.go
+++ b/e2e/ttl.go
@@ -12,7 +12,7 @@ package e2e
 import (
 	"encoding/binary"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/xx_network/crypto/large"
 	"math"
 )
diff --git a/fileTransfer/fingerprint.go b/fileTransfer/fingerprint.go
index 764c12cd..c629a237 100644
--- a/fileTransfer/fingerprint.go
+++ b/fileTransfer/fingerprint.go
@@ -15,8 +15,8 @@ package fileTransfer
 
 import (
 	"encoding/binary"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/hash"
 )
 
 const fingerprintVector = "FileTransferKeyFingerprint"
diff --git a/fileTransfer/keyGen.go b/fileTransfer/keyGen.go
index 64c9d931..ac5a8633 100644
--- a/fileTransfer/keyGen.go
+++ b/fileTransfer/keyGen.go
@@ -20,8 +20,8 @@ import (
 	"encoding/binary"
 	"encoding/json"
 	"github.com/pkg/errors"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/hash"
 )
 
 // Key length constants, in bytes.
diff --git a/fileTransfer/mac.go b/fileTransfer/mac.go
index 2663854b..75688d0a 100644
--- a/fileTransfer/mac.go
+++ b/fileTransfer/mac.go
@@ -18,7 +18,7 @@ package fileTransfer
 import (
 	"crypto/hmac"
 
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/hash"
 )
 
 // CreateTransferMAC creates a MAC for the entire file. This is for consistency
diff --git a/go.mod b/go.mod
index 0d70baa4..7fc72568 100644
--- a/go.mod
+++ b/go.mod
@@ -14,7 +14,7 @@ require (
 	github.com/spf13/jwalterweatherman v1.1.0
 	github.com/stretchr/testify v1.8.1
 	gitlab.com/elixxir/primitives v0.0.3-0.20230109222259-f62b2a90b62c
-	gitlab.com/xx_network/crypto v0.0.5-0.20230120192824-c0516b176d84
+	gitlab.com/xx_network/crypto v0.0.5-0.20230120185816-1788861281c9
 	gitlab.com/xx_network/primitives v0.0.4-0.20221219230308-4b5550a9247d
 	gitlab.com/yawning/nyquist.git v0.0.0-20221003103146-de5645224a22
 	golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
diff --git a/go.sum b/go.sum
index 75fbc959..958f24d4 100644
--- a/go.sum
+++ b/go.sum
@@ -61,8 +61,6 @@ gitlab.com/xx_network/crypto v0.0.5-0.20230113190331-06f2eb12b97f h1:fY97KmNOyH1
 gitlab.com/xx_network/crypto v0.0.5-0.20230113190331-06f2eb12b97f/go.mod h1:1zOTNhUZmMrus0eI227vWggdKJLeMvMPXcxm29dgt1Q=
 gitlab.com/xx_network/crypto v0.0.5-0.20230120185816-1788861281c9 h1:zYAU/+zKmBTpyOJpupKVAzT+qr/DCLeLVjXV9UmEDZs=
 gitlab.com/xx_network/crypto v0.0.5-0.20230120185816-1788861281c9/go.mod h1:YXQqutM8DxFihrirM5fgippte9dsFq3TZlSlLt0hXy0=
-gitlab.com/xx_network/crypto v0.0.5-0.20230120192824-c0516b176d84 h1:oYwG7zCbR6otwgxQg0x+rbQtOfAQ577aobu/OaJzWkY=
-gitlab.com/xx_network/crypto v0.0.5-0.20230120192824-c0516b176d84/go.mod h1:YXQqutM8DxFihrirM5fgippte9dsFq3TZlSlLt0hXy0=
 gitlab.com/xx_network/primitives v0.0.4-0.20221219230308-4b5550a9247d h1:D9hEtiQ7xj0yFBkDkb4X4S95RfNoeXxtB1eE4UuFHtk=
 gitlab.com/xx_network/primitives v0.0.4-0.20221219230308-4b5550a9247d/go.mod h1:wUxbEBGOBJZ/RkAiVAltlC1uIlIrU0dE113Nq7HiOhw=
 gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo=
diff --git a/group/mac.go b/group/mac.go
index 064f8f77..44712bbe 100644
--- a/group/mac.go
+++ b/group/mac.go
@@ -13,8 +13,8 @@ package group
 import (
 	"crypto/hmac"
 
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/hash"
 )
 
 // NewMAC generates a MAC for the encrypted internal message and the recipient's
diff --git a/group/membership.go b/group/membership.go
index 3cb183d1..293c376c 100644
--- a/group/membership.go
+++ b/group/membership.go
@@ -16,7 +16,7 @@ import (
 	"encoding/binary"
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/crypto/contact"
-	"gitlab.com/xx_network/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/primitives/id"
 	"golang.org/x/crypto/blake2b"
 	"sort"
diff --git a/group/membership_test.go b/group/membership_test.go
index 58d79510..039aaf25 100644
--- a/group/membership_test.go
+++ b/group/membership_test.go
@@ -13,8 +13,8 @@ import (
 	"encoding/binary"
 	"fmt"
 	"gitlab.com/elixxir/crypto/contact"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/shuffle"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/primitives/id"
 	"math/rand"
diff --git a/hash/hash.go b/hash/hash.go
new file mode 100644
index 00000000..cdb0fafd
--- /dev/null
+++ b/hash/hash.go
@@ -0,0 +1,65 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+// Package hash includes a general-purpose hashing algorithm, blake2b,
+// that should be suitable for most of our needs.
+// It also includes functions to calculate an HMAC.
+package hash
+
+import (
+	"crypto"
+	"crypto/hmac"
+	"crypto/sha256"
+	jww "github.com/spf13/jwalterweatherman"
+	"golang.org/x/crypto/blake2b"
+	"hash"
+)
+
+// NewCMixHash returns the current cMix hash implementation
+// which is currently the 256 bit version of blake2b
+func NewCMixHash() (hash.Hash, error) {
+
+	return blake2b.New256(nil)
+}
+
+// DefaultHash returns a CMIX hash or panics
+func DefaultHash() hash.Hash {
+	h, err := blake2b.New256(nil)
+	if err != nil {
+		jww.FATAL.Panicf("Could not initialize blake2b: %+v", err)
+	}
+	return h
+}
+
+// CMixHash type is currently BLAKE2b_256
+var CMixHash = crypto.BLAKE2b_256
+
+// NewHMAC creates a new Message Authentication Code from a message payload and a key.
+// This function does not accept keys that are less than 256 bits (or 32 bytes)
+// *Function was copied from (https://golang.org/pkg/crypto/hmac/), we need to analyze this again in the future *
+func CreateHMAC(message, key []byte) []byte {
+
+	h := hmac.New(sha256.New, key)
+	h.Write(message)
+
+	hMAC := h.Sum(nil)
+
+	// blank out the first first bit in order to ensure the group is satisfied
+	// in the message payload.  See primitives/format/message.go for more details
+	hMAC[0] &= 0x7F
+
+	return hMAC
+}
+
+// CheckHMAC receives a MAC value along with the respective message and key associated with the Msg Authentication Code
+// Returns true if calculated MAC matches the received one. False if not.
+// *Function was copied from (https://golang.org/pkg/crypto/hmac/), we need to analyze this again in the future *
+func VerifyHMAC(message, MAC, key []byte) bool {
+	expectedMAC := CreateHMAC(message, key)
+
+	return hmac.Equal(MAC, expectedMAC)
+}
diff --git a/hash/hash_test.go b/hash/hash_test.go
new file mode 100644
index 00000000..b0ed7948
--- /dev/null
+++ b/hash/hash_test.go
@@ -0,0 +1,64 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+package hash
+
+import (
+	"encoding/hex"
+	"testing"
+)
+
+// TestNewCMixHash tests that we get the expected value for the cmix hash
+func TestNewCMixHash(t *testing.T) {
+	expected := []byte{
+		72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33, 14, 87, 81,
+		192, 38, 229, 67, 178, 232, 171, 46, 176, 96, 153, 218, 161, 209, 229,
+		223, 71, 119, 143, 119, 135, 250, 171, 69, 205, 241, 47, 227, 168}
+	h, err := NewCMixHash()
+	if err != nil {
+		t.Errorf("NewCMixHash failed: %v", err)
+	}
+
+	actual := h.Sum([]byte("Hello, World!"))
+
+	for i, b := range actual {
+		if b != expected[i] {
+			t.Errorf("NewCMixHash byte %v failed, expected: '%v', got: '%v'",
+				i, expected, actual)
+		}
+	}
+}
+
+// TestHMAC tests that we get the expected value for the payload "Mario" and a key "key"
+func TestHMAC(t *testing.T) {
+	payload := []byte("Mario")
+	key := []byte("a906df88f30d6afbfa6165a50cc9e208d16b34e70b367068dc5d6bd6e155b2c3")
+
+	hmac1 := CreateHMAC(payload, key)
+	expectedHMAC := "0b716229f4920f70265ee25045d3dc01f40ec423c4da97d249ca9c0dd146693e"
+
+	if hex.EncodeToString(hmac1) != expectedHMAC {
+		t.Errorf("TestHMAC(): Error 1: MACs should have matched!")
+	}
+
+	if !VerifyHMAC(payload, hmac1, key) {
+		t.Errorf("TestHMAC(): Error 2: MACs should have matched!")
+	}
+}
+
+// tests that the first bit is blanked when we have a leading 1 on
+// the output
+func TestHMAC_LeadingOne(t *testing.T) {
+	payload := []byte("ARO00OOO")
+	key := []byte("a906df88f30d6afbfa6165a50cc9e208d16b34e70b367068dc5d6bd6e155b2c3")
+
+	hmac1 := CreateHMAC(payload, key)
+
+	if hmac1[0]>>7 != 0 {
+		t.Errorf("First bit not blanked!")
+	}
+}
diff --git a/hash/keys.go b/hash/keys.go
new file mode 100644
index 00000000..5addc49e
--- /dev/null
+++ b/hash/keys.go
@@ -0,0 +1,43 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+// Package hash includes a general-purpose hashing algorithm, blake2b,
+// that should be suitable for most of our needs.
+// It also includes functions to calculate an HMAC.
+package hash
+
+import (
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/crypto/large"
+	"golang.org/x/crypto/hkdf"
+	"hash"
+)
+
+type NewHash interface {
+	New() hash.Hash
+}
+
+// ExpandKey is a function that receives a key and expands such key to the size
+// of the prime group
+func ExpandKey(h func() hash.Hash, g *cyclic.Group, key []byte,
+	output *cyclic.Int) *cyclic.Int {
+	keyGen := hkdf.Expand(h, key, nil)
+
+	pBytes := g.GetPBytes()
+	expandedKey, err := csprng.GenerateInGroup(pBytes, len(pBytes), keyGen)
+	if err != nil {
+		jww.FATAL.Panicf("Key expansion failure: %v", err)
+	}
+
+	keyInt := large.NewInt(0)
+	keyInt.SetBytes(expandedKey)
+	g.SetLargeInt(output, keyInt)
+
+	return output
+}
diff --git a/hash/keys_test.go b/hash/keys_test.go
new file mode 100644
index 00000000..85144fea
--- /dev/null
+++ b/hash/keys_test.go
@@ -0,0 +1,81 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+package hash
+
+import (
+	"crypto/sha512"
+	"encoding/hex"
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/xx_network/crypto/large"
+	"hash"
+	"testing"
+)
+
+var primeString = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+	"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+	"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+	"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+	"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+	"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+	"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+	"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+	"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+	"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+	"15728E5A8AACAA68FFFFFFFFFFFFFFFF"
+
+var p = large.NewIntFromString(primeString, 16)
+var g = large.NewInt(2)
+var grp = cyclic.NewGroup(p, g)
+
+//TestExpandKey verifies ExpandKey with two different hashes
+func TestExpandKey(t *testing.T) {
+	test := 4
+	pass := 0
+
+	key := []byte("a906df88f30d6afbfa6165a50cc9e208d16b34e70b367068dc5d6bd6e155b2c3")
+
+	hashFunc := func() hash.Hash {
+		h, _ := NewCMixHash()
+		return h
+	}
+	x1 := ExpandKey(hashFunc, grp, []byte("key"), grp.NewInt(1))
+	x2 := ExpandKey(hashFunc, grp, key, grp.NewInt(1))
+
+	if x1.BitLen()/8 != 256 {
+		t.Errorf("TestExpandKey(): Error with the resulting key size")
+	} else {
+		pass++
+	}
+
+	if hex.EncodeToString(x1.Bytes()) != hex.EncodeToString(x2.Bytes()) {
+		pass++
+	} else {
+		t.Errorf("TestExpandKey():Error in the Key Expansion. Keys should not be the same!")
+	}
+
+	hashFunc = func() hash.Hash {
+		return sha512.New()
+	}
+	x1 = ExpandKey(hashFunc, grp, []byte("key"), grp.NewInt(1))
+	x2 = ExpandKey(hashFunc, grp, key, grp.NewInt(1))
+
+	if x1.BitLen()/8 != 255 {
+		t.Errorf("TestExpandKey(): Error with the resulting key size."+
+			"\nexpected: %d\nreceived: %d", 256, x1.BitLen()/8)
+	} else {
+		pass++
+	}
+
+	if hex.EncodeToString(x1.Bytes()) != hex.EncodeToString(x2.Bytes()) {
+		pass++
+	} else {
+		t.Errorf("TestExpandKey():Error in the Key Expansion. Keys should not be the same!")
+	}
+
+	println("TestExpandKey():", pass, "out of", test, "tests passed")
+}
diff --git a/message/id.go b/message/id.go
index 9a1c6fb4..34f03123 100644
--- a/message/id.go
+++ b/message/id.go
@@ -14,7 +14,7 @@ import (
 	"encoding/json"
 
 	"github.com/pkg/errors"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/xx_network/primitives/id"
 )
 
diff --git a/nike/dh/dh.go b/nike/dh/dh.go
index 8f5abdfe..75391177 100644
--- a/nike/dh/dh.go
+++ b/nike/dh/dh.go
@@ -14,8 +14,8 @@ import (
 
 	"gitlab.com/xx_network/crypto/large"
 
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
-	"gitlab.com/xx_network/crypto/cyclic"
 )
 
 const (
diff --git a/registration/hmac_test.go b/registration/hmac_test.go
index 35acc223..540aa6c8 100644
--- a/registration/hmac_test.go
+++ b/registration/hmac_test.go
@@ -9,7 +9,7 @@ package registration
 
 import (
 	"bytes"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/hash"
 	"testing"
 )
 
diff --git a/registration/keygen.go b/registration/keygen.go
index d9178cc4..0adc8d37 100644
--- a/registration/keygen.go
+++ b/registration/keygen.go
@@ -10,8 +10,8 @@
 package registration
 
 import (
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
-	"gitlab.com/xx_network/crypto/cyclic"
 	"hash"
 )
 
diff --git a/registration/keygen_test.go b/registration/keygen_test.go
index 1a4a323d..4d030a4e 100644
--- a/registration/keygen_test.go
+++ b/registration/keygen_test.go
@@ -9,9 +9,9 @@ package registration
 
 import (
 	"crypto/sha256"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
-	"gitlab.com/xx_network/crypto/cyclic"
-	"gitlab.com/xx_network/crypto/hash"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/xx_network/crypto/large"
 	"math/rand"
 	"testing"
-- 
GitLab