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 * This class represents an elliptic curve.
33 public abstract class ECCurve {
36 * Get the subgroup order for this curve (big-endian unsigned
37 * notation). The subgroup order is supposed to be a prime
40 public byte[] SubgroupOrder {
47 * Get the cofactor fors this curve (big-endian unsigned notation).
48 * The cofactor is the quotient of the curve order by the subgroup
51 public byte[] Cofactor {
58 * Get the curve symbolic name.
60 public abstract string Name {
67 public abstract ECCurveType CurveType {
72 * Get the length (in bytes) of an encoded point. The "point at
73 * infinity" may use a shorter encoding than other points. This
74 * uses the "normal" encoding (not compressed).
76 public abstract int EncodedLength {
81 * Get the length (in bytes) of an encoded compressed point.
82 * The "point at infinity" may use a shorter encoding than
85 public abstract int EncodedLengthCompressed {
90 * Perform extensive curve validity checks. These tests may be
91 * computationally expensive.
93 public abstract void CheckValid();
96 * Get the encoded generator for this curve. This is
97 * a conventional point that generates the subgroup of prime
98 * order on which computations are normally done.
100 public virtual byte[] GetGenerator(bool compressed)
102 return MakeGenerator().Encode(compressed);
106 * Get the offset and length of the X coordinate of a point,
107 * within its encoded representation. When doing a Diffie-Hellman
108 * key exchange, the resulting shared secret is the X coordinate
109 * of the resulting point.
111 public abstract int GetXoff(out int len);
114 * Multiply the provided (encoded) point G by a scalar x. Scalar
115 * encoding is big-endian. The scalar value shall be non-zero and
116 * lower than the subgroup order (exception: some curves allow
119 * The result is written in the provided D[] array, using either
120 * compressed or uncompressed format (for some curves, output is
121 * always compressed). The array shall have the appropriate length.
122 * Returned value is -1 on success, 0 on error. If 0 is returned
123 * then the array contents are indeterminate.
125 * G and D need not be distinct arrays.
127 public uint Mul(byte[] G, byte[] x, byte[] D, bool compressed)
129 MutableECPoint P = MakeZero();
130 uint good = P.DecodeCT(G);
131 good &= ~P.IsInfinityCT;
132 good &= P.MulSpecCT(x);
133 good &= P.Encode(D, compressed);
138 * Given points A and B, and scalar x and y, return x*A+y*B. This
139 * is used for ECDSA. Scalars use big-endian encoding and must be
140 * non-zero and lower than the subgroup order.
142 * The result is written in the provided D[] array, using either
143 * compressed or uncompressed format (for some curves, output is
144 * always compressed). The array shall have the appropriate length.
145 * Returned value is -1 on success, 0 on error. If 0 is returned
146 * then the array contents are indeterminate.
148 * Not all curves support this operation; if the curve does not,
149 * then an exception is thrown.
151 * A, B and D need not be distinct arrays.
153 public uint MulAdd(byte[] A, byte[] x, byte[] B, byte[] y,
154 byte[] D, bool compressed)
156 MutableECPoint P = MakeZero();
157 MutableECPoint Q = MakeZero();
160 * Decode both points.
162 uint good = P.DecodeCT(A);
163 good &= Q.DecodeCT(B);
164 good &= ~P.IsInfinityCT & ~Q.IsInfinityCT;
167 * Perform both point multiplications.
169 good &= P.MulSpecCT(x);
170 good &= Q.MulSpecCT(y);
171 good &= ~P.IsInfinityCT & ~Q.IsInfinityCT;
174 * Perform addition. The AddCT() function may fail if
175 * P = Q, in which case we must compute 2Q and use that
183 * Encode the result. The Encode() function will report
184 * an error if the addition result is infinity.
186 good &= P.Encode(D, compressed);
191 * Generate a new random secret value appropriate for an ECDH
192 * key exchange (WARNING: this might not be sufficiently uniform
193 * for the generation of the per-signature secret value 'k' for
196 * The value is returned in unsigned big-endian order, in an array
197 * of the same size of the subgroup order.
199 public abstract byte[] MakeRandomSecret();
201 /* ============================================================= */
203 byte[] subgroupOrder;
206 internal ECCurve(byte[] subgroupOrder, byte[] cofactor)
208 this.subgroupOrder = subgroupOrder;
209 this.cofactor = cofactor;
213 * Create a new mutable point instance, initialized to the point
216 * (On some curves whose implementations do not support generic
217 * point addition, this method may return a non-infinity point
218 * which serves as placeholder to obtain MutableECPoint instances.)
220 internal abstract MutableECPoint MakeZero();
223 * Create a new mutable point instance, initialized to the
224 * defined subgroup generator.
226 internal abstract MutableECPoint MakeGenerator();
229 * Create a new mutable point instance by decoding the provided
232 internal abstract MutableECPoint Decode(byte[] enc);