Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove ECDSA and Denom dependencies #7

Merged
merged 5 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ go 1.21
require (
github.com/bwesterb/go-ristretto v1.2.3
github.com/coinbase/kryptology v1.8.0
github.com/ethereum/go-ethereum v1.13.15
github.com/gtank/merlin v0.1.1
github.com/stretchr/testify v1.9.0
golang.org/x/crypto v0.27.0
Expand All @@ -16,6 +15,7 @@ require (
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
Expand Down
6 changes: 3 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
github.com/ethereum/go-ethereum v1.13.15 h1:U7sSGYGo4SPjP6iNIifNoyIAiNjrmQkz6EwQG+/EZWo=
github.com/ethereum/go-ethereum v1.13.15/go.mod h1:TN8ZiHrdJwSe8Cb6x+p0hs5CxhJZPbqB7hHkaUXcmIU=
github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is=
github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s=
Expand All @@ -24,10 +22,12 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0=
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/sei-protocol/coinbase-kryptology v0.0.0-20241015231206-08f61b7965cd h1:R/g4pa6pgegLAAt1NTrO1qVJ3uZH9hfcMcc4yLz1cgg=
Expand Down
29 changes: 7 additions & 22 deletions pkg/encryption/aes.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package encryption
import (
"crypto/aes"
"crypto/cipher"
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
Expand All @@ -12,33 +11,19 @@ import (
"io"
"math/big"

"github.com/ethereum/go-ethereum/crypto/secp256k1"

"golang.org/x/crypto/hkdf"
)

// GenerateKey generates a new ECDSA private key using the secp256k1 curve.
func GenerateKey() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(secp256k1.S256(), rand.Reader)
}

// GetAESKey derives a 32-byte AES key using the provided ECDSA private key and denomination string.
// It employs HKDF with SHA-256, using the ECDSA private key bytes and a SHA-256 hash of the denom as salt.
func GetAESKey(privKey ecdsa.PrivateKey, denom string) ([]byte, error) {
if privKey.D == nil {
return nil, fmt.Errorf("private key D is nil")
// GetAESKey derives a 32-byte AES key using the provided bytes.
// It employs HKDF with SHA-256, using the private key bytes.
// No additional salt is added here so ensure that the privateBytes are already salted or hashed.
func GetAESKey(privateBytes []byte) ([]byte, error) {
if len(privateBytes) == 0 {
return nil, fmt.Errorf("bytes is empty")
}
if len(denom) == 0 {
return nil, fmt.Errorf("denom is empty")
}
// Convert the ECDSA private key to bytes
privKeyBytes := privKey.D.Bytes()

// Use a SHA-256 hash of the denom string as the salt
salt := sha256.Sum256([]byte(denom))

// Create an HKDF reader using SHA-256
hkdf := hkdf.New(sha256.New, privKeyBytes, salt[:], []byte("aes key derivation"))
hkdf := hkdf.New(sha256.New, privateBytes, nil, []byte("aes key derivation"))

// Allocate a 32-byte array for the AES key
aesKey := make([]byte, 32)
Expand Down
55 changes: 13 additions & 42 deletions pkg/encryption/aes_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package encryption

import (
"crypto/ecdsa"
"math/big"
"testing"
"time"

"github.com/stretchr/testify/require"
)
Expand All @@ -16,57 +16,37 @@ const (
func TestGetAESKey(t *testing.T) {
tests := []struct {
name string
privateKey *ecdsa.PrivateKey
privateKey []byte
denom string
expectEqual bool
anotherKey *ecdsa.PrivateKey
anotherKey []byte
anotherDenom string
}{
{
name: "Deterministic Key Generation",
privateKey: generateTestKey(t),
denom: TestDenom,
privateKey: generateTestKey(),
expectEqual: true,
},
{
name: "Different Denom (Salt) Generates Different Key",
privateKey: generateTestKey(t),
denom: TestDenom,
anotherDenom: TestDenom + "1",
expectEqual: false,
},
{
name: "Different Denom (Salt) of same length Generates Different Key",
privateKey: generateTestKey(t),
denom: TestDenom + "1",
anotherDenom: TestDenom + "2",
expectEqual: false,
},
{
name: "Different PrivateKey Generates Different Key",
privateKey: generateTestKey(t),
denom: TestDenom + "N",
anotherKey: generateTestKey(t),
privateKey: generateTestKey(),
anotherKey: generateTestKey(),
expectEqual: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
aesPK, err := GetAESKey(*tt.privateKey, tt.denom)
aesPK, err := GetAESKey(tt.privateKey)
require.Nil(t, err, "Should not have error here")

if tt.anotherKey != nil {
aesPKDiff, err := GetAESKey(*tt.anotherKey, tt.denom)
aesPKDiff, err := GetAESKey(tt.anotherKey)
require.Nil(t, err)
require.NotEqual(t, aesPK, aesPKDiff, "PK should be different for different private keys")
} else if tt.anotherDenom != "" {
aesPKDiff, err := GetAESKey(*tt.privateKey, tt.anotherDenom)
require.Nil(t, err)
require.NotEqual(t, aesPK, aesPKDiff, "PK should be different for different salts")
} else {

aesPKAgain, err := GetAESKey(*tt.privateKey, tt.denom)
aesPKAgain, err := GetAESKey(tt.privateKey)
require.Nil(t, err, "Should not have error here")
if tt.expectEqual {
require.Equal(t, aesPK, aesPKAgain, "PK should be deterministically generated")
Expand All @@ -80,16 +60,8 @@ func TestGetAESKey(t *testing.T) {

func TestGetAESKey_InvalidInput(t *testing.T) {
// Nil private key
_, err := GetAESKey(*new(ecdsa.PrivateKey), TestDenom)
_, err := GetAESKey([]byte{})
require.Error(t, err, "Should return error for nil private key")

invalidPrivateKey := &ecdsa.PrivateKey{ /* Invalid key data */ }
_, err = GetAESKey(*invalidPrivateKey, TestDenom)
require.Error(t, err, "Should return error for invalid private key")

validPrivateKey := generateTestKey(t)
_, err = GetAESKey(*validPrivateKey, "")
require.Error(t, err, "Should not allow empty denom(salt)")
}

func TestAESEncryptionDecryption(t *testing.T) {
Expand Down Expand Up @@ -218,8 +190,7 @@ func TestDecryptAESGCM_InvalidCiphertext(t *testing.T) {
}

// Helper function to generate a test private key
func generateTestKey(t *testing.T) *ecdsa.PrivateKey {
privateKey, err := GenerateKey()
require.Nil(t, err, "Failed to generate private key")
return privateKey
func generateTestKey() []byte {
randomString := time.Now()
return []byte(randomString.String())
}
20 changes: 7 additions & 13 deletions pkg/encryption/elgamal/common.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package elgamal

import (
"crypto/ecdsa"
"crypto/sha256"
"io"

Expand All @@ -13,11 +12,12 @@ import (
const H_STRING = "gPt25pi0eDphSiXWu0BIeIvyVATCtwhslTqfqvNhW2c"

// KeyGen generates a new key pair for the Twisted ElGamal encryption scheme.
func (teg TwistedElGamal) KeyGen(privateKey ecdsa.PrivateKey, denom string) (*KeyPair, error) {
// The private key is derived from the provided privateBytes and denom string. Ensure that the privateBytes passed is not exposed.
func (teg TwistedElGamal) KeyGen(privateBytes []byte) (*KeyPair, error) {
// Fixed base point H
H := teg.GetH()

s, err := teg.getPrivateKey(privateKey, denom)
s, err := teg.getPrivateKeyFromBytes(privateBytes)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -47,17 +47,11 @@ func (teg TwistedElGamal) GetH() curves.Point {
return teg.curve.Point.Hash(bytes)
}

// getPrivateKey derives a private key for the ElGamal cryptosystem.
// It takes an ECDSA private key and a denomination string to generate the scalar.
func (teg TwistedElGamal) getPrivateKey(privateKey ecdsa.PrivateKey, denom string) (curves.Scalar, error) {
// Convert the ECDSA private key to bytes
privKeyBytes := privateKey.D.Bytes()

// Hash the denom to get a salt.
salt := sha256.Sum256([]byte(denom))

// Creates an el gamal private key from the provided bytes.
// No additional salt is added here so ensure that the privateBytes are already salted or hashed.
func (teg TwistedElGamal) getPrivateKeyFromBytes(privateBytes []byte) (curves.Scalar, error) {
// Create an HKDF reader using SHA-256
hkdf := hkdf.New(sha256.New, privKeyBytes, salt[:], []byte("elgamal scalar derivation"))
hkdf := hkdf.New(sha256.New, privateBytes, nil, []byte("elgamal scalar derivation"))

// Generate 64 bytes of randomness from HKDF output
var scalarBytes [64]byte
Expand Down
Loading
Loading