-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
shutter: port over crypto pkg (#13752)
part 2 of #13384 used in #13725 Short-term ported from: https://github.com/shutter-network/shutter/tree/main/shlib/shcrypto Long term plan is to import this as a library from the shutter repos, however for now im doing this port because currently that library has go-ethereum dependencies and so that will bring go-ethereum transitive dependencies to erigon which is not desirable. I've had a look and actually it is possible to remove that go-ethereum dependency in the shutter crypto package but needs a bit of work and cooperation with the shutter team. I've created an issue (#13724) for this and have left it for a future time (after we have a working shutter validator implementation).
- Loading branch information
Showing
13 changed files
with
2,379 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<h1>Context</h1> | ||
|
||
This is ported from https://github.com/shutter-network/shutter/tree/main/shlib/shcrypto to | ||
avoid introducing a go-ethereum transitive dependency in Erigon. | ||
|
||
In the long term, we can work with the shutter team to remove their dependency on go-ethereum | ||
for their `shcrypto` package (doable). When that is done we will be able to simply use their | ||
library directly. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,300 @@ | ||
// Copyright 2025 The Erigon Authors | ||
// This file is part of Erigon. | ||
// | ||
// Erigon is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU Lesser General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Erigon is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU Lesser General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU Lesser General Public License | ||
// along with Erigon. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
package crypto | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"fmt" | ||
"math/big" | ||
|
||
blst "github.com/supranational/blst/bindings/go" | ||
|
||
"github.com/erigontech/erigon-lib/common/hexutil" | ||
"github.com/erigontech/erigon-lib/common/hexutility" | ||
) | ||
|
||
var ( | ||
ErrInputTooLong = errors.New("input too long") | ||
ErrInvalidEonSecretKeyShare = errors.New("invalid eon secret key share") | ||
ErrVersionMismatch = func(version_got byte) error { | ||
return fmt.Errorf("version mismatch. want %d got %d", VersionIdentifier, version_got) | ||
} | ||
) | ||
|
||
// Marshal serializes the EncryptedMessage object. It panics, if C1 is nil. | ||
func (m *EncryptedMessage) Marshal() []byte { | ||
if m.C1 == nil { | ||
panic("not a valid encrypted message. C1==nil") | ||
} | ||
|
||
buff := bytes.Buffer{} | ||
buff.WriteByte(VersionIdentifier) | ||
buff.Write(m.C1.Compress()) | ||
buff.Write(m.C2[:]) | ||
for i := range m.C3 { | ||
buff.Write(m.C3[i][:]) | ||
} | ||
|
||
return buff.Bytes() | ||
} | ||
|
||
// Unmarshal deserializes an EncryptedMessage from the given byte slice. | ||
func (m *EncryptedMessage) Unmarshal(d []byte) error { | ||
if len(d) == 0 { | ||
return errors.New("not enough data") | ||
} | ||
if d[0] != VersionIdentifier { | ||
return ErrVersionMismatch(IdentifyVersion(d)) | ||
} | ||
|
||
if len(d) < 1+blst.BLST_P2_COMPRESS_BYTES+BlockSize || | ||
(len(d)-1-blst.BLST_P2_COMPRESS_BYTES-BlockSize)%BlockSize != 0 { | ||
return fmt.Errorf("invalid length %d of encrypted message", len(d)) | ||
} | ||
if m.C1 == nil { | ||
m.C1 = new(blst.P2Affine) | ||
} | ||
m.C1.Uncompress(d[1 : 1+blst.BLST_P2_COMPRESS_BYTES]) | ||
if m.C1 == nil { | ||
return errors.New("failed to deserialize C1") | ||
} | ||
if !m.C1.InG2() { | ||
return errors.New("C1 not on curve") | ||
} | ||
|
||
copy(m.C2[:], d[1+blst.BLST_P2_COMPRESS_BYTES:1+blst.BLST_P2_COMPRESS_BYTES+BlockSize]) | ||
|
||
m.C3 = nil | ||
for i := 1 + blst.BLST_P2_COMPRESS_BYTES + BlockSize; i < len(d); i += BlockSize { | ||
b := Block{} | ||
copy(b[:], d[i:i+BlockSize]) | ||
m.C3 = append(m.C3, b) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Marshal serializes the eon secret key share. | ||
func (eonSecretKeyShare *EonSecretKeyShare) Marshal() []byte { | ||
return (*big.Int)(eonSecretKeyShare).Bytes() | ||
} | ||
|
||
// Unarshal deserializes an eon secret key share. | ||
func (eonSecretKeyShare *EonSecretKeyShare) Unmarshal(m []byte) error { | ||
(*big.Int)(eonSecretKeyShare).SetBytes(m) | ||
if (*big.Int)(eonSecretKeyShare).Cmp(order) >= 0 { | ||
return ErrInvalidEonSecretKeyShare | ||
} | ||
return nil | ||
} | ||
|
||
// Marshal serializes the eon public key share. | ||
func (eonPublicKeyShare *EonPublicKeyShare) Marshal() []byte { | ||
return (*blst.P2Affine)(eonPublicKeyShare).Compress() | ||
} | ||
|
||
// Unmarshal deserializes an eon public key share. | ||
func (eonPublicKeyShare *EonPublicKeyShare) Unmarshal(m []byte) error { | ||
p := (*blst.P2Affine)(eonPublicKeyShare) | ||
p.Uncompress(m) | ||
if p == nil { | ||
return errors.New("failed to deserialize eon public key share") | ||
} | ||
if !p.InG2() { | ||
return errors.New("eon public key share is not on curve") | ||
} | ||
return nil | ||
} | ||
|
||
// Marshal serializes the eon public key. | ||
func (eonPublicKey *EonPublicKey) Marshal() []byte { | ||
return (*blst.P2Affine)(eonPublicKey).Compress() | ||
} | ||
|
||
// Unmarshal deserializes an eon public key from the given byte slice. | ||
func (eonPublicKey *EonPublicKey) Unmarshal(m []byte) error { | ||
p := (*blst.P2Affine)(eonPublicKey) | ||
p.Uncompress(m) | ||
if p == nil { | ||
return errors.New("failed to deserialize eon public key") | ||
} | ||
if !p.InG2() { | ||
return errors.New("eon public key is not on curve") | ||
} | ||
return nil | ||
} | ||
|
||
// MarshalText serializes the eon public key to hex. | ||
func (eonPublicKey EonPublicKey) MarshalText() ([]byte, error) { | ||
return hexutility.Bytes(eonPublicKey.Marshal()).MarshalText() | ||
} | ||
|
||
// UnmarshalText deserializes the eon public key from hex. | ||
func (eonPublicKey *EonPublicKey) UnmarshalText(input []byte) error { | ||
var b hexutility.Bytes | ||
if err := b.UnmarshalText(input); err != nil { | ||
return err | ||
} | ||
return eonPublicKey.Unmarshal(b) | ||
} | ||
|
||
// Marshal serializes the epoch id. | ||
func (epochID *EpochID) Marshal() []byte { | ||
return (*blst.P1Affine)(epochID).Compress() | ||
} | ||
|
||
// Unmarshal deserializes an epoch id. | ||
func (epochID *EpochID) Unmarshal(m []byte) error { | ||
p := (*blst.P1Affine)(epochID) | ||
p.Uncompress(m) | ||
if p == nil { | ||
return errors.New("failed to deserialize epoch id") | ||
} | ||
if !p.InG1() { | ||
return errors.New("epoch id is not on curve") | ||
} | ||
*epochID = EpochID(*p) | ||
return nil | ||
} | ||
|
||
// Marshal serializes the epoch secret key share. | ||
func (epochSecretKeyShare *EpochSecretKeyShare) Marshal() []byte { | ||
return (*blst.P1Affine)(epochSecretKeyShare).Compress() | ||
} | ||
|
||
// Unmarshal deserializes an epoch secret key share. | ||
func (epochSecretKeyShare *EpochSecretKeyShare) Unmarshal(m []byte) error { | ||
p := (*blst.P1Affine)(epochSecretKeyShare) | ||
p.Uncompress(m) | ||
if p == nil { | ||
return errors.New("failed to deserialize epoch secret key share") | ||
} | ||
if !p.InG1() { | ||
return errors.New("epoch secret key share is not on curve") | ||
} | ||
return nil | ||
} | ||
|
||
// Marshal serializes the epoch secret key. | ||
func (epochSecretKey *EpochSecretKey) Marshal() []byte { | ||
return (*blst.P1Affine)(epochSecretKey).Compress() | ||
} | ||
|
||
// Unmarshal deserializes an epoch secret key. | ||
func (epochSecretKey *EpochSecretKey) Unmarshal(m []byte) error { | ||
p := (*blst.P1Affine)(epochSecretKey) | ||
p.Uncompress(m) | ||
if p == nil { | ||
return errors.New("failed to deserialize epoch secret key") | ||
} | ||
if !p.InG1() { | ||
return errors.New("epoch secret key is not on curve") | ||
} | ||
return nil | ||
} | ||
|
||
// MarshalText serializes the epoch secret key to hex. | ||
func (epochSecretKey EpochSecretKey) MarshalText() ([]byte, error) { //nolint: unparam | ||
return []byte(hexutility.Encode(epochSecretKey.Marshal())), nil | ||
} | ||
|
||
// UnmarshalText deserializes the epoch secret key from hex. | ||
func (epochSecretKey *EpochSecretKey) UnmarshalText(input []byte) error { | ||
var b hexutility.Bytes | ||
if err := b.UnmarshalText(input); err != nil { | ||
return err | ||
} | ||
return epochSecretKey.Unmarshal(b) | ||
} | ||
|
||
// MarshalText serializes the block to hex. | ||
func (block Block) MarshalText() ([]byte, error) { //nolint:unparam | ||
return []byte(hexutility.Encode(block[:])), nil | ||
} | ||
|
||
// UnmarshalText deserializes the block from hex. | ||
func (block *Block) UnmarshalText(b []byte) error { | ||
decoded, err := hexutil.Decode(string(b)) | ||
copy(block[:], decoded) | ||
return err | ||
} | ||
|
||
// MarshalText serializes the encrypted message to hex. | ||
func (m EncryptedMessage) MarshalText() ([]byte, error) { //nolint:unparam | ||
return []byte(hexutility.Encode(m.Marshal())), nil | ||
} | ||
|
||
// UnmarshalText deserializes the encrypted message from hex. | ||
func (m *EncryptedMessage) UnmarshalText(b []byte) error { | ||
decoded, err := hexutil.Decode(string(b)) | ||
if err != nil { | ||
return err | ||
} | ||
err = m.Unmarshal(decoded) | ||
return err | ||
} | ||
|
||
// Marshal serializes the gammas value. | ||
// | ||
// Serialization format: [n:4][gamma1:96]...[gamman:96] | ||
func (g *Gammas) Marshal() []byte { | ||
if g == nil { | ||
return []byte{} | ||
} | ||
buff := bytes.Buffer{} | ||
for _, p := range *g { | ||
buff.Write(p.Compress()) | ||
} | ||
return buff.Bytes() | ||
} | ||
|
||
// Unmarshal deserializes a gammas value. | ||
func (g *Gammas) Unmarshal(m []byte) error { | ||
if len(m)%blst.BLST_P2_COMPRESS_BYTES != 0 { | ||
return errors.New("invalid length of gammas") | ||
} | ||
n := len(m) / blst.BLST_P2_COMPRESS_BYTES | ||
*g = make(Gammas, n) | ||
for i := 0; i < n; i++ { | ||
p := new(blst.P2Affine) | ||
p = p.Uncompress(m[i*blst.BLST_P2_COMPRESS_BYTES : (i+1)*blst.BLST_P2_COMPRESS_BYTES]) | ||
if p == nil { | ||
return errors.New("failed to deserialize gamma") | ||
} | ||
if !p.InG2() { | ||
return errors.New("gamma is not on curve") | ||
} | ||
(*g)[i] = p | ||
} | ||
return nil | ||
} | ||
|
||
// MarshalText serializes the gammas as hex. | ||
func (g *Gammas) MarshalText() ([]byte, error) { | ||
return []byte(hexutility.Encode(g.Marshal())), nil | ||
} | ||
|
||
// UnmarshalText deserializes the gammas from hex. | ||
func (g *Gammas) UnmarshalText(b []byte) error { | ||
decoded, err := hexutil.Decode(string(b)) | ||
if err != nil { | ||
return err | ||
} | ||
err = g.Unmarshal(decoded) | ||
return err | ||
} |
Oops, something went wrong.