Skip to content

Commit

Permalink
- Only allow ED25519 curve for now, but cache it to reduce amount of …
Browse files Browse the repository at this point in the history
…init calls

- add marshaling test
  • Loading branch information
dssei committed Oct 9, 2024
1 parent c63c513 commit 906f272
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 111 deletions.
21 changes: 4 additions & 17 deletions pkg/encryption/elgamal/encryption.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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")
}
Expand Down
122 changes: 31 additions & 91 deletions pkg/encryption/elgamal/encryption_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)

Expand All @@ -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()
Expand All @@ -278,34 +206,49 @@ 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)
require.NoError(t, err, "Decryption should not fail")
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()
keys, _ := eg.KeyGen(*privateKey, DefaultTestDenom)

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))
Expand All @@ -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)
Expand All @@ -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()
Expand Down
7 changes: 4 additions & 3 deletions pkg/encryption/elgamal/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Expand Down
31 changes: 31 additions & 0 deletions pkg/encryption/elgamal/types_test.go
Original file line number Diff line number Diff line change
@@ -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)

Check failure on line 16 in pkg/encryption/elgamal/types_test.go

View workflow job for this annotation

GitHub Actions / lint

ineffectual assignment to err (ineffassign)

// 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")

}

0 comments on commit 906f272

Please sign in to comment.