Skip to content

Commit

Permalink
Added JSONReGetGroup for JSON unmarshalling of group scalars and elem…
Browse files Browse the repository at this point in the history
…ents (#3)

Signed-off-by: bytemare <[email protected]>
  • Loading branch information
bytemare authored Oct 4, 2024
1 parent e3c27dc commit 390cb9d
Show file tree
Hide file tree
Showing 14 changed files with 264 additions and 11 deletions.
61 changes: 61 additions & 0 deletions encoding/json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// 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 encoding provides serde utilities.
package encoding

import (
"fmt"
"regexp"
"strconv"

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

func jsonReGetField(key, s, catch string) (string, error) {
r := fmt.Sprintf(`%q:%s`, key, catch)
re := regexp.MustCompile(r)
matches := re.FindStringSubmatch(s)

if len(matches) != 2 {
return "", internal.ErrDecodingInvalidJSONEncoding
}

return matches[1], nil
}

// JSONReGetGroup attempts to find the group JSON encoding in s. The optional key argument overrides the default key the
// regex will use to look for the group.
func JSONReGetGroup(s string, key ...string) (ecc.Group, error) {
reKey := "group"
if len(key) != 0 && key[0] != "" {
reKey = key[0]
}

f, err := jsonReGetField(reKey, s, `(\w+)`)
if err != nil {
return 0, err
}

i, err := strconv.Atoi(f)
if err != nil {
return 0, fmt.Errorf("failed to read Group: %w", err)
}

if i < 0 || i > 63 {
return 0, internal.ErrInvalidGroup
}

c := ecc.Group(i)
if !c.Available() {
return 0, internal.ErrInvalidGroup
}

return c, nil
}
9 changes: 9 additions & 0 deletions internal/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ import (
)

var (
// ErrInvalidGroup indicates usage of an unavailable or invalid group.
ErrInvalidGroup = errors.New("invalid group")

// ErrParamNilScalar indicates a forbidden nil or empty scalar.
ErrParamNilScalar = errors.New("nil or empty scalar")

Expand Down Expand Up @@ -54,6 +57,12 @@ var (

// ErrUInt64TooBig indicates that the scalar is higher than the allowed values for uint64.
ErrUInt64TooBig = errors.New("scalar is too big to be uint64")

// ErrDecodingInvalidLength indicates an invalid encoding length.
ErrDecodingInvalidLength = errors.New("invalid encoding length")

// ErrDecodingInvalidJSONEncoding indicates an invalid JSON encoding.
ErrDecodingInvalidJSONEncoding = errors.New("invalid JSON encoding")
)

// An Encoder can encode itself to machine or human-readable forms.
Expand Down
2 changes: 1 addition & 1 deletion tests/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

package group_test
package ecc_test

import (
"bytes"
Expand Down
2 changes: 1 addition & 1 deletion tests/element_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

package group_test
package ecc_test

import (
"encoding/hex"
Expand Down
52 changes: 51 additions & 1 deletion tests/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

package group_test
package ecc_test

import (
"bytes"
Expand All @@ -19,6 +19,7 @@ import (
"testing"

"github.com/bytemare/ecc"
eccEncoding "github.com/bytemare/ecc/encoding"
)

type serde interface {
Expand Down Expand Up @@ -263,3 +264,52 @@ func TestEncoding_Hex_Fails(t *testing.T) {
}
})
}

func TestJSONReGetGroup(t *testing.T) {
testAllGroups(t, func(group *testGroup) {
test := struct {
Group ecc.Group `json:"group"`
Int int `json:"int"`
}{
Group: group.group,
Int: 1,
}

enc, err := json.Marshal(test)
if err != nil {
t.Fatal(err)
}

g, err := eccEncoding.JSONReGetGroup(string(enc))
if err != nil {
t.Fatal(err)
}

if g != group.group {
t.Fatal(errExpectedEquality)
}

// with another key
test2 := struct {
Group ecc.Group `json:"ciphersuite"`
Int int `json:"int"`
}{
Group: group.group,
Int: 1,
}

enc, err = json.Marshal(test2)
if err != nil {
t.Fatal(err)
}

g, err = eccEncoding.JSONReGetGroup(string(enc), "ciphersuite")
if err != nil {
t.Fatal(err)
}

if g != group.group {
t.Fatal(errExpectedEquality)
}
})
}
2 changes: 1 addition & 1 deletion tests/groups_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

package group_test
package ecc_test

import (
"encoding/hex"
Expand Down
2 changes: 1 addition & 1 deletion tests/h2c_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

package group_test
package ecc_test

import (
"crypto/elliptic"
Expand Down
133 changes: 133 additions & 0 deletions tests/json_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// 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 ecc_test

import (
"encoding/json"
"fmt"
"strings"
"testing"

"github.com/bytemare/ecc"
eccEncoding "github.com/bytemare/ecc/encoding"
"github.com/bytemare/ecc/internal"
)

func replaceStringInBytes(data []byte, old, new string) []byte {
s := string(data)
s = strings.Replace(s, old, new, 1)

return []byte(s)
}

type jsonTesterBaddie struct {
key, value, expectedError string
}

func testJSONBaddie(in any, baddie jsonTesterBaddie) error {
data, err := json.Marshal(in)
if err != nil {
return err
}

data = replaceStringInBytes(data, baddie.key, baddie.value)

_, err = eccEncoding.JSONReGetGroup(string(data))

if len(baddie.expectedError) != 0 { // we're expecting an error
if err == nil ||
!strings.HasPrefix(err.Error(), baddie.expectedError) {
return fmt.Errorf("expected error %q, got %q", baddie.expectedError, err)
}
} else {
if err != nil {
return fmt.Errorf("unexpected error %q", err)
}
}

return nil
}

func jsonTester(badJSONErr string, in any) error {
// JSON: bad json
baddie := jsonTesterBaddie{
key: "\"group\"",
value: "bad",
expectedError: "invalid character 'b' looking for beginning of object key string",
}

if err := testJSONBaddie(in, baddie); err != nil {
// return err
}

// UnmarshallJSON: bad group
baddie = jsonTesterBaddie{
key: "\"group\"",
value: "\"group\":2, \"oldGroup\"",
expectedError: internal.ErrInvalidGroup.Error(),
}

if err := testJSONBaddie(in, baddie); err != nil {
return err
}

// UnmarshallJSON: bad ciphersuite
baddie = jsonTesterBaddie{
key: "\"group\"",
value: "\"group\":70, \"oldGroup\"",
expectedError: internal.ErrInvalidGroup.Error(),
}

if err := testJSONBaddie(in, baddie); err != nil {
return err
}

// UnmarshallJSON: bad ciphersuite
baddie = jsonTesterBaddie{
key: "\"group\"",
value: "\"group\":-1, \"oldGroup\"",
expectedError: badJSONErr,
}

if err := testJSONBaddie(in, baddie); err != nil {
return err
}

// UnmarshallJSON: bad ciphersuite
overflow := "9223372036854775808" // MaxInt64 + 1
baddie = jsonTesterBaddie{
key: "\"group\"",
value: "\"group\":" + overflow + ", \"oldGroup\"",
expectedError: "failed to read Group: strconv.Atoi: parsing \"9223372036854775808\": value out of range",
}

if err := testJSONBaddie(in, baddie); err != nil {
return err
}

return nil
}

func TestJSONReGetGroup_BadString(t *testing.T) {
testAllGroups(t, func(group *testGroup) {
test := struct {
Group ecc.Group `json:"group"`
Int int `json:"int"`
}{
Group: group.group,
Int: 1,
}

// JSON: bad json
errInvalidJSON := "invalid JSON encoding"
if err := jsonTester(errInvalidJSON, test); err != nil {
t.Fatal(err)
}
})
}
2 changes: 1 addition & 1 deletion tests/nist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

package group_test
package ecc_test

import (
"crypto/elliptic"
Expand Down
2 changes: 1 addition & 1 deletion tests/ristretto_hash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

package group_test
package ecc_test

import (
"bytes"
Expand Down
2 changes: 1 addition & 1 deletion tests/ristretto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

package group_test
package ecc_test

import (
"bytes"
Expand Down
2 changes: 1 addition & 1 deletion tests/scalar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

package group_test
package ecc_test

import (
"bytes"
Expand Down
2 changes: 1 addition & 1 deletion tests/table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

package group_test
package ecc_test

import (
"crypto"
Expand Down
2 changes: 1 addition & 1 deletion tests/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

package group_test
package ecc_test

import (
"encoding/hex"
Expand Down

0 comments on commit 390cb9d

Please sign in to comment.