2 * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * A MutableECPoint instance contains an elliptic curve point, in a
31 * given curve. It may be modified to contain another point, but not
34 * Constant-time guarantees: IsInfinityCT, DoubleCT(), NegCT() and
35 * AddCT() are constant-time with regards to the represented curve
36 * point. Execution time may vary depending on the sequence of calls,
37 * but not on the point data. In particular, points may be internally
38 * "normalized" or not, and operations involving normalized points can
39 * be faster; however, normalization happens only upon an explicit call.
40 * The normalization process itself (Normalize()) is constant-time.
43 internal abstract class MutableECPoint {
45 internal MutableECPoint()
49 internal abstract ECCurve Curve {
54 * Test whether this point is the point at infinity.
56 internal bool IsInfinity {
58 return IsInfinityCT != 0;
63 * Test whether this point is the point at infinity (returns
64 * 0xFFFFFFFF or 0x00000000).
66 internal abstract uint IsInfinityCT {
71 * Normalize this instance. What this entails depends on the
72 * curve type, but it will typically means computing affine
73 * coordinates in case this instance was using some sort of
76 internal abstract void Normalize();
79 * Encode this point into some bytes. If "compressed" is true,
80 * then a compressed format will be used.
82 * This call may entail normalization. If the point is not the
83 * infinity point, then this method is constant-time.
85 internal abstract byte[] Encode(bool compressed);
88 * Encode this point into some bytes. If "compressed is true,
89 * then a compressed format will be used. The destination array
90 * must have the proper length for the requested point format.
92 * This call may entail normalization. If the point is invalid
93 * or is the point at infinity, then the returned value is 0
94 * and what gets written in the array is indeterminate. Otherwise,
95 * the encoded point is written and -1 is returned. Either way,
96 * this call is constant-time.
98 internal abstract uint Encode(byte[] dst, bool compressed);
101 * Set this point by decoding the provided value. An invalid
102 * encoding sets this point to 0 (infinity) and triggers an
105 internal void Decode(byte[] enc)
107 if (DecodeCT(enc) == 0) {
108 throw new CryptoException("Invalid encoded point");
113 * Set this point by decoding the provided value. This is
114 * constant-time (up to the encoded point length). Returned
115 * value is 0xFFFFFFFF if the encoded point was valid,
116 * 0x00000000 otherwise. If the decoding failed, then this
117 * value is set to 0 (infinity).
119 internal abstract uint DecodeCT(byte[] enc);
122 * Get the X coordinate for this point. This implies
123 * normalization. If the point is the point at infinity,
124 * then the returned array contains the encoding of 0.
125 * This is constant-time.
127 internal abstract byte[] X {
132 * Get the Y coordinate for this point. This implies
133 * normalization. If the point is the point at infinity,
134 * then the returned array contains the encoding of 0.
135 * This is constant-time.
137 internal abstract byte[] Y {
142 * Create a new instance that starts with the same contents as
145 internal abstract MutableECPoint Dup();
148 * Set this instance to the point at infinity.
150 internal abstract void SetZero();
153 * Set this instance to the same contents as the provided point.
154 * The operand Q must be part of the same curve.
156 internal abstract void Set(MutableECPoint Q);
159 * Set this instance to the same contents as the provided point,
160 * but only if ctl == 0xFFFFFFFFF. If ctl == 0x00000000, then
161 * this instance is unmodified. The operand Q must be part of
164 internal abstract void Set(MutableECPoint Q, uint ctl);
167 * Set this instance to the same contents as point P1 if
168 * ctl == 0xFFFFFFFF, or point P2 if ctl == 0x00000000.
169 * Both operands must use the same curve as this instance.
171 internal abstract void SetMux(uint ctl,
172 MutableECPoint P1, MutableECPoint P2);
175 * DoubleCT() is constant-time. It works for all points
176 * (including points of order 2 and the infinity point).
178 internal abstract void DoubleCT();
181 * AddCT() computes P+Q (P is this instance, Q is the operand).
182 * It may assume that P != Q. If P = Q and the method could not
183 * compute the correct result, then it shall set this instance to
184 * 0 (infinity) and return 0x00000000. In all other cases, it must
185 * compute the correct point and return 0xFFFFFFFF. In particular,
186 * it should properly handle cases where P = 0 or Q = 0. This
187 * function is allowed to handle doubling cases as well, if it
190 * This method may be more efficient if the operand is
191 * normalized. Execution time and memory access may depend on
192 * whether this instance or the other operand is normalized,
193 * but not on the actual point values (including if the points
194 * do not fulfill the properties above).
196 internal abstract uint AddCT(MutableECPoint Q);
199 * Negate this point. It also works on the point at infinity,
200 * and it is constant-time.
202 internal abstract void NegCT();
205 * Multiply this point by the provided integer (unsigned
206 * big-endian representation). This is constant-time. This
207 * method assumes that:
208 * -- the point on which we are operating is part of the curve
210 * -- the defined subgroup has a prime order which is no less
212 * -- the point is not the point at infinity;
213 * -- the multiplier operand is no more than the subgroup order.
214 * If these conditions are met, then the resulting point will
215 * be the proper element of the defined subgroup (it will be
216 * the point at infinity only if the multiplier is 0 or is
217 * equal to the subgroup order). If they are NOT met, then the
218 * resulting point is undefined (but will still be part of the
221 * This method is constant-time.
223 * Returned value is 0xFFFFFFFF if none of the internal
224 * operations reached a problematic state (i.e. that we tried to
225 * perform an addition and the two operands turned out to be
226 * equal to each other). If the conditions above are met, then
227 * this is always the case. If a problematic state was reached,
228 * then the returned value is 0x00000000. Callers MUST be very
229 * cautious about using that reported error state, since it is
230 * not guaranteed that all invalid points would be reported as
231 * such. There thus is potential for leakage of secret data.
233 internal abstract uint MulSpecCT(byte[] n);
236 * Compare this point to another. This method throws an
237 * exception if the provided point is not on the same curve as
238 * this instance. It otherwise returns 0xFFFFFFFF if both points
239 * are equal, 0x00000000 otherwise. This method is constant-time
240 * (its execution time may depend on whether this and/or the
241 * other point is normalized or not, but not on the actual
244 internal abstract uint EqCT(MutableECPoint Q);
246 internal bool Eq(MutableECPoint Q)