From 906f272e352735558cfb8bdee8307f4362c21d71 Mon Sep 17 00:00:00 2001 From: _dssei_ Date: Wed, 9 Oct 2024 14:48:15 -0700 Subject: [PATCH] - Only allow ED25519 curve for now, but cache it to reduce amount of init calls - add marshaling test --- pkg/encryption/elgamal/encryption.go | 21 +--- pkg/encryption/elgamal/encryption_test.go | 122 ++++++---------------- pkg/encryption/elgamal/types.go | 7 +- pkg/encryption/elgamal/types_test.go | 31 ++++++ 4 files changed, 70 insertions(+), 111 deletions(-) create mode 100644 pkg/encryption/elgamal/types_test.go diff --git a/pkg/encryption/elgamal/encryption.go b/pkg/encryption/elgamal/encryption.go index 33ba03c..29caeb0 100644 --- a/pkg/encryption/elgamal/encryption.go +++ b/pkg/encryption/elgamal/encryption.go @@ -16,7 +16,8 @@ type TwistedElGamal struct { maxMapping map[MaxBits]bool } -func NewTwistedElgamalWithED25519Curve() *TwistedElGamal { +// NewTwistedElgamal creates a new TwistedElGamal instance with ED25519 curve. +func NewTwistedElgamal() *TwistedElGamal { var s ristretto.Point s.SetZero() mapping := make(map[string]uint64) @@ -30,30 +31,16 @@ func NewTwistedElgamalWithED25519Curve() *TwistedElGamal { } } -func NewTwistedElgamal(curve *curves.Curve) *TwistedElGamal { - var s ristretto.Point - s.SetZero() - mapping := make(map[string]uint64) - maxMapping := make(map[MaxBits]bool) - mapping[s.String()] = 0 - - return &TwistedElGamal{ - curve: curve, - maxMapping: maxMapping, - mapping: mapping, - } -} - // Encrypt encrypts a message using the public key pk. func (teg TwistedElGamal) Encrypt(pk curves.Point, message uint64) (*Ciphertext, curves.Scalar, error) { // Generate a random scalar r randomFactor := teg.curve.Scalar.Random(crand.Reader) - return teg.EncryptWithRand(pk, message, randomFactor) + return teg.encryptWithRand(pk, message, randomFactor) } // EncryptWithRand encrypts a message using the public key pk and a given random factor. -func (teg TwistedElGamal) EncryptWithRand(pk curves.Point, message uint64, randomFactor curves.Scalar) (*Ciphertext, curves.Scalar, error) { +func (teg TwistedElGamal) encryptWithRand(pk curves.Point, message uint64, randomFactor curves.Scalar) (*Ciphertext, curves.Scalar, error) { if pk == nil { return nil, nil, fmt.Errorf("invalid public key") } diff --git a/pkg/encryption/elgamal/encryption_test.go b/pkg/encryption/elgamal/encryption_test.go index ced2d3d..57e15fb 100644 --- a/pkg/encryption/elgamal/encryption_test.go +++ b/pkg/encryption/elgamal/encryption_test.go @@ -20,40 +20,7 @@ func TestKeyGeneration(t *testing.T) { privateKey, err := generateKey() require.Nil(t, err) - eg := NewTwistedElgamalWithED25519Curve() - keyPair, err := eg.KeyGen(*privateKey, DefaultTestDenom) - require.Nil(t, err) - - // Test that keyPair is deterministically generated - keyPairAgain, err := eg.KeyGen(*privateKey, DefaultTestDenom) - require.Nil(t, err) - require.Equal(t, keyPair, keyPairAgain, "PK should be deterministically generated") - - // Test that changing the salt should generate a different key - altDenom := "factory/sei1239081236470/testToken1" - keyPairDiffSalt, err := eg.KeyGen(*privateKey, altDenom) - require.Nil(t, err) - require.NotEqual(t, keyPair, keyPairDiffSalt, "PK should be different for different salt") - - // Test same thing for salt of same length - altDenom = "factory/sei1239081236470/testTokeN" - keyPairDiffSalt, err = eg.KeyGen(*privateKey, altDenom) - require.Nil(t, err) - require.NotEqual(t, keyPair, keyPairDiffSalt, "PK should be different for different salt") - - // Test that different privateKey should generate different PK - altPrivateKey, err := generateKey() - require.Nil(t, err) - keyPairDiffPK, err := eg.KeyGen(*altPrivateKey, altDenom) - require.Nil(t, err) - require.NotEqual(t, keyPair, keyPairDiffPK, "PK should be different for different ESDCA Private Key") -} - -func TestKeyGenerationBLS12377G1Curve(t *testing.T) { - privateKey, err := generateKey() - require.Nil(t, err) - - eg := NewTwistedElgamal(curves.BLS12377G1()) + eg := NewTwistedElgamal() keyPair, err := eg.KeyGen(*privateKey, DefaultTestDenom) require.Nil(t, err) @@ -86,42 +53,7 @@ func TestEncryptionDecryption(t *testing.T) { privateKey, _ := generateKey() altPrivateKey, _ := generateKey() - eg := NewTwistedElgamalWithED25519Curve() - - keys, _ := eg.KeyGen(*privateKey, DefaultTestDenom) - altKeys, _ := eg.KeyGen(*altPrivateKey, DefaultTestDenom) - - // Happy Path - value := uint64(108) - ciphertext, _, err := eg.Encrypt(keys.PublicKey, value) - require.Nil(t, err, "Should have no error while encrypting") - - decrypted, err := eg.Decrypt(keys.PrivateKey, ciphertext, MaxBits16) - require.Nil(t, err, "Should have no error while decrypting") - require.Equal(t, value, decrypted, "Should have the same value") - - decrypted, err = eg.Decrypt(keys.PrivateKey, ciphertext, MaxBits32) - require.Nil(t, err, "Should have no error while decrypting") - require.Equal(t, value, decrypted, "Should have the same value") - - // Using a different private key to decrypt should yield an error. - decryptedWrongly, err := eg.Decrypt(altKeys.PrivateKey, ciphertext, MaxBits32) - require.Zero(t, decryptedWrongly) - require.Error(t, err, "Should be unable to decrypt using the wrong private key") - - // Test overflow behavior - ciphertextOverflow, _, err := eg.Encrypt(keys.PublicKey, math.MaxUint64) - require.Nil(t, err, "Should have no error while encrypting") - decryptedOverflow, err := eg.Decrypt(keys.PrivateKey, ciphertextOverflow, MaxBits32) - require.Zero(t, decryptedOverflow) - require.Error(t, err, "Should be unable to decrypt the invalid overflow value") -} - -func TestEncryptionDecryptionBLS12377G1Curve(t *testing.T) { - privateKey, _ := generateKey() - altPrivateKey, _ := generateKey() - - eg := NewTwistedElgamal(curves.BLS12377G1()) + eg := NewTwistedElgamal() keys, _ := eg.KeyGen(*privateKey, DefaultTestDenom) altKeys, _ := eg.KeyGen(*altPrivateKey, DefaultTestDenom) @@ -157,8 +89,7 @@ func Test48BitEncryptionDecryption(t *testing.T) { privateKey, err := generateKey() require.Nil(t, err) - ed25519 := curves.ED25519() - eg := NewTwistedElgamal(ed25519) + eg := NewTwistedElgamal() keys, _ := eg.KeyGen(*privateKey, DefaultTestDenom) // First decrypt a 32 bit number (sets up the decryptor for a later test) @@ -199,8 +130,7 @@ func TestAddCiphertext(t *testing.T) { privateKey, _ := generateKey() altPrivateKey, _ := generateKey() - ed25519 := curves.ED25519() - eg := NewTwistedElgamal(ed25519) + eg := NewTwistedElgamal() keys, _ := eg.KeyGen(*privateKey, DefaultTestDenom) altKeys, _ := eg.KeyGen(*altPrivateKey, DefaultTestDenom) @@ -244,8 +174,7 @@ func TestAddCiphertext(t *testing.T) { } func TestTwistedElGamal_InvalidCiphertext(t *testing.T) { - curve := curves.ED25519() - eg := NewTwistedElgamal(curve) + eg := NewTwistedElgamal() privateKey, _ := generateKey() keys, _ := eg.KeyGen(*privateKey, DefaultTestDenom) @@ -258,8 +187,7 @@ func TestTwistedElGamal_InvalidCiphertext(t *testing.T) { } func TestTwistedElGamal_NilPrivateKey(t *testing.T) { - curve := curves.ED25519() - eg := NewTwistedElgamal(curve) + eg := NewTwistedElgamal() // Generate a valid key pair for comparison privateKey, _ := generateKey() @@ -278,16 +206,15 @@ func TestTwistedElGamal_NilPrivateKey(t *testing.T) { } func TestTwistedElGamal_EncryptDecryptWithRand(t *testing.T) { - curve := curves.ED25519() - eg := NewTwistedElgamal(curve) + eg := NewTwistedElgamal() // Generate a valid key pair for comparison privateKey, _ := generateKey() keys, _ := eg.KeyGen(*privateKey, DefaultTestDenom) message := uint64(555555555) - randomFactor := curve.Scalar.Random(rand.Reader) - ct, _, err := eg.EncryptWithRand(keys.PublicKey, message, randomFactor) + randomFactor := curves.ED25519().Scalar.Random(rand.Reader) + ct, _, err := eg.encryptWithRand(keys.PublicKey, message, randomFactor) require.NoError(t, err, "Encryption with randomFactor should not fail") decrypted, err := eg.DecryptLargeNumber(keys.PrivateKey, ct, MaxBits48) @@ -295,9 +222,25 @@ func TestTwistedElGamal_EncryptDecryptWithRand(t *testing.T) { require.Equal(t, message, decrypted, "Decrypted message should match original") } +func TestTwistedElGamal_EncryptMessageTwice(t *testing.T) { + curve := curves.ED25519() + eg := NewTwistedElgamal() + + // Generate a valid key pair for comparison + privateKey, _ := generateKey() + keys, _ := eg.KeyGen(*privateKey, DefaultTestDenom) + + message := uint64(555555555) + randomFactor := curve.Scalar.Random(rand.Reader) + ct1, _, _ := eg.encryptWithRand(keys.PublicKey, message, randomFactor) + ct2, _, _ := eg.encryptWithRand(keys.PublicKey, message, randomFactor) + + require.Equal(t, ct1, ct2, "Ciphertexts should be the same for the same message and random factor") +} + func TestTwistedElGamal_DecryptWithZeroBits(t *testing.T) { curve := curves.ED25519() - eg := NewTwistedElgamal(curve) + eg := NewTwistedElgamal() // Generate a valid key pair for comparison privateKey, _ := generateKey() @@ -305,7 +248,7 @@ func TestTwistedElGamal_DecryptWithZeroBits(t *testing.T) { message := uint64(555555555) randomFactor := curve.Scalar.Random(rand.Reader) - ct, _, err := eg.EncryptWithRand(keys.PublicKey, message, randomFactor) + ct, _, err := eg.encryptWithRand(keys.PublicKey, message, randomFactor) require.NoError(t, err, "Encryption with randomFactor should not fail") _, err = eg.DecryptLargeNumber(keys.PrivateKey, ct, MaxBits(0)) @@ -314,8 +257,7 @@ func TestTwistedElGamal_DecryptWithZeroBits(t *testing.T) { } func TestTwistedElGamal_EncryptInvalidKey(t *testing.T) { - curve := curves.ED25519() - eg := NewTwistedElgamal(curve) + eg := NewTwistedElgamal() // Test with nil public key _, _, err := eg.Encrypt(nil, 12345) @@ -324,22 +266,20 @@ func TestTwistedElGamal_EncryptInvalidKey(t *testing.T) { } func TestTwistedElGamal_EncryptInvalidRandomFactor(t *testing.T) { - curve := curves.ED25519() - eg := NewTwistedElgamal(curve) + eg := NewTwistedElgamal() // Generate a valid key pair for comparison privateKey, _ := generateKey() keys, _ := eg.KeyGen(*privateKey, DefaultTestDenom) // Test with nil public key - _, _, err := eg.EncryptWithRand(keys.PublicKey, uint64(12345), nil) + _, _, err := eg.encryptWithRand(keys.PublicKey, uint64(12345), nil) require.Error(t, err, "Encryption should fail with nil random factor") require.Equal(t, "invalid random factor", err.Error()) } func TestTwistedElGamal_EncryptBoundaryValues(t *testing.T) { - curve := curves.ED25519() - eg := NewTwistedElgamal(curve) + eg := NewTwistedElgamal() // Generate a valid key pair for comparison privateKey, _ := generateKey() diff --git a/pkg/encryption/elgamal/types.go b/pkg/encryption/elgamal/types.go index e6cb627..94a11bb 100644 --- a/pkg/encryption/elgamal/types.go +++ b/pkg/encryption/elgamal/types.go @@ -29,7 +29,7 @@ const ( ) // MarshalJSON for Ciphertext -func (c Ciphertext) MarshalJSON() ([]byte, error) { +func (c *Ciphertext) MarshalJSON() ([]byte, error) { // Serialize the points to a format you prefer return json.Marshal(map[string]interface{}{ "c": c.C.ToAffineCompressed(), // Assuming `ToAffineCompressed` returns a byte slice @@ -52,11 +52,12 @@ func (c *Ciphertext) UnmarshalJSON(data []byte) error { // Convert the byte arrays back into curve points // Assuming `FromCompressed` is a method to parse compressed points - pointC, err := curves.ED25519().Point.FromAffineCompressed(temp.C) + ed25519Curve := curves.ED25519() + pointC, err := ed25519Curve.Point.FromAffineCompressed(temp.C) if err != nil { return err } - pointD, err := curves.ED25519().Point.FromAffineCompressed(temp.D) + pointD, err := ed25519Curve.Point.FromAffineCompressed(temp.D) if err != nil { return err } diff --git a/pkg/encryption/elgamal/types_test.go b/pkg/encryption/elgamal/types_test.go new file mode 100644 index 0000000..a3f10da --- /dev/null +++ b/pkg/encryption/elgamal/types_test.go @@ -0,0 +1,31 @@ +package elgamal + +import ( + "encoding/json" + "github.com/stretchr/testify/require" + "testing" +) + +func TestCiphertext_MarshalJSON(t *testing.T) { + privateKey, _ := generateKey() + eg := NewTwistedElgamal() + + keys, _ := eg.KeyGen(*privateKey, DefaultTestDenom) + + value := uint64(108) + ciphertext, _, err := eg.Encrypt(keys.PublicKey, value) + + // Marshal the Ciphertext to JSON + data, err := json.Marshal(ciphertext) + require.NoError(t, err, "Marshaling should not produce an error") + + // Unmarshal the JSON back to a Ciphertext + var unmarshaled Ciphertext + err = json.Unmarshal(data, &unmarshaled) + require.NoError(t, err, "Unmarshaling should not produce an error") + + // Compare the original and unmarshaled Ciphertext + require.True(t, ciphertext.C.Equal(unmarshaled.C), "C points should be equal") + require.True(t, ciphertext.D.Equal(unmarshaled.D), "D points should be equal") + +}