Skip to content

Commit

Permalink
Use the group-specific scalar type when hashing in BDN (#553)
Browse files Browse the repository at this point in the history
Previously, `hashPointToR` would always use `mod.Int` but that only
works with the Kilic backend. This change makes the BDN scheme work with
all backends.
  • Loading branch information
Stebalien authored Sep 24, 2024
1 parent 0ba2750 commit 4de3374
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 30 deletions.
17 changes: 9 additions & 8 deletions sign/bdn/bdn.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,20 @@ import (
"crypto/cipher"
"errors"
"fmt"
"math/big"
"slices"

"go.dedis.ch/kyber/v4"
"go.dedis.ch/kyber/v4/group/mod"
"go.dedis.ch/kyber/v4/pairing"
"go.dedis.ch/kyber/v4/sign"
"go.dedis.ch/kyber/v4/sign/bls"
"golang.org/x/crypto/blake2s"
)

// modulus128 can be provided to the big integer implementation to create numbers
// over 128 bits
var modulus128 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 128), big.NewInt(1))

// For the choice of H, we're mostly worried about the second preimage attack. In
// other words, find m' where H(m) == H(m')
// We also use the entire roster so that the coefficient will vary for the same
// public key used in different roster
func hashPointToR(pubs []kyber.Point) ([]kyber.Scalar, error) {
func hashPointToR(group kyber.Group, pubs []kyber.Point) ([]kyber.Scalar, error) {
h, err := blake2s.NewXOF(blake2s.OutputLengthUnknown, nil)
if err != nil {
return nil, err
Expand All @@ -55,7 +50,13 @@ func hashPointToR(pubs []kyber.Point) ([]kyber.Scalar, error) {

coefs := make([]kyber.Scalar, len(pubs))
for i := range coefs {
coefs[i] = mod.NewIntBytes(out[i*16:(i+1)*16], modulus128, kyber.LittleEndian)
scalar := group.Scalar()
bytes := out[i*16 : (i+1)*16]
if scalar.ByteOrder() != kyber.LittleEndian {
slices.Reverse(bytes)
}
scalar.SetBytes(bytes)
coefs[i] = scalar
}

return coefs, nil
Expand Down
22 changes: 8 additions & 14 deletions sign/bdn/bdn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,14 @@ func TestBDN_HashPointToR_BN256(t *testing.T) {
p2 := suite.Point().Mul(two, suite.Point().Base())
p3 := suite.Point().Mul(three, suite.Point().Base())

coefs, err := hashPointToR([]kyber.Point{p1, p2, p3})
coefs, err := hashPointToR(suite, []kyber.Point{p1, p2, p3})

require.NoError(t, err)
require.Equal(t, "35b5b395f58aba3b192fb7e1e5f2abd3", coefs[0].String())
require.Equal(t, "14dcc79d46b09b93075266e47cd4b19e", coefs[1].String())
require.Equal(t, "933f6013eb3f654f9489d6d45ad04eaf", coefs[2].String())
require.Equal(t, 16, coefs[0].MarshalSize())

mask, _ := NewMask([]kyber.Point{p1, p2, p3}, nil)
mask, _ := NewMask(suite, []kyber.Point{p1, p2, p3}, nil)
mask.SetBit(0, true)
mask.SetBit(1, true)
mask.SetBit(2, true)
Expand All @@ -48,15 +47,14 @@ func TestBDN_HashPointToR_BN256(t *testing.T) {

func TestBDN_AggregateSignatures(t *testing.T) {
msg := []byte("Hello Boneh-Lynn-Shacham")
suite := bn256.NewSuite()
private1, public1 := NewKeyPair(suite, random.New())
private2, public2 := NewKeyPair(suite, random.New())
sig1, err := Sign(suite, private1, msg)
require.NoError(t, err)
sig2, err := Sign(suite, private2, msg)
require.NoError(t, err)

mask, _ := NewMask([]kyber.Point{public1, public2}, nil)
mask, _ := NewMask(suite, []kyber.Point{public1, public2}, nil)
mask.SetBit(0, true)
mask.SetBit(1, true)

Expand Down Expand Up @@ -85,7 +83,6 @@ func TestBDN_AggregateSignatures(t *testing.T) {

func TestBDN_SubsetSignature(t *testing.T) {
msg := []byte("Hello Boneh-Lynn-Shacham")
suite := bn256.NewSuite()
private1, public1 := NewKeyPair(suite, random.New())
private2, public2 := NewKeyPair(suite, random.New())
_, public3 := NewKeyPair(suite, random.New())
Expand All @@ -94,7 +91,7 @@ func TestBDN_SubsetSignature(t *testing.T) {
sig2, err := Sign(suite, private2, msg)
require.NoError(t, err)

mask, _ := NewMask([]kyber.Point{public1, public3, public2}, nil)
mask, _ := NewMask(suite, []kyber.Point{public1, public3, public2}, nil)
mask.SetBit(0, true)
mask.SetBit(2, true)

Expand All @@ -113,7 +110,6 @@ func TestBDN_SubsetSignature(t *testing.T) {

func TestBDN_RogueAttack(t *testing.T) {
msg := []byte("Hello Boneh-Lynn-Shacham")
suite := bn256.NewSuite()
scheme := bls.NewSchemeOnG1(suite)
// honest
_, public1 := scheme.NewKeyPair(random.New())
Expand All @@ -133,7 +129,7 @@ func TestBDN_RogueAttack(t *testing.T) {
require.NoError(t, scheme.Verify(agg, msg, sig))

// New scheme that should detect
mask, _ := NewMask(pubs, nil)
mask, _ := NewMask(suite, pubs, nil)
mask.SetBit(0, true)
mask.SetBit(1, true)
agg, err = AggregatePublicKeys(suite, mask)
Expand All @@ -142,7 +138,6 @@ func TestBDN_RogueAttack(t *testing.T) {
}

func Benchmark_BDN_AggregateSigs(b *testing.B) {
suite := bn256.NewSuite()
private1, public1 := NewKeyPair(suite, random.New())
private2, public2 := NewKeyPair(suite, random.New())
msg := []byte("Hello many times Boneh-Lynn-Shacham")
Expand All @@ -151,7 +146,7 @@ func Benchmark_BDN_AggregateSigs(b *testing.B) {
sig2, err := Sign(suite, private2, msg)
require.Nil(b, err)

mask, _ := NewMask([]kyber.Point{public1, public2}, nil)
mask, _ := NewMask(suite, []kyber.Point{public1, public2}, nil)
mask.SetBit(0, true)
mask.SetBit(1, false)

Expand All @@ -172,7 +167,7 @@ func Benchmark_BDN_BLS12381_AggregateVerify(b *testing.B) {
privKeys[i], pubKeys[i] = schemeOnG2.NewKeyPair(rng)
}

mask, err := NewMask(pubKeys, nil)
mask, err := NewMask(suite.G1(), pubKeys, nil)
require.NoError(b, err)
for i := range pubKeys {
require.NoError(b, mask.SetBit(i, true))
Expand Down Expand Up @@ -210,7 +205,6 @@ func unmarshalHex[T encoding.BinaryUnmarshaler](t *testing.T, into T, s string)
// This tests exists to make sure we don't accidentally make breaking changes to signature
// aggregation by using checking against known aggregated signatures and keys.
func TestBDNFixtures(t *testing.T) {
suite := bn256.NewSuite()
schemeOnG1 := NewSchemeOnG1(suite)

public1 := unmarshalHex(t, suite.G2().Point(), "1a30714035c7a161e286e54c191b8c68345bd8239c74925a26290e8e1ae97ed6657958a17dca12c943fadceb11b824402389ff427179e0f10194da3c1b771c6083797d2b5915ea78123cbdb99ea6389d6d6b67dcb512a2b552c373094ee5693524e3ebb4a176f7efa7285c25c80081d8cb598745978f1a63b886c09a316b1493")
Expand Down Expand Up @@ -243,7 +237,7 @@ func TestBDNFixtures(t *testing.T) {
require.Nil(t, err)
require.Equal(t, sig3Exp, sig3)

mask, _ := NewMask([]kyber.Point{public1, public2, public3}, nil)
mask, _ := NewMask(suite, []kyber.Point{public1, public2, public3}, nil)
mask.SetBit(0, true)
mask.SetBit(1, false)
mask.SetBit(2, true)
Expand Down
4 changes: 2 additions & 2 deletions sign/bdn/mask.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type Mask struct {
// The returned Mask will contain pre-computed terms and coefficients for all provided public
// keys, so it should be re-used for optimal performance (e.g., by creating a "base" mask and
// cloning it whenever aggregating signatures and/or public keys).
func NewMask(publics []kyber.Point, myKey kyber.Point) (*Mask, error) {
func NewMask(group kyber.Group, publics []kyber.Point, myKey kyber.Point) (*Mask, error) {
m := &Mask{
publics: publics,
}
Expand All @@ -49,7 +49,7 @@ func NewMask(publics []kyber.Point, myKey kyber.Point) (*Mask, error) {
}

var err error
m.publicCoefs, err = hashPointToR(publics)
m.publicCoefs, err = hashPointToR(group, publics)
if err != nil {
return nil, fmt.Errorf("failed to hash public keys: %w", err)
}
Expand Down
12 changes: 6 additions & 6 deletions sign/bdn/mask_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func init() {
}

func TestMask_CreateMask(t *testing.T) {
mask, err := NewMask(publics, nil)
mask, err := NewMask(suite, publics, nil)
require.NoError(t, err)

require.Equal(t, len(publics), len(mask.Publics()))
Expand All @@ -32,19 +32,19 @@ func TestMask_CreateMask(t *testing.T) {
require.Equal(t, n/8+1, mask.Len())
require.Equal(t, uint8(0), mask.Mask()[0])

mask, err = NewMask(publics, publics[2])
mask, err = NewMask(suite, publics, publics[2])
require.NoError(t, err)

require.Equal(t, len(publics), len(mask.Publics()))
require.Equal(t, 1, mask.CountEnabled())
require.Equal(t, uint8(0x4), mask.Mask()[0])

_, err = NewMask(publics, suite.G1().Point())
_, err = NewMask(suite, publics, suite.G1().Point())
require.Error(t, err)
}

func TestMask_SetBit(t *testing.T) {
mask, err := NewMask(publics, publics[2])
mask, err := NewMask(suite, publics, publics[2])
require.NoError(t, err)

// Make sure the mask is initially as we'd expect.
Expand Down Expand Up @@ -111,7 +111,7 @@ func TestMask_SetBit(t *testing.T) {
}

func TestMask_SetAndMerge(t *testing.T) {
mask, err := NewMask(publics, publics[2])
mask, err := NewMask(suite, publics, publics[2])
require.NoError(t, err)

err = mask.SetMask([]byte{})
Expand All @@ -129,7 +129,7 @@ func TestMask_SetAndMerge(t *testing.T) {
}

func TestMask_PositionalQueries(t *testing.T) {
mask, err := NewMask(publics, publics[2])
mask, err := NewMask(suite, publics, publics[2])
require.NoError(t, err)

for i := 0; i < 10000; i++ {
Expand Down

0 comments on commit 4de3374

Please sign in to comment.