Skip to content

Commit

Permalink
replace uint64 identifiers, threshold, and max with uint16 (#43)
Browse files Browse the repository at this point in the history
* replace uint64 identifiers, threshold, and max with uint16

Signed-off-by: bytemare <3641580+bytemare@users.noreply.github.com>
  • Loading branch information
bytemare authored Sep 11, 2024
1 parent 73bb732 commit e969657
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 131 deletions.
3 changes: 3 additions & 0 deletions .github/.golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ linters-settings:
- style
disabled-checks:
- unnamedResult
- builtinShadow
gocyclo:
min-complexity: 15
godox:
Expand Down Expand Up @@ -229,6 +230,8 @@ linters-settings:
prealloc:
simple: false
for-loops: true
predeclared:
ignore: "max"
whitespace:
multi-if: false
multi-func: false
Expand Down
8 changes: 4 additions & 4 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import (
func ExampleShard() {
// These are the configuration parameters
g := group.Ristretto255Sha512
threshold := uint(3) // threshold is the minimum amount of necessary shares to recombine the secret
shareholders := uint(7) // the total amount of key share-holders
threshold := uint16(3) // threshold is the minimum amount of necessary shares to recombine the secret
shareholders := uint16(7) // the max amount of key share-holders

// This is the global secret to be shared
secret := g.NewScalar().Random()
Expand Down Expand Up @@ -58,8 +58,8 @@ func ExampleShard() {
func ExampleVerify() {
// These are the configuration parameters
g := group.Ristretto255Sha512
threshold := uint(3) // threshold is minimum amount of necessary shares to recombine the secret
shareholders := uint(7) // the total amount of key share-holders
threshold := uint16(3) // threshold is minimum amount of necessary shares to recombine the secret
shareholders := uint16(7) // the max amount of key share-holders

// This is the global secret to be shared
secret := g.NewScalar().Random()
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ require (
github.com/bytemare/hash2curve v0.3.0 // indirect
github.com/bytemare/secp256k1 v0.1.4 // indirect
github.com/gtank/ristretto255 v0.1.2 // 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
)
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,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.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.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=
48 changes: 27 additions & 21 deletions keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ var (
errEncodingInvalidGroup = errors.New("invalid group identifier")
errEncodingInvalidLength = errors.New("invalid encoding length")
errEncodingInvalidJSONEncoding = errors.New("invalid JSON encoding")
errInvalidPolynomialLength = errors.New("invalid polynomial length (exceeds uint16 limit 65535)")
)

// The Share interface enables to use functions in this package with compatible key shares.
type Share interface {
// Identifier returns the identity for this share.
Identifier() uint64
Identifier() uint16

// SecretKey returns the participant's secret share.
SecretKey() *group.Scalar
Expand All @@ -46,7 +47,7 @@ type PublicKeyShare struct {
Commitment []*group.Element `json:"commitment,omitempty"`

// ID of the participant.
ID uint64 `json:"id"`
ID uint16 `json:"id"`

// Group specifies the elliptic curve group the elements are part of.
Group group.Group `json:"group"`
Expand All @@ -57,14 +58,17 @@ func (p *PublicKeyShare) Verify() bool {
return Verify(p.Group, p.ID, p.PublicKey, p.Commitment)
}

func publicKeyShareLength(g group.Group, polyLen int) int {
eLen := g.ElementLength()
return 1 + 2 + 4 + eLen + polyLen*eLen
}

// Encode serializes p into a compact byte string.
func (p *PublicKeyShare) Encode() []byte {
eLen := p.Group.ElementLength()
oLen := 1 + 8 + 4 + eLen + len(p.Commitment)*eLen
out := make([]byte, 13, oLen)
out := make([]byte, 7, publicKeyShareLength(p.Group, len(p.Commitment)))
out[0] = byte(p.Group)
binary.LittleEndian.PutUint64(out[1:9], p.ID)
binary.LittleEndian.PutUint32(out[9:13], uint32(len(p.Commitment)))
binary.LittleEndian.PutUint16(out[1:3], p.ID)
binary.LittleEndian.PutUint32(out[3:7], uint32(len(p.Commitment)))
out = append(out, p.PublicKey.Encode()...)

for _, c := range p.Commitment {
Expand All @@ -76,17 +80,17 @@ func (p *PublicKeyShare) Encode() []byte {

func (p *PublicKeyShare) decode(g group.Group, cLen int, data []byte) error {
eLen := g.ElementLength()
id := binary.LittleEndian.Uint64(data[1:9])
id := binary.LittleEndian.Uint16(data[1:3])

pk := g.NewElement()
if err := pk.Decode(data[13 : 13+eLen]); err != nil {
if err := pk.Decode(data[7 : 7+eLen]); err != nil {
return fmt.Errorf("failed to decode public key: %w", err)
}

i := 0
commitment := make([]*group.Element, cLen)

for j := 13 + eLen; j < len(data); j += eLen {
for j := 7 + eLen; j < len(data); j += eLen {
c := g.NewElement()
if err := c.Decode(data[j : j+eLen]); err != nil {
return fmt.Errorf("failed to decode commitment %d: %w", i+1, err)
Expand Down Expand Up @@ -138,7 +142,7 @@ type KeyShare struct {
}

// Identifier returns the identity for this share.
func (k *KeyShare) Identifier() uint64 {
func (k *KeyShare) Identifier() uint16 {
return k.ID
}

Expand Down Expand Up @@ -217,12 +221,12 @@ func (k *KeyShare) UnmarshalJSON(data []byte) error {
// helper functions

type shadowInit interface {
init(g group.Group, threshold int)
init(g group.Group, threshold uint16)
}

type publicKeyShareShadow PublicKeyShare

func (p *publicKeyShareShadow) init(g group.Group, threshold int) {
func (p *publicKeyShareShadow) init(g group.Group, threshold uint16) {
p.ID = 0
p.Group = g
p.PublicKey = g.NewElement()
Expand All @@ -239,15 +243,15 @@ type keyShareShadow struct {
*publicKeyShareShadow
}

func (k *keyShareShadow) init(g group.Group, threshold int) {
func (k *keyShareShadow) init(g group.Group, threshold uint16) {
p := new(publicKeyShareShadow)
p.init(g, threshold)
k.Secret = g.NewScalar()
k.GroupPublicKey = g.NewElement()
k.publicKeyShareShadow = p
}

func unmarshalJSONHeader(data []byte) (group.Group, int, error) {
func unmarshalJSONHeader(data []byte) (group.Group, uint16, error) {
s := string(data)

g, err := jsonReGetGroup(s)
Expand All @@ -256,8 +260,11 @@ func unmarshalJSONHeader(data []byte) (group.Group, int, error) {
}

nPoly := jsonRePolyLen(s)
if nPoly > 65535 {
return 0, 0, errInvalidPolynomialLength
}

return g, nPoly, nil
return g, uint16(nPoly), nil
}

func unmarshalJSON(data []byte, target shadowInit) error {
Expand Down Expand Up @@ -339,13 +346,12 @@ func decodeKeyShareHeader(data []byte) (group.Group, int, int, error) {
return 0, 0, 0, errEncodingInvalidGroup
}

if len(data) <= 13 {
if len(data) <= 7 {
return 0, 0, 0, errEncodingInvalidLength
}

cLen := int(binary.LittleEndian.Uint32(data[9:13]))
eLen := g.ElementLength()
pks := 1 + 8 + 4 + eLen + cLen*eLen
cLen := int(binary.LittleEndian.Uint32(data[3:7]))
pksLen := publicKeyShareLength(g, cLen)

return g, pks, cLen, nil
return g, pksLen, cLen, nil
}
16 changes: 6 additions & 10 deletions polynomial.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
)

var (
errPolyDiffLength = errors.New("destination and source polynomials length differ")
errPolyXIsZero = errors.New("identifier for interpolation is nil or zero")
errPolyHasZeroCoeff = errors.New("one of the polynomial's coefficients is zero")
errPolyHasDuplicates = errors.New("the polynomial has duplicate coefficients")
Expand All @@ -29,15 +28,15 @@ var (
type Polynomial []*group.Scalar

// NewPolynomial returns a slice of Scalars with the capacity to hold the desired coefficients.
func NewPolynomial(coefficients uint) Polynomial {
func NewPolynomial(coefficients uint16) Polynomial {
return make(Polynomial, coefficients)
}

// NewPolynomialFromIntegers returns a Polynomial from a slice of uint64.
func NewPolynomialFromIntegers(g group.Group, ints []uint64) Polynomial {
// NewPolynomialFromIntegers returns a Polynomial from a slice of uint16.
func NewPolynomialFromIntegers(g group.Group, ints []uint16) Polynomial {
polynomial := make(Polynomial, len(ints))
for i, v := range ints {
polynomial[i] = g.NewScalar().SetUInt64(v)
polynomial[i] = g.NewScalar().SetUInt64(uint64(v))
}

return polynomial
Expand All @@ -54,11 +53,8 @@ func NewPolynomialFromListFunc[S ~[]E, E any](g group.Group, s S, f func(E) *gro
return polynomial
}

// the only call to copyPolynomial ensure that both polynomials are of the same length.
func copyPolynomial(dst, src Polynomial) error {
if len(dst) != len(src) {
return errPolyDiffLength
}

for index, coeff := range src {
if coeff == nil {
return errPolyHasNilCoeff
Expand Down Expand Up @@ -194,7 +190,7 @@ func (p Polynomial) DeriveInterpolatingValue(g group.Group, id *group.Scalar) (*
// key shares.
func PolynomialInterpolateConstant(g group.Group, shares []Share) (*group.Scalar, error) {
xCoords := NewPolynomialFromListFunc(g, shares, func(share Share) *group.Scalar {
return g.NewScalar().SetUInt64(share.Identifier())
return g.NewScalar().SetUInt64(uint64(share.Identifier()))
})

key := g.NewScalar().Zero()
Expand Down
28 changes: 14 additions & 14 deletions sharing.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ var (
errPolySecretNotSet = errors.New("provided polynomial's first coefficient not set to the secret")
)

func makeKeyShare(g group.Group, id uint64, p Polynomial, groupPublicKey *group.Element) *KeyShare {
ids := g.NewScalar().SetUInt64(id)
func makeKeyShare(g group.Group, id uint16, p Polynomial, groupPublicKey *group.Element) *KeyShare {
ids := g.NewScalar().SetUInt64(uint64(id))
yi := p.Evaluate(ids)

return &KeyShare{
Expand All @@ -40,15 +40,15 @@ func makeKeyShare(g group.Group, id uint64, p Polynomial, groupPublicKey *group.
}
}

// Shard splits the secret into total shares, recoverable by a subset of threshold shares. If no secret is provided, a
// Shard splits the secret into max shares, recoverable by a subset of threshold shares. If no secret is provided, a
// new random secret is created. To use Verifiable Secret Sharing, use ShardAndCommit.
func Shard(
g group.Group,
secret *group.Scalar,
threshold, total uint,
threshold, max uint16,
polynomial ...*group.Scalar,
) ([]*KeyShare, error) {
shares, p, err := ShardReturnPolynomial(g, secret, threshold, total, polynomial...)
shares, p, err := ShardReturnPolynomial(g, secret, threshold, max, polynomial...)

for _, pi := range p {
pi.Zero() // zero-out the polynomial, just to be sure.
Expand All @@ -61,10 +61,10 @@ func Shard(
// If no secret is provided, a new random secret is created.
func ShardAndCommit(g group.Group,
secret *group.Scalar,
threshold, total uint,
threshold, max uint16,
polynomial ...*group.Scalar,
) ([]*KeyShare, error) {
shares, p, err := ShardReturnPolynomial(g, secret, threshold, total, polynomial...)
shares, p, err := ShardReturnPolynomial(g, secret, threshold, max, polynomial...)
if err != nil {
return nil, err
}
Expand All @@ -82,16 +82,16 @@ func ShardAndCommit(g group.Group,
return shares, nil
}

// ShardReturnPolynomial splits the secret into total shares, recoverable by a subset of threshold shares, and returns
// ShardReturnPolynomial splits the secret into max shares, recoverable by a subset of threshold shares, and returns
// the constructed secret polynomial without committing to it. If no secret is provided, a new random secret is created.
// Use the Commit function if you want to commit to the returned polynomial.
func ShardReturnPolynomial(
g group.Group,
secret *group.Scalar,
threshold, total uint,
threshold, max uint16,
polynomial ...*group.Scalar,
) ([]*KeyShare, Polynomial, error) {
if total < threshold {
if max < threshold {
return nil, nil, errTooFewShares
}

Expand All @@ -103,9 +103,9 @@ func ShardReturnPolynomial(
groupPublicKey := g.Base().Multiply(p[0])

// Evaluate the polynomial for each point x=1,...,n
secretKeyShares := make([]*KeyShare, total)
secretKeyShares := make([]*KeyShare, max)

for i := uint64(1); i <= uint64(total); i++ {
for i := uint16(1); i <= max; i++ {
secretKeyShares[i-1] = makeKeyShare(g, i, p, groupPublicKey)
}

Expand Down Expand Up @@ -138,7 +138,7 @@ func CombineShares(g group.Group, shares []Share) (*group.Scalar, error) {
return PolynomialInterpolateConstant(g, shares)
}

func makePolynomial(g group.Group, s *group.Scalar, threshold uint, polynomial ...*group.Scalar) (Polynomial, error) {
func makePolynomial(g group.Group, s *group.Scalar, threshold uint16, polynomial ...*group.Scalar) (Polynomial, error) {
if threshold == 0 {
return nil, errThresholdIsZero
}
Expand All @@ -151,7 +151,7 @@ func makePolynomial(g group.Group, s *group.Scalar, threshold uint, polynomial .

switch len(polynomial) {
case 0:
i := uint(0)
i := uint16(0)

if s != nil {
p[0] = s.Copy()
Expand Down
Loading

0 comments on commit e969657

Please sign in to comment.