Skip to content
This repository has been archived by the owner on Oct 3, 2024. It is now read-only.

Commit

Permalink
Return groups for elements and scalars
Browse files Browse the repository at this point in the history
Signed-off-by: bytemare <[email protected]>
  • Loading branch information
bytemare committed Oct 1, 2024
1 parent 24e1bda commit 0a3f664
Show file tree
Hide file tree
Showing 24 changed files with 225 additions and 111 deletions.
5 changes: 5 additions & 0 deletions element.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ func newPoint(p internal.Element) *Element {
return &Element{Element: p}
}

// Group returns the group's Identifier.
func (e *Element) Group() Group {
return Group(e.Element.Group())
}

// Base sets the element to the group's base point a.k.a. canonical generator.
func (e *Element) Base() *Element {
return &Element{Element: e.Element.Base()}
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ require (

require (
github.com/bytemare/hash v0.3.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/sys v0.25.0 // indirect
)
12 changes: 4 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@ github.com/bytemare/secp256k1 v0.1.4 h1:6F1yP6RiUiWwH7AsGHsHktmHm24QcetdDcc39roB
github.com/bytemare/secp256k1 v0.1.4/go.mod h1:Pxb9miDs8PTt5mOktvvXiRflvLxI1wdxbXrc6IYsaho=
github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc=
github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
2 changes: 1 addition & 1 deletion groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const (
// Edwards25519Sha512 identifies the Edwards25519 group with SHA2-512 hash-to-group hashing.
Edwards25519Sha512

// Secp256k1 identifies the Secp256k1 group with SHA2-256 hash-to-group hashing.
// Secp256k1 identifies the SECp256k1 group with SHA2-256 hash-to-group hashing.
Secp256k1

maxID
Expand Down
5 changes: 5 additions & 0 deletions internal/edwards25519/element.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ func checkElement(element internal.Element) *Element {
return ec
}

// Group returns the group's Identifier.
func (e *Element) Group() byte {
return Identifier
}

// Base sets the element to the group's base point a.k.a. canonical generator.
func (e *Element) Base() internal.Element {
e.element.Set(ed.NewGeneratorPoint())
Expand Down
3 changes: 3 additions & 0 deletions internal/edwards25519/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import (
)

const (
// Identifier distinguishes this group from the others by a byte representation.
Identifier = byte(6)

canonicalEncodingLength = 32
orderPrime = "7237005577332262213973186563042994240857116359379907606001950938285454250989"
)
Expand Down
9 changes: 6 additions & 3 deletions internal/edwards25519/scalar.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ import (
"github.com/bytemare/crypto/internal"
)

const (
inputLength = 64
)
const inputLength = 64

var (
scZero Scalar
Expand Down Expand Up @@ -69,6 +67,11 @@ func (s *Scalar) set(scalar *ed.Scalar) {
s.scalar = *scalar
}

// Group returns the group's Identifier.
func (s *Scalar) Group() byte {
return Identifier
}

// Zero sets the scalar to 0, and returns it.
func (s *Scalar) Zero() internal.Scalar {
s.scalar = *ed.NewScalar()
Expand Down
3 changes: 3 additions & 0 deletions internal/element.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ package internal

// Element interface abstracts common operations on an Element in a prime-order Group.
type Element interface {
// Group returns the group's Identifier.
Group() byte

// Base sets the element to the group's base point a.k.a. canonical generator.
Base() Element

Expand Down
11 changes: 9 additions & 2 deletions internal/field/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type Field struct {
pMinus1div2 *big.Int // used in IsSquare
pMinus2 *big.Int // used for Field big.Int inversion
exp *big.Int
byteLen int
}

// NewField returns a newly instantiated field for the given prime order.
Expand All @@ -58,6 +59,7 @@ func NewField(prime *big.Int) Field {
pMinus1div2: pMinus1div2,
pMinus2: pMinus2,
exp: exp,
byteLen: (prime.BitLen() + 7) / 8,
}
}

Expand Down Expand Up @@ -89,9 +91,14 @@ func (f Field) Order() *big.Int {
return f.order
}

// BitLen of the order.
// BitLen returns the length of the field order in bits.
func (f Field) BitLen() int {
return f.order.BitLen()
return (f.byteLen * 8) - 7

Check warning on line 96 in internal/field/field.go

View check run for this annotation

Codecov / codecov/patch

internal/field/field.go#L96

Added line #L96 was not covered by tests
}

// ByteLen returns the length of the field order in bytes.
func (f Field) ByteLen() int {
return f.byteLen
}

// AreEqual returns whether both elements are equal.
Expand Down
2 changes: 1 addition & 1 deletion internal/nist/curve.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ var (
func (c *curve[point]) affineToPoint(pxc, pyc *big.Int) point {
var decompressed []byte

byteLen := (c.field.BitLen() + 7) / 8
byteLen := c.field.ByteLen()
switch byteLen {
case 32:
decompressed = decompressed256[:]
Expand Down
22 changes: 22 additions & 0 deletions internal/nist/element.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import (
"crypto/subtle"
"encoding/hex"
"fmt"
"reflect"

"filippo.io/nistec"

"github.com/bytemare/crypto/internal"
)
Expand Down Expand Up @@ -41,6 +44,25 @@ func checkElement[Point nistECPoint[Point]](element internal.Element) *Element[P
return ec
}

// Group returns the group's Identifier.
func (e *Element[Point]) Group() byte {
switch any(e.p).(type) {
case *nistec.P256Point:
return IdentifierP256
case *nistec.P384Point:
return IdentifierP384
case *nistec.P521Point:
return IdentifierP521
}

panic(
fmt.Sprintf(
"invalid group type, expected *nistec.P256Point/P384Point/P521Point, got %v",
reflect.TypeFor[Point](),
),
)

Check warning on line 63 in internal/nist/element.go

View check run for this annotation

Codecov / codecov/patch

internal/nist/element.go#L58-L63

Added lines #L58 - L63 were not covered by tests
}

// Base sets the element to the group's base point a.k.a. canonical generator.
func (e *Element[Point]) Base() internal.Element {
e.p.SetGenerator()
Expand Down
18 changes: 13 additions & 5 deletions internal/nist/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

// Package nist allows simple and abstracted operations in the NIST P-256, P-384, and P-521 groups.
// Package nist allows simple and abstracted operations in the NIST P-256, P-384, and
// P-521 groups, wrapping filippo.io/nistec.
package nist

import (
Expand Down Expand Up @@ -39,6 +40,15 @@ const (

// E2CP521 represents the encode-to-curve string identifier for P521.
E2CP521 = "P521_XMD:SHA-512_SSWU_NU_"

// IdentifierP256 distinguishes this group from the others by a byte representation.
IdentifierP256 = byte(3)

// IdentifierP384 distinguishes this group from the others by a byte representation.
IdentifierP384 = byte(4)

// IdentifierP521 distinguishes this group from the others by a byte representation.
IdentifierP521 = byte(5)
)

// P256 returns the single instantiation of the P256 Group.
Expand Down Expand Up @@ -140,14 +150,12 @@ func (g Group[P]) Ciphersuite() string {

// ScalarLength returns the byte size of an encoded element.
func (g Group[P]) ScalarLength() int {
byteLen := (g.scalarField.BitLen() + 7) / 8
return byteLen
return g.scalarField.ByteLen()
}

// ElementLength returns the byte size of an encoded element.
func (g Group[P]) ElementLength() int {
byteLen := (g.curve.field.BitLen() + 7) / 8
return 1 + byteLen
return 1 + g.scalarField.ByteLen()
}

// Order returns the order of the canonical group of scalars.
Expand Down
24 changes: 17 additions & 7 deletions internal/nist/scalar.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ func (s *Scalar) assert(scalar internal.Scalar) *Scalar {
return _sc
}

// Group returns the group's Identifier.
func (s *Scalar) Group() byte {
switch s.field.ByteLen() {
case 32:
return IdentifierP256
case 48:
return IdentifierP384
case 66:
return IdentifierP521
}

panic("invalid group type, expected nistec.P256Point/P384Point/P521Point")

Check warning on line 62 in internal/nist/scalar.go

View check run for this annotation

Codecov / codecov/patch

internal/nist/scalar.go#L62

Added line #L62 was not covered by tests
}

// Zero sets s to 0, and returns it.
func (s *Scalar) Zero() internal.Scalar {
s.scalar.Set(s.field.Zero())
Expand Down Expand Up @@ -194,7 +208,7 @@ func (s *Scalar) SetUInt64(i uint64) internal.Scalar {
func (s *Scalar) UInt64() (uint64, error) {
b := s.Encode()
overflows := byte(0)
scalarLength := (s.field.BitLen() + 7) / 8
scalarLength := s.field.ByteLen()

for _, bx := range b[:scalarLength-8] {
overflows |= bx
Expand All @@ -217,20 +231,16 @@ func (s *Scalar) Copy() internal.Scalar {

// Encode returns the compressed byte encoding of the scalar.
func (s *Scalar) Encode() []byte {
byteLen := (s.field.BitLen() + 7) / 8
scalar := make([]byte, byteLen)

scalar := make([]byte, s.field.ByteLen())
return s.scalar.FillBytes(scalar)
}

// Decode sets the receiver to a decoding of the input data, and returns an error on failure.
func (s *Scalar) Decode(in []byte) error {
expectedLength := (s.field.BitLen() + 7) / 8

switch len(in) {
case 0:
return internal.ErrParamNilScalar
case expectedLength:
case s.field.ByteLen():
break
default:
return internal.ErrParamScalarLength
Expand Down
5 changes: 5 additions & 0 deletions internal/ristretto/element.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ func checkElement(element internal.Element) *Element {
return ec
}

// Group returns the group's Identifier.
func (e *Element) Group() byte {
return Identifier
}

// Base sets the element to the group's base point a.k.a. canonical generator.
func (e *Element) Base() internal.Element {
e.element.Base()
Expand Down
3 changes: 3 additions & 0 deletions internal/ristretto/ristretto.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import (
)

const (
// Identifier distinguishes this group from the others by a byte representation.
Identifier = byte(1)

inputLength = 64

// H2C represents the hash-to-curve string identifier.
Expand Down
5 changes: 5 additions & 0 deletions internal/ristretto/scalar.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ func (s *Scalar) set(scalar *ristretto255.Scalar) {
s.scalar = *ristretto255.NewScalar().Add(&scZero.scalar, scalar)
}

// Group returns the group's Identifier.
func (s *Scalar) Group() byte {
return Identifier
}

// Zero sets the scalar to 0, and returns it.
func (s *Scalar) Zero() internal.Scalar {
s.scalar.Zero()
Expand Down
3 changes: 3 additions & 0 deletions internal/scalar.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ package internal

// Scalar interface abstracts common operations on scalars in a prime-order Group.
type Scalar interface {
// Group returns the group's Identifier.
Group() byte

// Zero sets the scalar to 0, and returns it.
Zero() Scalar

Expand Down
5 changes: 5 additions & 0 deletions internal/secp256k1/element.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ func assertElement(element internal.Element) *Element {
return ec
}

// Group returns the group's Identifier.
func (e *Element) Group() byte {
return Identifier
}

// Base sets the element to the group's base point a.k.a. canonical generator.
func (e *Element) Base() internal.Element {
e.element.Base()
Expand Down
3 changes: 3 additions & 0 deletions internal/secp256k1/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import (
)

const (
// Identifier distinguishes this group from the others by a byte representation.
Identifier = byte(7)

// H2CSECP256K1 represents the hash-to-curve string identifier for Secp256k1.
H2CSECP256K1 = "secp256k1_XMD:SHA-256_SSWU_RO_"

Expand Down
5 changes: 5 additions & 0 deletions internal/secp256k1/scalar.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ func assert(scalar internal.Scalar) *Scalar {
return sc
}

// Group returns the group's Identifier.
func (s *Scalar) Group() byte {
return Identifier
}

// Zero sets the scalar to 0, and returns it.
func (s *Scalar) Zero() internal.Scalar {
s.scalar.Zero()
Expand Down
5 changes: 5 additions & 0 deletions scalar.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ func newScalar(s internal.Scalar) *Scalar {
return &Scalar{Scalar: s}
}

// Group returns the group's Identifier.
func (s *Scalar) Group() Group {
return Group(s.Scalar.Group())
}

// Zero sets the scalar to 0, and returns it.
func (s *Scalar) Zero() *Scalar {
s.Scalar.Zero()
Expand Down
13 changes: 11 additions & 2 deletions tests/element_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,24 @@ func testElementCopySet(t *testing.T, element, other *crypto.Element) {
}
}

func TestElementCopy(t *testing.T) {
func TestElement_Group(t *testing.T) {
testAllGroups(t, func(group *testGroup) {
e := group.group.NewElement()
if e.Group() != group.group {
t.Fatal(errWrongGroup)
}
})
}

func TestElement_Copy(t *testing.T) {
testAllGroups(t, func(group *testGroup) {
base := group.group.Base()
cpy := base.Copy()
testElementCopySet(t, base, cpy)
})
}

func TestElementSet(t *testing.T) {
func TestElement_Set(t *testing.T) {
testAllGroups(t, func(group *testGroup) {
base := group.group.Base()
other := group.group.NewElement()
Expand Down
Loading

0 comments on commit 0a3f664

Please sign in to comment.