5
5
//
6
6
// Decaf (3) is a prime-order group constructed as a quotient of groups. A Decaf
7
7
// element can be represented by any point in the coset P+J[2], where J is a
8
- // Jacobi quartic and J[2] are its 2-torsion points.
8
+ // Jacobi quartic curve and J[2] are its 2-torsion points.
9
9
// Since P+J[2] has four points, Decaf specifies rules to choose one canonical
10
10
// representative, which has a unique encoding. Two representations are
11
11
// equivalent if they belong to the same coset.
15
15
//
16
16
// Version
17
17
//
18
- // This implementation uses Decaf v1.0 of the encoding (see (4) for a complete
18
+ // This implementation uses Decaf v1.0 of the encoding (see (4,5 ) for a complete
19
19
// specification).
20
20
//
21
- // Internals
22
- //
23
- // Decaf uses as internal representation the curve
24
- // ted448: ax^2+y^2 = 1 + dx^2y^2, where a=-1 and d=-39082.
25
- // This curve is 4-degree isogeneous to the Goldilocks curve, and 2-degree
26
- // isogeneous to the Jacobi quartic. The ted448 curve was chosen because it
27
- // provides faster arithmetic operations.
28
- //
29
21
// References
30
22
//
31
23
// (1) https://www.shiftleft.org/papers/goldilocks
35
27
// (3) https://doi.org/10.1007/978-3-662-47989-6_34 and https://www.shiftleft.org/papers/decaf
36
28
//
37
29
// (4) https://sourceforge.net/p/ed448goldilocks/code/ci/v1.0/tree/
30
+ //
31
+ // (5) https://mailarchive.ietf.org/arch/msg/cfrg/S4YUTt_5eD4kwYbDuhEK0tXT1aM/
38
32
package decaf
39
33
40
34
import (
@@ -96,8 +90,8 @@ func (e *Elt) IsEqual(a *Elt) bool {
96
90
return fp .IsZero (l )
97
91
}
98
92
99
- // UnmarshalBinary if succeeds returns a Decaf element by decoding the first
100
- // DecafEncodingSize bytes of data .
93
+ // UnmarshalBinary interprets the first EncodingSize bytes passed in data, and
94
+ // returns a Decaf element .
101
95
func (e * Elt ) UnmarshalBinary (data []byte ) error {
102
96
if len (data ) < EncodingSize {
103
97
return ErrInvalidDecoding
@@ -109,35 +103,34 @@ func (e *Elt) UnmarshalBinary(data []byte) error {
109
103
isLessThanP := isLessThan (s [:], p [:])
110
104
isPositiveS := fp .Parity (s ) == 0
111
105
112
- s2 , den , num := & fp.Elt {}, & fp.Elt {}, & fp.Elt {}
113
- isr , altx := & fp.Elt {}, & fp.Elt {}
114
- t0 , t1 := & fp.Elt {}, & fp.Elt {}
106
+ den , num := & fp.Elt {}, & fp.Elt {}
107
+ isr , altx , t0 := & fp.Elt {}, & fp.Elt {}, & fp.Elt {}
115
108
x , y := & fp.Elt {}, & fp.Elt {}
116
109
one := fp .One ()
117
- fp . Sqr ( s2 , s ) // s2 = s^2
118
- fp .Sub ( den , & one , s2 ) // den = 1 + a* s^2
119
- fp .Mul ( t1 , s2 , & ted448 . ParamD ) // t1 = d *s^2
120
- fp .Add (t1 , t1 , t1 ) // t1 = 2*d *s^2
121
- fp .Add ( t1 , t1 , t1 ) // t1 = 4* d*s^2
122
- fp .Sqr ( t0 , den ) // num = (1 + a*s^2) ^2
123
- fp .Sub (num , t0 , t1 ) // num = (1 + a*s^2)^2 - 4*d*s^2
124
- fp .Mul (t0 , t0 , num ) // t0 = num* den^2
125
- isQR := fp .InvSqrt ( isr , & one , t0 ) // v = 1/sqrt(num* den^2)
126
- fp .Mul (t1 , den , isr ) // altx = isr* den
127
- fp .Mul ( t1 , t1 , s ) // altx = s*isr* den
128
- fp .Add ( t1 , t1 , t1 ) // t1 = 2*s* isr*den
129
- fp .Mul (altx , t1 , & sqrtAMinusDTwist ) // altx = 2* s*isr*den*sqrt(A-D)
130
- isNegX := fp .Parity (altx ) // isNeg = sgn(altx)
131
- fp .Neg ( t0 , isr ) // t0 = - isr
132
- fp .Cmov ( isr , t0 , uint ( isNegX )) // if altx is negative then isr = -isr
133
- fp .Sqr ( x , isr ) // x = isr^2
134
- fp .Mul ( x , x , den ) // x = isr^2*den
135
- fp .Mul (x , x , num ) // x = isr^2 *den*num
136
- fp .Mul (x , x , s ) // x = s* isr^2*den*num
137
- fp .Add (x , x , x ) // x = 2*s* isr^2*den*num
138
- fp .Mul (y , isr , den ) // y = isr*den
139
- fp .Add (t0 , & one , s2 ) // t0 = 1 - a*s^2
140
- fp .Mul (y , y , t0 ) // y = (1 - a*s^2)*isr*den
110
+ paramD := ted448 . ParamD ()
111
+ fp .Sqr ( t0 , s ) // t0 = s^2
112
+ fp .Sub ( den , & one , t0 ) // den = 1 + a *s^2
113
+ fp .Add (y , & one , t0 ) // y = 1 - a *s^2
114
+ fp .Mul ( num , t0 , & paramD ) // num = d*s^2
115
+ fp .Add ( num , num , num ) // = 2*d*s ^2
116
+ fp .Add (num , num , num ) // = 4*d*s^2
117
+ fp .Sqr (t0 , den ) // t0 = den^2 = (1 + a*s^2) ^2
118
+ fp .Sub ( num , t0 , num ) // num = den^2 - 4*d*s^2
119
+ fp .Mul (t0 , t0 , num ) // t0 = den^2*num
120
+ isQR := fp .InvSqrt ( isr , & one , t0 ) // isr = 1/( den*sqrt(num))
121
+ fp .Mul ( altx , isr , den ) // altx = isr*den
122
+ fp .Mul (altx , altx , s ) // = s*isr*den
123
+ fp .Add (altx , altx , altx ) // = 2*s*isr*den
124
+ fp .Mul ( altx , altx , & sqrtAMinusD ) // = 2*s* isr*den*sqrt(A-D)
125
+ isNegX := fp .Parity ( altx ) // isNeg = sgn(altx)
126
+ fp .Neg ( t0 , isr ) // t0 = - isr
127
+ fp .Cmov ( isr , t0 , uint ( isNegX )) // if altx is negative then isr = - isr
128
+ fp .Mul (t0 , isr , den ) // t0 = isr*den
129
+ fp .Mul (x , t0 , isr ) // x = isr^2*den
130
+ fp .Mul (x , x , num ) // x = isr^2*den*num
131
+ fp .Mul (x , x , s ) // x = s* isr^2 *den*num
132
+ fp .Add (x , x , x ) // x = 2*s*isr^2*den*num
133
+ fp .Mul (y , y , t0 ) // y = (1 - a*s^2)*isr*den
141
134
142
135
isValid := isPositiveS && isLessThanP && isQR
143
136
b := uint (* ((* byte )(unsafe .Pointer (& isValid ))))
@@ -146,45 +139,45 @@ func (e *Elt) UnmarshalBinary(data []byte) error {
146
139
fp .Cmov (& e .p .Ta , x , b )
147
140
fp .Cmov (& e .p .Tb , y , b )
148
141
fp .Cmov (& e .p .Z , & one , b )
149
- var err error
150
142
if ! isValid {
151
- err = ErrInvalidDecoding
143
+ return ErrInvalidDecoding
152
144
}
153
- return err
145
+ return nil
154
146
}
155
147
156
148
// MarshalBinary returns a unique encoding of the element e.
157
149
func (e * Elt ) MarshalBinary () ([]byte , error ) {
158
- x , ta , tb , z := & e .p .X , & e .p .Ta , & e .p .Tb , & e .p .Z
159
- one , t , t2 , s := & fp.Elt {}, & fp.Elt {}, & fp.Elt {}, & fp.Elt {}
160
- fp .SetOne (one )
161
- fp .Mul (t , ta , tb ) // t = ta*tb
162
- t0 , t1 := * x , * t // (t0,t1) = (x,t)
163
- fp .Sqr (t2 , x ) // t2 = x^2
164
- fp .AddSub (& t0 , & t1 ) // (t0,t1) = (x+t,x-t)
165
- fp .Mul (& t1 , & t0 , & t1 ) // t1 = (x+t)*(x-t)
166
- fp .Mul (& t0 , & t1 , & aMinusDTwist ) // t0 = (a-d)*(x+t)*(x-t)
167
- fp .Mul (& t0 , & t0 , t2 ) // t0 = x^2*(a-d)*(x+t)*(x-t)
168
- fp .InvSqrt (& t0 , one , & t0 ) // t0 = 1/sqrt( x^2*(a-d)*(z+y)*(z-y) )
169
- fp .Mul (& t1 , & t1 , & t0 ) // t1 = (z+y)*(z-y)/sqrt( x^2*(a-d)*(z+y)*(z-y) )
170
- fp .Mul (t2 , & t1 , & sqrtAMinusDTwist ) // t2 = sqrt( (z+y)*(z-y) )/z
171
- isNeg := fp .Parity (t2 ) // isNeg = sgn(t2)
172
- fp .Neg (t2 , & t1 ) // t2 = -t1
173
- fp .Cmov (& t1 , t2 , uint (isNeg )) // if t2 is negative then t1 = -t1
174
- fp .Mul (s , & t1 , z ) // s = t1*z
175
- fp .Sub (s , s , t ) // s = t1*z - t
176
- fp .Mul (s , s , x ) // s = x*(t1*z - t)
177
- fp .Mul (s , s , & t0 ) // s = isr*x*(t1*z - t)
178
- fp .Mul (s , s , & aMinusDTwist ) // s = (a-d)*isr*x*(t1*z - t)
179
- isNeg = fp .Parity (s ) // isNeg = sgn(s)
180
- fp .Neg (& t0 , s ) // t0 = -s
181
- fp .Cmov (s , & t0 , uint (isNeg )) // if s is negative then s = -s
182
-
183
150
var encS [EncodingSize ]byte
184
- if err := fp .ToBytes (encS [:], s ); err != nil {
185
- return nil , err
186
- }
187
- return encS [:], nil
151
+ err := e .marshalBinary (encS [:])
152
+ return encS [:], err
153
+ }
154
+
155
+ func (e * Elt ) marshalBinary (enc []byte ) error {
156
+ x , ta , tb , z := & e .p .X , & e .p .Ta , & e .p .Tb , & e .p .Z
157
+ t , t2 , s := & fp.Elt {}, & fp.Elt {}, & fp.Elt {}
158
+ one := fp .One ()
159
+ fp .Mul (t , ta , tb ) // t = ta*tb
160
+ t0 , t1 := * x , * t // (t0,t1) = (x,t)
161
+ fp .AddSub (& t0 , & t1 ) // (t0,t1) = (x+t,x-t)
162
+ fp .Mul (& t1 , & t0 , & t1 ) // t1 = num = (x+t)*(x-t) = x^2*(z^2-y^2)/z^2
163
+ fp .Mul (& t0 , & t1 , & aMinusD ) // t0 = (a-d)*(x+t)*(x-t) = (a-d)*x^2*(z^2-y^2)/z^2
164
+ fp .Sqr (t2 , x ) // t2 = x^2
165
+ fp .Mul (& t0 , & t0 , t2 ) // t0 = x^2*(a-d)*(x+t)*(x-t) = (a-d)*x^4*(z^2-y^2)/z^2
166
+ fp .InvSqrt (& t0 , & one , & t0 ) // t0 = isr = z/(x^2*sqrt((a-d)*(z^2-y^2)))
167
+ fp .Mul (& t1 , & t1 , & t0 ) // t1 = ratio = (z^2-y^2)/(z*sqrt((a-d)*(z^2-y^2)))
168
+ fp .Mul (t2 , & t1 , & sqrtAMinusD ) // t2 = altx = sqrt((z^2-y^2))/z
169
+ isNeg := fp .Parity (t2 ) // isNeg = sgn(t2)
170
+ fp .Neg (t2 , & t1 ) // t2 = -t1
171
+ fp .Cmov (& t1 , t2 , uint (isNeg )) // if t2 is negative then t1 = -t1
172
+ fp .Mul (s , & t1 , z ) // s = t1*z
173
+ fp .Sub (s , s , t ) // s = t1*z - t
174
+ fp .Mul (s , s , x ) // s = x*(t1*z - t)
175
+ fp .Mul (s , s , & t0 ) // s = isr*x*(t1*z - t)
176
+ fp .Mul (s , s , & aMinusD ) // s = (a-d)*isr*x*(t1*z - t)
177
+ isNeg = fp .Parity (s ) // isNeg = sgn(s)
178
+ fp .Neg (& t0 , s ) // t0 = -s
179
+ fp .Cmov (s , & t0 , uint (isNeg )) // if s is negative then s = -s
180
+ return fp .ToBytes (enc [:], s )
188
181
}
189
182
190
183
// isLessThan returns true if 0 <= x < y, and assumes that slices are of the
0 commit comments