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

upgrade package crypto and support KZG cryptography #751

Merged
merged 39 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
d3fc08d
update golang.org/x/crypto to v0.29.0
gzliudan Nov 29, 2024
92fc843
crypto: switch over to upstream sha3 package (#18390)
gzliudan Nov 29, 2024
9d9bd65
crypto/ecies: remove unused function (#19096)
gzliudan Nov 29, 2024
d2ac7d0
crypto: fix build when CGO_ENABLED=0 (#19121)
gzliudan Nov 29, 2024
66dd846
crypto/bn256/cloudflare: fix comments to describe the updated curve p…
gzliudan Nov 29, 2024
b9054b2
crypto: replace fmt.Println calls with t.Log in tests (#19670)
gzliudan Nov 29, 2024
8dcea8d
crypto: replace t.Log(); t.FailNow() with t.Fatal() (#19849)
gzliudan Nov 29, 2024
ad5e7d6
crypto: add SignatureLength constant and use it everywhere (#19996)
gzliudan Nov 29, 2024
e1eb00e
crypto: make unit tests work with Go 1.13 (#20053)
gzliudan Nov 29, 2024
6033722
crypto: use golangci-lint (#20295)
gzliudan Nov 29, 2024
b2be754
crypto/bn256: fix import line (#20723)
gzliudan Nov 29, 2024
ee303c9
crypto/ecies: improve concatKDF (#20836)
gzliudan Nov 29, 2024
f948466
crypto: less allocations when hashing and tx handling (#21265)
gzliudan Nov 29, 2024
a2eb855
crypto/bn256: better comments for u, P and Order (#21836)
gzliudan Nov 29, 2024
a64e424
crypto/bn256: refine comments according to #19577, #21595, and #21836…
gzliudan Nov 29, 2024
ddc5e61
crypto/bn256: fix bn256Mul fuzzer to not hang on large input (#21872)
gzliudan Nov 29, 2024
b1c7190
crypto: improve trie updates (#21047)
gzliudan Nov 29, 2024
ae95cea
bn256: added consensys/gurvy bn256 implementation (#21812)
gzliudan Nov 29, 2024
7711f4b
tests/fuzzers: crypto/bn256 tests against gnark-crypto (#22755)
gzliudan Nov 29, 2024
5ee26e0
crypto/secp256k1: fix undefined behavior in BitCurve.Add (#22621)
gzliudan Nov 29, 2024
9dab065
crypto: gofuzz build directives (#23137)
gzliudan Nov 29, 2024
146bc2b
crypto: add go:build lines (#23468)
gzliudan Nov 29, 2024
949fa63
crypto/ecies: use AES-192 for curve P384 (#24139)
gzliudan Nov 29, 2024
cb3edac
crypto: use btcec/v2 for no-cgo (#24533)
gzliudan Nov 29, 2024
797efe7
crypto: more linters and fix typo (#24783)
gzliudan Nov 29, 2024
bedd571
crypto/kzg4844: pull in the C and Go libs for KZG cryptography (#27155)
gzliudan Nov 29, 2024
ed03a99
crypto/kzg4844: upgrade c-kzg-4844 to v0.2.0 (#27257)
gzliudan Nov 29, 2024
bd93c59
crypto: replace noarg fmt.Errorf with errors.New (#27333)
gzliudan Nov 29, 2024
17c0480
tests/fuzzers/bn256: add PairingCheck fuzzer (#27252)
gzliudan Nov 29, 2024
541ddee
go.mod: update kzg libraries to use big-endian (#27510)
gzliudan Nov 29, 2024
247ebd6
crypto/kzg4844: do lazy init in all ckzg funcs (#27679)
gzliudan Nov 29, 2024
8f57d6c
go.mod: upgrade c-kzg-4844 (#27907)
gzliudan Nov 29, 2024
f7b6ad6
crypto, tests: update fuzzers to native go fuzzing (#28352)
gzliudan Nov 29, 2024
b5cc7e6
crypto/blake2b: put architecture-dependent features behind build-tag …
gzliudan Nov 29, 2024
824dea6
crypto/kzg4844: use the new trusted setup file and format (#28383)
gzliudan Nov 29, 2024
cae53aa
crypto/kzg4844: add helpers for versioned blob hashes (#28827)
gzliudan Nov 29, 2024
fabfcc7
crypto: fix docstring names (#28923)
gzliudan Nov 29, 2024
7278557
crypto: add support for blobs in eth_fillTransaction (#28839)
gzliudan Nov 29, 2024
3fbbc9d
crypto: fix typos in comments (#29186)
gzliudan Nov 29, 2024
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
Prev Previous commit
Next Next commit
crypto/ecies: improve concatKDF (ethereum#20836)
  • Loading branch information
gzliudan committed Dec 9, 2024
commit ee303c9f3df7d5f60e33ed32301f221adff77a2a
144 changes: 47 additions & 97 deletions crypto/ecies/ecies.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ import (
"crypto/elliptic"
"crypto/hmac"
"crypto/subtle"
"encoding/binary"
"errors"
"fmt"
"hash"
"io"
"math/big"
Expand All @@ -45,7 +45,6 @@ import (
var (
ErrImport = errors.New("ecies: failed to import key")
ErrInvalidCurve = errors.New("ecies: invalid elliptic curve")
ErrInvalidParams = errors.New("ecies: invalid ECIES parameters")
ErrInvalidPublicKey = errors.New("ecies: invalid public key")
ErrSharedKeyIsPointAtInfinity = errors.New("ecies: shared key is point at infinity")
ErrSharedKeyTooBig = errors.New("ecies: shared key params are too big")
Expand Down Expand Up @@ -139,57 +138,39 @@ func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []b
}

var (
ErrKeyDataTooLong = errors.New("ecies: can't supply requested key data")
ErrSharedTooLong = errors.New("ecies: shared secret is too long")
ErrInvalidMessage = errors.New("ecies: invalid message")
)

var (
big2To32 = new(big.Int).Exp(big.NewInt(2), big.NewInt(32), nil)
big2To32M1 = new(big.Int).Sub(big2To32, big.NewInt(1))
)

func incCounter(ctr []byte) {
if ctr[3]++; ctr[3] != 0 {
return
}
if ctr[2]++; ctr[2] != 0 {
return
}
if ctr[1]++; ctr[1] != 0 {
return
}
if ctr[0]++; ctr[0] != 0 {
return
}
}

// NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1).
func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) (k []byte, err error) {
if s1 == nil {
s1 = make([]byte, 0)
}

reps := ((kdLen + 7) * 8) / (hash.BlockSize() * 8)
if big.NewInt(int64(reps)).Cmp(big2To32M1) > 0 {
fmt.Println(big2To32M1)
return nil, ErrKeyDataTooLong
}

counter := []byte{0, 0, 0, 1}
k = make([]byte, 0)

for i := 0; i <= reps; i++ {
hash.Write(counter)
func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) []byte {
counterBytes := make([]byte, 4)
k := make([]byte, 0, roundup(kdLen, hash.Size()))
for counter := uint32(1); len(k) < kdLen; counter++ {
binary.BigEndian.PutUint32(counterBytes, counter)
hash.Reset()
hash.Write(counterBytes)
hash.Write(z)
hash.Write(s1)
k = append(k, hash.Sum(nil)...)
hash.Reset()
incCounter(counter)
k = hash.Sum(k)
}
return k[:kdLen]
}

k = k[:kdLen]
return
// roundup rounds size up to the next multiple of blocksize.
func roundup(size, blocksize int) int {
return size + blocksize - (size % blocksize)
}

// deriveKeys creates the encryption and MAC keys using concatKDF.
func deriveKeys(hash hash.Hash, z, s1 []byte, keyLen int) (Ke, Km []byte) {
K := concatKDF(hash, z, s1, 2*keyLen)
Ke = K[:keyLen]
Km = K[keyLen:]
hash.Reset()
hash.Write(Km)
Km = hash.Sum(Km[:0])
return Ke, Km
}

// messageTag computes the MAC of a message (called the tag) as per
Expand All @@ -210,7 +191,6 @@ func generateIV(params *ECIESParams, rand io.Reader) (iv []byte, err error) {
}

// symEncrypt carries out CTR encryption using the block cipher specified in the
// parameters.
func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte, err error) {
c, err := params.Cipher(key)
if err != nil {
Expand Down Expand Up @@ -250,36 +230,27 @@ func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) {
// ciphertext. s1 is fed into key derivation, s2 is fed into the MAC. If the
// shared information parameters aren't being used, they should be nil.
func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) {
params := pub.Params
if params == nil {
if params = ParamsFromCurve(pub.Curve); params == nil {
err = ErrUnsupportedECIESParameters
return
}
params, err := pubkeyParams(pub)
if err != nil {
return nil, err
}

R, err := GenerateKey(rand, pub.Curve, params)
if err != nil {
return
return nil, err
}

hash := params.Hash()
z, err := R.GenerateShared(pub, params.KeyLen, params.KeyLen)
if err != nil {
return
}
K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)
if err != nil {
return
return nil, err
}
Ke := K[:params.KeyLen]
Km := K[params.KeyLen:]
hash.Write(Km)
Km = hash.Sum(nil)
hash.Reset()

hash := params.Hash()
Ke, Km := deriveKeys(hash, z, s1, params.KeyLen)

em, err := symEncrypt(rand, params, Ke, m)
if err != nil || len(em) <= params.BlockSize {
return
return nil, err
}

d := messageTag(params.Hash, Km, em, s2)
Expand All @@ -289,21 +260,19 @@ func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err e
copy(ct, Rb)
copy(ct[len(Rb):], em)
copy(ct[len(Rb)+len(em):], d)
return
return ct, nil
}

// Decrypt decrypts an ECIES ciphertext.
func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {
if len(c) == 0 {
return nil, ErrInvalidMessage
}
params := prv.PublicKey.Params
if params == nil {
if params = ParamsFromCurve(prv.PublicKey.Curve); params == nil {
err = ErrUnsupportedECIESParameters
return
}
params, err := pubkeyParams(&prv.PublicKey)
if err != nil {
return nil, err
}

hash := params.Hash()

var (
Expand All @@ -317,12 +286,10 @@ func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {
case 2, 3, 4:
rLen = (prv.PublicKey.Curve.Params().BitSize + 7) / 4
if len(c) < (rLen + hLen + 1) {
err = ErrInvalidMessage
return
return nil, ErrInvalidMessage
}
default:
err = ErrInvalidPublicKey
return
return nil, ErrInvalidPublicKey
}

mStart = rLen
Expand All @@ -332,36 +299,19 @@ func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {
R.Curve = prv.PublicKey.Curve
R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen])
if R.X == nil {
err = ErrInvalidPublicKey
return
}
if !R.Curve.IsOnCurve(R.X, R.Y) {
err = ErrInvalidCurve
return
return nil, ErrInvalidPublicKey
}

z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen)
if err != nil {
return
return nil, err
}

K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)
if err != nil {
return
}

Ke := K[:params.KeyLen]
Km := K[params.KeyLen:]
hash.Write(Km)
Km = hash.Sum(nil)
hash.Reset()
Ke, Km := deriveKeys(hash, z, s1, params.KeyLen)

d := messageTag(params.Hash, Km, c[mStart:mEnd], s2)
if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 {
err = ErrInvalidMessage
return
return nil, ErrInvalidMessage
}

m, err = symDecrypt(params, Ke, c[mStart:mEnd])
return
return symDecrypt(params, Ke, c[mStart:mEnd])
}
39 changes: 26 additions & 13 deletions crypto/ecies/ecies_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,23 @@ import (
"github.com/XinFinOrg/XDPoSChain/crypto"
)

// Ensure the KDF generates appropriately sized keys.
func TestKDF(t *testing.T) {
msg := []byte("Hello, world")
h := sha256.New()

k, err := concatKDF(h, msg, nil, 64)
if err != nil {
t.Fatal(err)
}
if len(k) != 64 {
t.Fatalf("KDF: generated key is the wrong size (%d instead of 64\n", len(k))
tests := []struct {
length int
output []byte
}{
{6, decode("858b192fa2ed")},
{32, decode("858b192fa2ed4395e2bf88dd8d5770d67dc284ee539f12da8bceaa45d06ebae0")},
{48, decode("858b192fa2ed4395e2bf88dd8d5770d67dc284ee539f12da8bceaa45d06ebae0700f1ab918a5f0413b8140f9940d6955")},
{64, decode("858b192fa2ed4395e2bf88dd8d5770d67dc284ee539f12da8bceaa45d06ebae0700f1ab918a5f0413b8140f9940d6955f3467fd6672cce1024c5b1effccc0f61")},
}

for _, test := range tests {
h := sha256.New()
k := concatKDF(h, []byte("input"), nil, test.length)
if !bytes.Equal(k, test.output) {
t.Fatalf("KDF: generated key %x does not match expected output %x", k, test.output)
}
}
}

Expand Down Expand Up @@ -293,8 +299,8 @@ func TestParamSelection(t *testing.T) {

func testParamSelection(t *testing.T, c testCase) {
params := ParamsFromCurve(c.Curve)
if params == nil && c.Expected != nil {
t.Fatalf("%s (%s)\n", ErrInvalidParams.Error(), c.Name)
if params == nil {
t.Fatal("ParamsFromCurve returned nil")
} else if params != nil && !cmpParams(params, c.Expected) {
t.Fatalf("ecies: parameters should be invalid (%s)\n", c.Name)
}
Expand Down Expand Up @@ -328,7 +334,6 @@ func testParamSelection(t *testing.T, c testCase) {
if err == nil {
t.Fatalf("ecies: encryption should not have succeeded (%s)\n", c.Name)
}

}

// Ensure that the basic public key validation in the decryption operation
Expand Down Expand Up @@ -414,3 +419,11 @@ func hexKey(prv string) *PrivateKey {
}
return ImportECDSA(key)
}

func decode(s string) []byte {
bytes, err := hex.DecodeString(s)
if err != nil {
panic(err)
}
return bytes
}
20 changes: 20 additions & 0 deletions crypto/ecies/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (
"crypto/sha256"
"crypto/sha512"
"errors"
"fmt"
"hash"

ethcrypto "github.com/XinFinOrg/XDPoSChain/crypto"
Expand All @@ -49,8 +50,14 @@ var (
DefaultCurve = ethcrypto.S256()
ErrUnsupportedECDHAlgorithm = errors.New("ecies: unsupported ECDH algorithm")
ErrUnsupportedECIESParameters = errors.New("ecies: unsupported ECIES parameters")
ErrInvalidKeyLen = fmt.Errorf("ecies: invalid key size (> %d) in ECIESParams", maxKeyLen)
)

// KeyLen is limited to prevent overflow of the counter
// in concatKDF. While the theoretical limit is much higher,
// no known cipher uses keys larger than 512 bytes.
const maxKeyLen = 512

type ECIESParams struct {
Hash func() hash.Hash // hash function
hashAlgo crypto.Hash
Expand Down Expand Up @@ -115,3 +122,16 @@ func AddParamsForCurve(curve elliptic.Curve, params *ECIESParams) {
func ParamsFromCurve(curve elliptic.Curve) (params *ECIESParams) {
return paramsFromCurve[curve]
}

func pubkeyParams(key *PublicKey) (*ECIESParams, error) {
params := key.Params
if params == nil {
if params = ParamsFromCurve(key.Curve); params == nil {
return nil, ErrUnsupportedECIESParameters
}
}
if params.KeyLen > maxKeyLen {
return nil, ErrInvalidKeyLen
}
return params, nil
}