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

tbls: library for BLS12-381 abstraction #1692

Merged
merged 22 commits into from
Jan 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
aa59047
tbls: first iteration of BLS abstraction
gsora Jan 20, 2023
06b7626
tbls: implement BLS abstraction as a thin layer on top of []byte obje…
gsora Jan 20, 2023
4be276b
tbls: refactor variable initialization
gsora Jan 20, 2023
9a4ac38
tbls: place Implementation behind a lock
gsora Jan 20, 2023
7bd40dc
tbls: replace raw []byte with specialized types
gsora Jan 20, 2023
e90f9d0
tbls: pass total and threshold parameters to RecoverSecret
gsora Jan 20, 2023
5626ff2
tbls: partial Kryptology implementation of tbls.Interface
gsora Jan 20, 2023
74178d2
tbls: generalize testing framework
gsora Jan 23, 2023
67ab196
tbls: complete Kryptology implementation of taketwo.Implementation
gsora Jan 23, 2023
660eadf
tbls: add randomized taketwo.Implementation
gsora Jan 23, 2023
1f96967
tbls: remove unused method in taketwo tests
gsora Jan 23, 2023
5d88381
tbls: add benchmarks for all available taketwo.Implementation's
gsora Jan 23, 2023
2202389
tbls: add FuzzRandomImplementations fuzzing target
gsora Jan 23, 2023
4c8f2d7
tbls: remove first iteration of BLS abstraction
gsora Jan 25, 2023
ec3818a
tbls: rename taketwo to v2
gsora Jan 25, 2023
a196c49
tbls: PublicKey, PrivateKey and Signature are now arrays
gsora Jan 25, 2023
012e813
tbls: convert fmt.Errorf calls to errors package in herumi implementa…
gsora Jan 25, 2023
7ed71c1
tbls: fix golangci-lint errors
gsora Jan 26, 2023
f18d063
tbls: fix pre-commit issues
gsora Jan 26, 2023
bd4daee
tbls: shorten herumi sync.Once variable name
gsora Jan 26, 2023
ad3cac8
tbls: fix GenerateSecret comment in herumi implementation
gsora Jan 26, 2023
c5c7160
testutil: remove CGO_ENABLE=0
gsora Jan 26, 2023
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
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/ferranbt/fastssz v0.1.2
github.com/golang/snappy v0.0.4
github.com/gorilla/mux v1.8.0
github.com/herumi/bls-eth-go-binary v1.28.1
gsora marked this conversation as resolved.
Show resolved Hide resolved
github.com/ipfs/go-log/v2 v2.5.1
github.com/jonboulle/clockwork v0.3.0
github.com/jsternberg/zap-logfmt v1.3.0
Expand Down
3 changes: 2 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,9 @@ github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuW
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e h1:wCMygKUQhmcQAjlk2Gquzq6dLmyMv2kF+llRspoRgrk=
github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/herumi/bls-eth-go-binary v1.28.1 h1:fcIZ48y5EE9973k05XjE8+P3YiQgjZz4JI/YabAm8KA=
github.com/herumi/bls-eth-go-binary v1.28.1/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
Expand Down
232 changes: 232 additions & 0 deletions tbls/v2/herumi/herumi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
// Copyright © 2022 Obol Labs Inc.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program 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 General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <http://www.gnu.org/licenses/>.

package herumi

import (
"fmt"
"strconv"
"sync"

"github.com/herumi/bls-eth-go-binary/bls"

"github.com/obolnetwork/charon/app/errors"
"github.com/obolnetwork/charon/app/z"
v2 "github.com/obolnetwork/charon/tbls/v2"
)

var initOnce = sync.Once{}

// PSA: as much as init() is (almost) an antipattern in Go, Herumi BLS implementation needs an initialization routine
// before it can be used.
// Hence, we embed it in an init() method along with a sync.Once, so that this effect is only run once.
//
//nolint:gochecknoinits
func init() {
initOnce.Do(func() {
//nolint:nosnakecase
if err := bls.Init(bls.BLS12_381); err != nil {
panic(errors.Wrap(err, "cannot initialize Herumi BLS"))
}

if err := bls.SetETHmode(bls.EthModeLatest); err != nil {
panic(errors.Wrap(err, "cannot initialize Herumi BLS"))
}
})
}

// Herumi is an Implementation with Herumi-specific inner logic.
type Herumi struct{}

func (Herumi) GenerateSecretKey() (v2.PrivateKey, error) {
var p bls.SecretKey
p.SetByCSPRNG()

// Commenting here once, this syntax will appear often:
// here I'm converting the output of p.Serialize() to a pointer to instance of v2.PrivateKey, which is
// an array with constant size.
// I'm dereferencing it to return a copy as well.
// Ref: https://go.dev/ref/spec#Conversions_from_slice_to_array_pointer
return *(*v2.PrivateKey)(p.Serialize()), nil
}

