-
Notifications
You must be signed in to change notification settings - Fork 15
/
id.go
154 lines (129 loc) · 4.1 KB
/
id.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package party
import (
"encoding/binary"
"errors"
"fmt"
"math"
"math/rand"
"strconv"
"github.com/taurusgroup/frost-ed25519/pkg/ristretto"
)
// IDByteSize is the number of bytes required to store and ID or Size
const IDByteSize = 2
// _MAX is the maximum integer that can represent a party.
// It can be used to bound the number of parties, and the maximum integer value
// an ID can be.
const _MAX = uint64(math.MaxUint32)
// ID represents the identifier of a particular party, encoded as a 16 bit unsigned integer.
// The ID 0 is considered invalid.
type ID uint16
// Size is an alias for ID that allows us to differentiate between a party's ID and the threshold for example.
type Size = ID
// Scalar returns the corresponding ristretto.Scalar
func (id ID) Scalar() *ristretto.Scalar {
var s ristretto.Scalar
bytes := make([]byte, 32)
binary.LittleEndian.PutUint16(bytes, uint16(id))
_, err := s.SetCanonicalBytes(bytes[:])
if err != nil {
panic(fmt.Errorf("edwards25519: failed to set uint32 Scalar: %w", err))
}
return &s
}
// Bytes returns a []byte slice of length party.IDByteSize
func (id ID) Bytes() []byte {
bytes := make([]byte, IDByteSize)
binary.BigEndian.PutUint16(bytes, uint16(id))
return bytes
}
// String returns a base 10 representation of ID
func (id ID) String() string {
return strconv.FormatUint(uint64(id), 10)
}
// FromBytes reads the first party.IDByteSize bytes from b and creates an ID from it.
// Returns an error if b is too small to hold an ID
func FromBytes(b []byte) (ID, error) {
if len(b) < IDByteSize {
return 0, errors.New("party.FromBytes: b is not long enough to hold an ID")
}
id := ID(binary.BigEndian.Uint16(b))
return id, nil
}
// RandID returns a pseudo-random value as a ID
// from the default Source.
func RandID() ID {
id := rand.Int31n(math.MaxUint16 + 1)
if id == 0 {
return ID(id + 1)
}
return ID(id)
}
// MarshalText implements encoding/TextMarshaler interface
func (id ID) MarshalText() (text []byte, err error) {
return []byte(strconv.FormatUint(uint64(id), 10)), nil
}
// UnmarshalText implements encoding/TextMarshaler interface
// Returns an error when the encoded text is too large
func (id *ID) UnmarshalText(text []byte) error {
idUint, err := strconv.ParseUint(string(text), 10, 16)
if err != nil {
return fmt.Errorf("party.ID: UnmarshalText: %v", err)
}
if idUint > _MAX {
return errors.New("party.ID: UnmarshalText: party ID overflows")
}
*id = ID(idUint)
return nil
}
// Lagrange gives the Lagrange coefficient lⱼ(x) for x = 0.
//
// We iterate over all points in the set.
// To get the coefficients over a smaller set,
// you should first get a smaller subset.
//
// The following formulas are taken from
// https://en.wikipedia.org/wiki/Lagrange_polynomial
//
// ( x - x₀) ... ( x - xₖ)
// lⱼ(x) = ---------------------------
// (xⱼ - x₀) ... (xⱼ - xₖ)
//
// x₀ ... xₖ
// lⱼ(0) = ---------------------------
// (x₀ - xⱼ) ... (xₖ - xⱼ)
//
// returns an error if id is not included in partyIDs
func (id ID) Lagrange(partyIDs IDSlice) (*ristretto.Scalar, error) {
if id == 0 {
return nil, errors.New("party.ID: Lagrange: id was 0 (invalid)")
}
var one, num, denum, xM, xJ ristretto.Scalar
// we can't use scalar.NewScalarUInt32() since that would cause an import cycle
_, _ = one.SetCanonicalBytes([]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
num.Set(&one)
denum.Set(&one)
xJ = *id.Scalar()
foundSelfInIDs := false
for _, partyID := range partyIDs {
if partyID == id {
foundSelfInIDs = true
continue
}
xM = *partyID.Scalar()
// num = x₀ * ... * xₖ
num.Multiply(&num, &xM) // num * xM
// denum = (x₀ - xⱼ) ... (xₖ - xⱼ)
xM.Subtract(&xM, &xJ) // = xM - xJ
denum.Multiply(&denum, &xM) // denum * (xm - xj)
}
if !foundSelfInIDs {
return nil, errors.New("party.ID: Lagrange: partyIDs does not containd id")
}
// check against 0
if denum.Equal(ristretto.NewScalar()) == 1 {
return nil, errors.New("party.ID: Lagrange: denominator was 0")
}
denum.Invert(&denum)
num.Multiply(&num, &denum)
return &num, nil
}