Skip to content

Commit

Permalink
Added kilic bls12-381
Browse files Browse the repository at this point in the history
  • Loading branch information
matteosz committed Feb 25, 2024
1 parent d12180b commit 10b5a6f
Show file tree
Hide file tree
Showing 16 changed files with 1,337 additions and 14 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module go.dedis.ch/kyber/v3

require (
github.com/cloudflare/circl v1.3.7
github.com/kilic/bls12-381 v0.1.0
github.com/stretchr/testify v1.3.0
go.dedis.ch/fixbuf v1.0.3
go.dedis.ch/protobuf v1.0.11
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vc
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4=
github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down Expand Up @@ -37,6 +39,7 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
4 changes: 4 additions & 0 deletions group.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ type Point interface {
Mul(s Scalar, p Point) Point
}

type HashablePoint interface {
Hash([]byte) Point
}

// AllowsVarTime allows callers to determine if a given kyber.Scalar
// or kyber.Point supports opting-in to variable time operations. If
// an object implements AllowsVarTime, then the caller can use
Expand Down
2 changes: 1 addition & 1 deletion pairing/circl_bls12381/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ func (s *SuiteBLS12381) ScalarLen() int {

// String returns the name of the suite
func (s *SuiteBLS12381) String() string {
return "bls12381.adapter"
return "circl_bls12381.adapter"
}
2 changes: 1 addition & 1 deletion pairing/circl_bls12381/adapter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ func TestAdapter_SuiteBLS12381(t *testing.T) {
err = privhex.UnmarshalBinary(privkey)
require.Nil(t, err)

require.Equal(t, "bls12381.adapter", suite.String())
require.Equal(t, "circl_bls12381.adapter", suite.String())
}
48 changes: 48 additions & 0 deletions pairing/kilic_bls12381/adapter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package kilic_bls12381

import (
"go.dedis.ch/kyber/v3"
)

// SuiteBLS12381 is an adapter that implements the suites.Suite interface so that
// bls12381 can be used as a common suite to generate key pairs for instance but
// still preserves the properties of the pairing (e.g. the Pair function).
//
// It's important to note that the Point function will generate a point
// compatible with public keys only (group G2) where the signature must be
// used as a point from the group G1.
type SuiteBLS12381 struct {
Suite
kyber.Group
}

// NewSuiteBLS12381 makes a new BN256 suite
func NewSuiteBLS12381() *SuiteBLS12381 {
return &SuiteBLS12381{}
}

// Point generates a point from the G2 group that can only be used
// for public keys
func (s *SuiteBLS12381) Point() kyber.Point {
return s.G2().Point()
}

// PointLen returns the length of a G2 point
func (s *SuiteBLS12381) PointLen() int {
return s.G2().PointLen()
}

// Scalar generates a scalar
func (s *SuiteBLS12381) Scalar() kyber.Scalar {
return s.G1().Scalar()
}

// ScalarLen returns the lenght of a scalar
func (s *SuiteBLS12381) ScalarLen() int {
return s.G1().ScalarLen()
}

// String returns the name of the suite
func (s *SuiteBLS12381) String() string {
return "kilic_bls12381.adapter"
}
28 changes: 28 additions & 0 deletions pairing/kilic_bls12381/adapter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package kilic_bls12381

import (
"testing"

"github.com/stretchr/testify/require"
"go.dedis.ch/kyber/v3/util/key"
)

func TestAdapter_SuiteBLS12381(t *testing.T) {
suite := NewSuiteBLS12381()

pair := key.NewKeyPair(suite)
pubkey, err := pair.Public.MarshalBinary()
require.Nil(t, err)
privkey, err := pair.Private.MarshalBinary()
require.Nil(t, err)

pubhex := suite.Point()
err = pubhex.UnmarshalBinary(pubkey)
require.Nil(t, err)

privhex := suite.Scalar()
err = privhex.UnmarshalBinary(privkey)
require.Nil(t, err)

require.Equal(t, "kilic_bls12381.adapter", suite.String())
}
172 changes: 172 additions & 0 deletions pairing/kilic_bls12381/g1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package kilic_bls12381

import (
"bytes"
"crypto/cipher"
"encoding/hex"
"io"

bls12381 "github.com/kilic/bls12-381"
"go.dedis.ch/kyber/v3"
"go.dedis.ch/kyber/v3/group/mod"
)

// domainG1 is the DST used for hash to curve on G1, this is the default from the RFC.
var domainG1 = []byte("BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_")

func DefaultDomainG1() []byte {
return domainG1
}

// KyberG1 is a kyber.Point holding a G1 point on BLS12-381 curve
type KyberG1 struct {
p *bls12381.PointG1
// domain separation tag. We treat a 0 len dst as the default value as per the RFC "Tags MUST have nonzero length"
dst []byte

kyber.Point
kyber.HashablePoint
}

func NullKyberG1(dst ...byte) *KyberG1 {
var p bls12381.PointG1
return newKyberG1(&p, dst)
}
func newKyberG1(p *bls12381.PointG1, dst []byte) *KyberG1 {
domain := dst
if bytes.Equal(dst, domainG1) {
domain = nil
}
return &KyberG1{p: p, dst: domain}
}

func (k *KyberG1) Equal(k2 kyber.Point) bool {
k2g1, ok := k2.(*KyberG1)
if !ok {
return false
}
return bls12381.NewG1().Equal(k.p, k2g1.p) && bytes.Equal(k.dst, k2g1.dst)
}

func (k *KyberG1) Null() kyber.Point {
return newKyberG1(bls12381.NewG1().Zero(), k.dst)
}

func (k *KyberG1) Base() kyber.Point {
return newKyberG1(bls12381.NewG1().One(), k.dst)
}

func (k *KyberG1) Pick(rand cipher.Stream) kyber.Point {
var dst, src [32]byte
rand.XORKeyStream(dst[:], src[:])
return k.Hash(dst[:])
}

func (k *KyberG1) Set(q kyber.Point) kyber.Point {
k.p.Set(q.(*KyberG1).p)
return k
}

func (k *KyberG1) Clone() kyber.Point {
var p bls12381.PointG1
p.Set(k.p)
return newKyberG1(&p, k.dst)
}

func (k *KyberG1) EmbedLen() int {
panic("bls12-381: unsupported operation")
}

func (k *KyberG1) Embed(data []byte, rand cipher.Stream) kyber.Point {
panic("bls12-381: unsupported operation")
}

func (k *KyberG1) Data() ([]byte, error) {
panic("bls12-381: unsupported operation")
}

func (k *KyberG1) Add(a, b kyber.Point) kyber.Point {
aa := a.(*KyberG1)
bb := b.(*KyberG1)
bls12381.NewG1().Add(k.p, aa.p, bb.p)
return k
}

func (k *KyberG1) Sub(a, b kyber.Point) kyber.Point {
aa := a.(*KyberG1)
bb := b.(*KyberG1)
bls12381.NewG1().Sub(k.p, aa.p, bb.p)
return k
}

func (k *KyberG1) Neg(a kyber.Point) kyber.Point {
aa := a.(*KyberG1)
bls12381.NewG1().Neg(k.p, aa.p)
return k
}

func (k *KyberG1) Mul(s kyber.Scalar, q kyber.Point) kyber.Point {
if q == nil {
q = NullKyberG1(k.dst...).Base()
}
bls12381.NewG1().MulScalarBig(k.p, q.(*KyberG1).p, &s.(*mod.Int).V)
return k
}

// MarshalBinary returns a compressed point, without any domain separation tag information
func (k *KyberG1) MarshalBinary() ([]byte, error) {
// we need to clone the point because of https://github.com/kilic/bls12-381/issues/37
// in order to avoid risks of race conditions.
t := new(bls12381.PointG1).Set(k.p)
return bls12381.NewG1().ToCompressed(t), nil
}

// UnmarshalBinary populates the point from a compressed point representation.
func (k *KyberG1) UnmarshalBinary(buff []byte) error {
var err error
k.p, err = bls12381.NewG1().FromCompressed(buff)
return err
}

// MarshalTo writes a compressed point to the Writer, without any domain separation tag information
func (k *KyberG1) MarshalTo(w io.Writer) (int, error) {
buf, err := k.MarshalBinary()
if err != nil {
return 0, err
}
return w.Write(buf)
}

// UnmarshalFrom populates the point from a compressed point representation read from the Reader.
func (k *KyberG1) UnmarshalFrom(r io.Reader) (int, error) {
buf := make([]byte, k.MarshalSize())
n, err := io.ReadFull(r, buf)
if err != nil {
return n, err
}
return n, k.UnmarshalBinary(buf)
}

func (k *KyberG1) MarshalSize() int {
return 48
}

func (k *KyberG1) String() string {
b, _ := k.MarshalBinary()
return "bls12-381.G1: " + hex.EncodeToString(b)
}

func (k *KyberG1) Hash(m []byte) kyber.Point {
domain := domainG1
// We treat a 0 len dst as the default value as per the RFC "Tags MUST have nonzero length"
if len(k.dst) != 0 {
domain = k.dst
}
p, _ := bls12381.NewG1().HashToCurve(m, domain)
k.p = p
return k
}

func (k *KyberG1) IsInCorrectGroup() bool {
return bls12381.NewG1().InCorrectSubgroup(k.p)
}
Loading

0 comments on commit 10b5a6f

Please sign in to comment.