From 4de33740016e6b6a3c1aff054597262be39eeadb Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 24 Sep 2024 13:24:04 +0000 Subject: [PATCH] Use the group-specific scalar type when hashing in BDN (#553) 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. --- sign/bdn/bdn.go | 17 +++++++++-------- sign/bdn/bdn_test.go | 22 ++++++++-------------- sign/bdn/mask.go | 4 ++-- sign/bdn/mask_test.go | 12 ++++++------ 4 files changed, 25 insertions(+), 30 deletions(-) diff --git a/sign/bdn/bdn.go b/sign/bdn/bdn.go index 71dc6326..141a0b70 100644 --- a/sign/bdn/bdn.go +++ b/sign/bdn/bdn.go @@ -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 @@ -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 diff --git a/sign/bdn/bdn_test.go b/sign/bdn/bdn_test.go index b686e4a6..64eec571 100644 --- a/sign/bdn/bdn_test.go +++ b/sign/bdn/bdn_test.go @@ -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) @@ -48,7 +47,6 @@ 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) @@ -56,7 +54,7 @@ func TestBDN_AggregateSignatures(t *testing.T) { 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) @@ -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()) @@ -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) @@ -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()) @@ -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) @@ -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") @@ -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) @@ -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)) @@ -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") @@ -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) diff --git a/sign/bdn/mask.go b/sign/bdn/mask.go index a6a6fd78..8e695b87 100644 --- a/sign/bdn/mask.go +++ b/sign/bdn/mask.go @@ -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, } @@ -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) } diff --git a/sign/bdn/mask_test.go b/sign/bdn/mask_test.go index f87cf270..9cccecab 100644 --- a/sign/bdn/mask_test.go +++ b/sign/bdn/mask_test.go @@ -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())) @@ -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. @@ -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{}) @@ -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++ {