func (Herumi) SecretToPublicKey(secret v2.PrivateKey) (v2.PublicKey, error) {
var p bls.SecretKey

if err := p.Deserialize(secret[:]); err != nil {
return v2.PublicKey{}, errors.Wrap(err, "cannot unmarshal secret into Herumi secret key")
}

pubk, err := p.GetSafePublicKey()
if err != nil {
return v2.PublicKey{}, errors.Wrap(err, "cannot obtain public key from secret")
}

return *(*v2.PublicKey)(pubk.Serialize()), nil
}

func (Herumi) ThresholdSplit(secret v2.PrivateKey, total uint, threshold uint) (map[int]v2.PrivateKey, error) {
var p bls.SecretKey

if err := p.Deserialize(secret[:]); err != nil {
return nil, errors.Wrap(err, "cannot unmarshal bytes into Herumi secret key")
}

// master key Polynomial
poly := make([]bls.SecretKey, threshold)

poly[0] = p

// initialize threshold amount of points
for i := 1; i < int(threshold); i++ {
var sk bls.SecretKey
sk.SetByCSPRNG()
poly[i] = sk
}

ret := make(map[int]v2.PrivateKey)
for i := 1; i <= int(total); i++ {
var blsID bls.ID

err := blsID.SetDecString(fmt.Sprintf("%d", i))
if err != nil {
return nil, errors.Wrap(
err,
"cannot set ID",
z.Int("id_number", i),
z.Int("key_number", i),
)
}

var sk bls.SecretKey

err = sk.Set(poly, &blsID)
if err != nil {
return nil, errors.Wrap(err, "cannot set ID on polynomial", z.Int("id_number", i))
}

ret[i] = *(*v2.PrivateKey)(sk.Serialize())
}

return ret, nil
}

func (Herumi) RecoverSecret(shares map[int]v2.PrivateKey, _, _ uint) (v2.PrivateKey, error) {
var pk bls.SecretKey

var rawKeys []bls.SecretKey
var rawIDs []bls.ID

for idx, key := range shares {
// do a local copy, we're dealing with references here
key := key
var kpk bls.SecretKey
if err := kpk.Deserialize(key[:]); err != nil {
return v2.PrivateKey{}, errors.Wrap(
err,
"cannot unmarshal key with into Herumi secret key",
z.Int("key_number", idx),
)
}

rawKeys = append(rawKeys, kpk)

var id bls.ID
if err := id.SetDecString(strconv.Itoa(idx)); err != nil {
return v2.PrivateKey{}, errors.Wrap(
err,
"private key isn't a number",
z.Int("key_number", idx),
)
}

rawIDs = append(rawIDs, id)
}

if err := pk.Recover(rawKeys, rawIDs); err != nil {
return v2.PrivateKey{}, errors.Wrap(err, "cannot recover full private key from partial keys")
}

return *(*v2.PrivateKey)(pk.Serialize()), nil
}

func (Herumi) ThresholdAggregate(partialSignaturesByIndex map[int]v2.Signature) (v2.Signature, error) {
var rawSigns []bls.Sign
var rawIDs []bls.ID

for idx, rawSignature := range partialSignaturesByIndex {
// do a local copy, we're dealing with references here
rawSignature := rawSignature
var signature bls.Sign
if err := signature.Deserialize(rawSignature[:]); err != nil {
return v2.Signature{}, errors.Wrap(
err,
"cannot unmarshal signature into Herumi signature",
z.Int("signature_number", idx),
)
}

rawSigns = append(rawSigns, signature)

var id bls.ID
if err := id.SetDecString(strconv.Itoa(idx)); err != nil {
return v2.Signature{}, errors.Wrap(
err,
"signature id isn't a number",
z.Int("signature_number", idx),
)
}

rawIDs = append(rawIDs, id)
}

var complete bls.Sign

if err := complete.Recover(rawSigns, rawIDs); err != nil {
return v2.Signature{}, errors.Wrap(err, "cannot combine signatures")
}

return *(*v2.Signature)(complete.Serialize()), nil
}

func (Herumi) Verify(compressedPublicKey v2.PublicKey, data []byte, rawSignature v2.Signature) error {
var pubKey bls.PublicKey
if err := pubKey.Deserialize(compressedPublicKey[:]); err != nil {
return errors.Wrap(err, "cannot set compressed public key in Herumi format")
}

var signature bls.Sign
if err := signature.Deserialize(rawSignature[:]); err != nil {
return errors.Wrap(err, "cannot unmarshal signature into Herumi signature")
}

if !signature.VerifyByte(&pubKey, data) {
return errors.New("signature not verified")
}

return nil
}

func (Herumi) Sign(privateKey v2.PrivateKey, data []byte) (v2.Signature, error) {
var p bls.SecretKey

if err := p.Deserialize(privateKey[:]); err != nil {
return v2.Signature{}, errors.Wrap(err, "cannot unmarshal secret into Herumi secret key")
}

sigBytes := p.SignByte(data).Serialize()

return *(*v2.Signature)(sigBytes), nil
}
Loading