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 (#66)
Browse files Browse the repository at this point in the history
* Elements and Scalars can now return their group with the Group() method

---------

Signed-off-by: bytemare <[email protected]>
  • Loading branch information
bytemare authored Oct 1, 2024
1 parent 24e1bda commit e89a42e
Show file tree
Hide file tree
Showing 25 changed files with 222 additions and 139 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
strategy:
fail-fast: false
matrix:
go: [ '1.22', '1.21' ]
go: [ '1.23.2', '1.22.8', '1.21.13' ]
uses: bytemare/workflows/.github/workflows/test-go.yml@f572ea606a74fe011e68a23c19f8d4f5daf58488
with:
command: cd .github && make test
Expand Down
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
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/bytemare/crypto

go 1.22.2
go 1.23.1

require (
filippo.io/edwards25519 v1.1.0
Expand All @@ -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
28 changes: 5 additions & 23 deletions internal/field/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ import (
"math/big"
)

var (
zero = big.NewInt(0)
one = big.NewInt(1)
)

// String2Int returns a big.Int representation of the integer s.
func String2Int(s string) big.Int {
if p, _ := new(big.Int).SetString(s, 0); p != nil {
Expand All @@ -35,6 +30,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,19 +54,10 @@ func NewField(prime *big.Int) Field {
pMinus1div2: pMinus1div2,
pMinus2: pMinus2,
exp: exp,
byteLen: (prime.BitLen() + 7) / 8,
}
}

// Zero returns the zero big.Int of the finite Field.
func (f Field) Zero() *big.Int {
return zero
}

// One returns one big.Int of the finite Field.
func (f Field) One() *big.Int {
return one
}

// Random sets res to a random big.Int in the Field.
func (f Field) Random(res *big.Int) *big.Int {
tmp, err := rand.Int(rand.Reader, f.order)
Expand All @@ -89,14 +76,9 @@ func (f Field) Order() *big.Int {
return f.order
}

// BitLen of the order.
func (f Field) BitLen() int {
return f.order.BitLen()
}

// AreEqual returns whether both elements are equal.
func (f Field) AreEqual(f1, f2 *big.Int) bool {
return f.IsZero(f.Sub(&big.Int{}, f1, f2))
// ByteLen returns the length of the field order in bytes.
func (f Field) ByteLen() int {
return f.byteLen
}

// IsZero returns whether the big.Int is equivalent to zero.
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
19 changes: 18 additions & 1 deletion 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,20 @@ 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 point type %v", reflect.TypeFor[Point]()))
}

// 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 All @@ -67,7 +84,7 @@ func (e *Element[Point]) Double() internal.Element {
return e
}

// negateSmall returns the compressed byte encoding of the negated element e with 5 allocs in 13000 ns/op.
// negateSmall returns the compressed byte encoding of the negated element e with 5 allocations in 13000 ns/op.
func (e *Element[Point]) negateSmall() []byte {
enc := e.p.BytesCompressed()

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
31 changes: 20 additions & 11 deletions internal/nist/scalar.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ func newScalar(f *field.Field) *Scalar {
field: f,
scalar: big.Int{},
}
s.scalar.Set(s.field.Zero())

return s
}
Expand All @@ -48,15 +47,29 @@ func (s *Scalar) assert(scalar internal.Scalar) *Scalar {
return _sc
}

// Group returns the group's Identifier.
func (s *Scalar) Group() byte {
switch *s.field {
case p256.scalarField:
return IdentifierP256
case p384.scalarField:
return IdentifierP384
case p521.scalarField:
return IdentifierP521
}

panic(fmt.Sprintf("invalid field order for scalar %s", s.field.Order().String()))
}

// Zero sets s to 0, and returns it.
func (s *Scalar) Zero() internal.Scalar {
s.scalar.Set(s.field.Zero())
s.scalar.Set(big.NewInt(0))
return s
}

// One sets s to 1, and returns it.
func (s *Scalar) One() internal.Scalar {
s.scalar.Set(s.field.One())
s.scalar.Set(big.NewInt(1))
return s
}

Expand Down Expand Up @@ -168,7 +181,7 @@ func (s *Scalar) LessOrEqual(scalar internal.Scalar) int {

// IsZero returns whether the scalar is 0.
func (s *Scalar) IsZero() bool {
return s.field.AreEqual(&s.scalar, s.field.Zero())
return s.field.IsZero(&s.scalar)
}

// Set sets the receiver to the value of the argument scalar, and returns the receiver.
Expand All @@ -194,7 +207,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 +230,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
Loading

0 comments on commit e89a42e

Please sign in to comment.