Skip to content

Commit

Permalink
added debug data for bad scalars and elements + fixed some tests (#2)
Browse files Browse the repository at this point in the history
* added debug data for bad scalars and elements + fixed some tests

---------

Signed-off-by: bytemare <3641580+bytemare@users.noreply.github.com>
  • Loading branch information
bytemare authored Oct 4, 2024
1 parent a8c0b1c commit e3c27dc
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 47 deletions.
11 changes: 4 additions & 7 deletions .github/.golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,10 @@ issues:
#- "do not define dynamic errors, use wrapped static errors instead"
#- "missing cases in switch of type Group: maxID"

#exclude-rules:
# - path: internal/hash.go
# linters:
# - errcheck
# - path: internal/tag/strings.go
# linters:
# - gosec
exclude-rules:
- path: debug/debug.go
linters:
- dupl

max-issues-per-linter: 0
max-same-issues: 0
Expand Down
121 changes: 121 additions & 0 deletions debug/debug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// SPDX-License-Identifier: MIT
//
// Copyright (C) 2020-2024 Daniel Bourdrez. All Rights Reserved.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

// Package debug provides tools to help debugging.
package debug

import (
"github.com/bytemare/ecc"
)

var groupOrderPlusOne = map[ecc.Group][]byte{
ecc.Ristretto255Sha512: {
238, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16,
},
ecc.P256Sha256: {
255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
188, 230, 250, 173, 167, 23, 158, 132, 243, 185, 202, 194, 252, 99, 37, 82,
},
ecc.P384Sha384: {
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 199, 99, 77, 129, 244, 55, 45, 223,
88, 26, 13, 178, 72, 176, 167, 122, 236, 236, 25, 106, 204, 197, 41, 116,
},
ecc.P521Sha512: {
1, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 250, 81, 134, 135, 131, 191, 47, 150, 107, 127, 204, 1, 72, 247, 9,
165, 208, 59, 181, 201, 184, 137, 156, 71, 174, 187, 111, 183, 30, 145, 56, 100, 10,
},
ecc.Edwards25519Sha512: {
238, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16,
},
ecc.Secp256k1Sha256: {
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254,
186, 174, 220, 230, 175, 72, 160, 59, 191, 210, 94, 140, 208, 54, 65, 66,
},
}

// BadScalarHigh returns an encoding of a Scalar above the group's order. Its decoding must return an error.
func BadScalarHigh(g ecc.Group) []byte {
return groupOrderPlusOne[g]
}

var fieldOrdersBE = map[ecc.Group][]byte{
ecc.Ristretto255Sha512: {
127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 237,
},
ecc.P256Sha256: {
2, 255, 255, 255, 255, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
},
ecc.P384Sha384: {
2, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
254, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255,
},
ecc.P521Sha512: {
2, 1, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255,
},
ecc.Edwards25519Sha512: {
127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 238,
},
ecc.Secp256k1Sha256: {
2, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 252, 47,
},
}

// BadElementOffCurve returns an encoding of an Element that is not on the group's underlying curve.
// Its decoding must return an error.
func BadElementOffCurve(g ecc.Group) []byte {
return fieldOrdersBE[g]
}

var badElements = map[ecc.Group][]byte{
ecc.Ristretto255Sha512: {
42, 41, 45, 247, 227, 44, 171, 171, 189, 157, 224, 136, 209, 209, 171, 236,
159, 192, 68, 15, 99, 126, 210, 251, 161, 69, 9, 77, 193, 75, 234, 8,
},
ecc.P256Sha256: {
180, 156, 135, 52, 186, 207, 78, 34, 25, 58, 107, 30, 29, 189, 67, 96,
27, 122, 38, 254, 237, 242, 41, 66, 32, 248, 155, 253, 65, 203, 45, 234, 107,
},
ecc.P384Sha384: {
106, 132, 66, 85, 228, 73, 52, 118, 169, 95, 39, 187, 201, 209, 229, 140,
210, 216, 37, 255, 4, 203, 27, 221, 46, 95, 40, 21, 137, 156, 131, 66,
9, 79, 116, 72, 160, 242, 218, 155, 55, 127, 93, 35, 226, 76, 213, 147, 228,
},
ecc.P521Sha512: {
202, 195, 75, 180, 128, 54, 127, 17, 106, 221, 70, 34, 192, 171, 83, 18,
235, 78, 198, 68, 239, 97, 123, 143, 59, 111, 105, 108, 148, 216, 48, 97,
44, 237, 67, 178, 233, 136, 147, 98, 102, 232, 99, 240, 98, 89, 54, 13, 149,
115, 147, 208, 140, 76, 95, 32, 54, 192, 66, 15, 187, 142, 94, 190, 85, 140, 220,
},
ecc.Edwards25519Sha512: {
239, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127,
},
ecc.Secp256k1Sha256: {
248, 194, 40, 96, 152, 251, 181, 46, 76, 234, 70, 112, 83, 163, 182, 140,
48, 35, 199, 44, 130, 86, 124, 138, 93, 210, 45, 56, 95, 208, 36, 234, 104,
},
}

// BadElementEncoding returns a bad encoding of an element. Its decoding must return an error.
func BadElementEncoding(g ecc.Group) []byte {
return badElements[g]
}
2 changes: 1 addition & 1 deletion internal/edwards25519/element.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func (e *Element) Decode(data []byte) error {

// superfluous identity check
if element.Equal(ed.NewIdentityPoint()) == 1 {
return internal.ErrIdentity
return fmt.Errorf("invalid edwards25519 encoding: %w", internal.ErrIdentity)
}

e.element = *element
Expand Down
2 changes: 1 addition & 1 deletion internal/ristretto/element.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func (e *Element) Decode(data []byte) error {

// superfluous identity check
if element.Equal(ristretto255.NewElement().Zero()) == 1 {
return internal.ErrIdentity
return fmt.Errorf("invalid Ristretto encoding: %w", internal.ErrIdentity)
}

e.element = *element
Expand Down
2 changes: 1 addition & 1 deletion internal/secp256k1/element.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func (e *Element) XCoordinate() []byte {
// Decode sets the receiver to a decoding of the input data, and returns an error on failure.
func (e *Element) Decode(data []byte) error {
if err := e.element.Decode(data); err != nil {
return fmt.Errorf("%w", err)
return fmt.Errorf("invalid secp256k1 encoding: %w", err)
}

return nil
Expand Down
88 changes: 61 additions & 27 deletions tests/element_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import (
"encoding/hex"
"errors"
"log"
"math/big"
"testing"

"github.com/bytemare/ecc"
"github.com/bytemare/ecc/debug"
"github.com/bytemare/ecc/internal"
)

Expand Down Expand Up @@ -172,10 +172,44 @@ func TestElement_EncodedLength(t *testing.T) {
})
}

func TestElement_Decode_OutOfBounds(t *testing.T) {
func TestElement_Decode_Identity(t *testing.T) {
testAllGroups(t, func(group *testGroup) {
decodeErr := "element Decode: "
unmarshallBinaryErr := "element UnmarshalBinary: "
errMessage := ""
switch group.group {
case ecc.Ristretto255Sha512:
errMessage = "invalid Ristretto encoding: infinity/identity point"
case ecc.P256Sha256:
errMessage = "invalid P256 point encoding"
case ecc.P384Sha384:
errMessage = "invalid P384 point encoding"
case ecc.P521Sha512:
errMessage = "invalid P521 point encoding"
case ecc.Edwards25519Sha512:
errMessage = "invalid edwards25519 encoding: infinity/identity point"
case ecc.Secp256k1Sha256:
errMessage = "invalid secp256k1 encoding: invalid point encoding"
}

decodeErr += errMessage

id := group.group.NewElement().Identity()

if !id.IsIdentity() {
t.Fatal(errExpectedIdentity)
}

expected := errors.New(decodeErr)
if err := group.group.NewElement().Decode(id.Encode()); err == nil || err.Error() != expected.Error() {
t.Errorf("expected error %q, got %v\n", expected, err)
}
})
}

func TestElement_Decode_Bad(t *testing.T) {
testAllGroups(t, func(group *testGroup) {
decodePrefix := "element Decode: "
unmarshallBinaryPrefix := "element UnmarshalBinary: "
errMessage := ""
switch group.group {
case ecc.Ristretto255Sha512:
Expand All @@ -189,41 +223,41 @@ func TestElement_Decode_OutOfBounds(t *testing.T) {
case ecc.Edwards25519Sha512:
errMessage = "edwards25519: invalid point encoding"
case ecc.Secp256k1Sha256:
errMessage = "invalid point encoding"
errMessage = "invalid secp256k1 encoding: invalid point encoding"
}

decodeErr += errMessage
unmarshallBinaryErr += errMessage

encoded := make([]byte, group.group.ElementLength())
// off curve
bad := debug.BadElementOffCurve(group.group)

y := big.NewInt(0)

x, ok := new(big.Int).SetString(group.fieldOrder, 0)
if !ok {
t.Fatalf("setting int in base %d failed: %v", 0, group.fieldOrder)
expected := errors.New(decodePrefix + errMessage)
if err := group.group.NewElement().Decode(bad); err == nil || err.Error() != expected.Error() {
t.Errorf("expected error %q, got %v\n", expected, err)
}

// x exceeds the order
x.Add(x, big.NewInt(1))
expected = errors.New(unmarshallBinaryPrefix + errMessage)
if err := group.group.NewElement().UnmarshalBinary(bad); err == nil || err.Error() != expected.Error() {
t.Errorf("expected error %q, got %v", expected, err)
}

// bad encoding, e.g. sign
switch group.group {
case ecc.Ristretto255Sha512, ecc.Edwards25519Sha512:
x.FillBytes(encoded)
case ecc.P256Sha256, ecc.P384Sha384, ecc.P521Sha512, ecc.Secp256k1Sha256:
encoded[0] = byte(2 | y.Bit(0)&1)
x.FillBytes(encoded[1:])
default:
t.Fatalf("non registered group %s", group.group)
case ecc.P256Sha256:
errMessage = "invalid P256 point encoding"
case ecc.P384Sha384:
errMessage = "invalid P384 point encoding"
case ecc.P521Sha512:
errMessage = "invalid P521 point encoding"
}

expected := errors.New(decodeErr)
if err := group.group.NewElement().Decode(encoded[:]); err == nil || err.Error() != expected.Error() {
t.Errorf("expected error %q, got %v", expected, err)
bad = debug.BadElementEncoding(group.group)

expected = errors.New(decodePrefix + errMessage)
if err := group.group.NewElement().Decode(bad); err == nil || err.Error() != expected.Error() {
t.Errorf("expected error %q, got %v\n", expected, err)
}

expected = errors.New(unmarshallBinaryErr)
if err := group.group.NewElement().UnmarshalBinary(encoded[:]); err == nil || err.Error() != expected.Error() {
expected = errors.New(unmarshallBinaryPrefix + errMessage)
if err := group.group.NewElement().UnmarshalBinary(bad); err == nil || err.Error() != expected.Error() {
t.Errorf("expected error %q, got %v", expected, err)
}
})
Expand Down
17 changes: 7 additions & 10 deletions tests/scalar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"testing"

"github.com/bytemare/ecc"
"github.com/bytemare/ecc/debug"
"github.com/bytemare/ecc/internal"
)

Expand Down Expand Up @@ -226,33 +227,29 @@ func TestScalar_Decode_OutOfBounds(t *testing.T) {

// Decode invalid length
errMessage := "invalid scalar length"
encoded := make([]byte, 2)
big.NewInt(1).FillBytes(encoded)
bad := []byte{0, 1}

expected := errors.New(decodeErrPrefix + errMessage)
if err := group.group.NewScalar().Decode(encoded); err == nil || err.Error() != expected.Error() {
if err := group.group.NewScalar().Decode(bad); err == nil || err.Error() != expected.Error() {
t.Errorf("expected error %q, got %v", expected, err)
}

expected = errors.New(unmarshallBinaryErrPrefix + errMessage)
if err := group.group.NewScalar().UnmarshalBinary(encoded); err == nil || err.Error() != expected.Error() {
if err := group.group.NewScalar().UnmarshalBinary(bad); err == nil || err.Error() != expected.Error() {
t.Errorf("expected error %q, got %v", expected, err)
}

// Decode a scalar higher than order
errMessage = "invalid scalar encoding"
encoded = make([]byte, group.group.ScalarLength())
order := new(big.Int).SetBytes(group.group.Order())
order.Add(order, big.NewInt(1))
order.FillBytes(encoded)
bad = debug.BadScalarHigh(group.group)

expected = errors.New(decodeErrPrefix + errMessage)
if err := group.group.NewScalar().Decode(encoded); err == nil || err.Error() != expected.Error() {
if err := group.group.NewScalar().Decode(bad); err == nil || err.Error() != expected.Error() {
t.Errorf("expected error %q, got %v", expected, err)
}

expected = errors.New(unmarshallBinaryErrPrefix + errMessage)
if err := group.group.NewScalar().UnmarshalBinary(encoded); err == nil || err.Error() != expected.Error() {
if err := group.group.NewScalar().UnmarshalBinary(bad); err == nil || err.Error() != expected.Error() {
t.Errorf("expected error %q, got %v", expected, err)
}
})
Expand Down

0 comments on commit e3c27dc

Please sign in to comment.