annotate curve25519-donna.c @ 994:5c5ade336926

Prefer stronger algorithms in algorithm negotiation. Prefer diffie-hellman-group14-sha1 (2048 bit) over diffie-hellman-group1-sha1 (1024 bit). Due to meet-in-the-middle attacks the effective key length of three key 3DES is 112 bits. AES is stronger and faster then 3DES. Prefer to delay the start of compression until after authentication has completed. This avoids exposing compression code to attacks from unauthenticated users. (github pull request #9)
author Fedor Brunner <fedor.brunner@azet.sk>
date Fri, 23 Jan 2015 23:00:25 +0800
parents 6c69e7df3621
children d3925ed45a85
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
848
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
1 /* Copyright 2008, Google Inc.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
2 * All rights reserved.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
3 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
4 * Redistribution and use in source and binary forms, with or without
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
5 * modification, are permitted provided that the following conditions are
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
6 * met:
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
7 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
8 * * Redistributions of source code must retain the above copyright
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
9 * notice, this list of conditions and the following disclaimer.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
10 * * Redistributions in binary form must reproduce the above
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
11 * copyright notice, this list of conditions and the following disclaimer
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
12 * in the documentation and/or other materials provided with the
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
13 * distribution.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
14 * * Neither the name of Google Inc. nor the names of its
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
15 * contributors may be used to endorse or promote products derived from
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
16 * this software without specific prior written permission.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
17 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
29 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
30 * curve25519-donna: Curve25519 elliptic curve, public key function
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
31 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
32 * http://code.google.com/p/curve25519-donna/
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
33 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
34 * Adam Langley <[email protected]>
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
35 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
36 * Derived from public domain C code by Daniel J. Bernstein <[email protected]>
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
37 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
38 * More information about curve25519 can be found here
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
39 * http://cr.yp.to/ecdh.html
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
40 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
41 * djb's sample implementation of curve25519 is written in a special assembly
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
42 * language called qhasm and uses the floating point registers.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
43 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
44 * This is, almost, a clean room reimplementation from the curve25519 paper. It
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
45 * uses many of the tricks described therein. Only the crecip function is taken
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
46 * from the sample implementation.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
47 */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
48
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
49 #include <string.h>
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
50 #include <stdint.h>
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
51
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
52 #ifdef _MSC_VER
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
53 #define inline __inline
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
54 #endif
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
55
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
56 typedef uint8_t u8;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
57 typedef int32_t s32;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
58 typedef int64_t limb;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
59
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
60 /* Field element representation:
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
61 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
62 * Field elements are written as an array of signed, 64-bit limbs, least
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
63 * significant first. The value of the field element is:
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
64 * x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ...
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
65 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
66 * i.e. the limbs are 26, 25, 26, 25, ... bits wide.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
67 */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
68
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
69 /* Sum two numbers: output += in */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
70 static void fsum(limb *output, const limb *in) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
71 unsigned i;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
72 for (i = 0; i < 10; i += 2) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
73 output[0+i] = (output[0+i] + in[0+i]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
74 output[1+i] = (output[1+i] + in[1+i]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
75 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
76 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
77
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
78 /* Find the difference of two numbers: output = in - output
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
79 * (note the order of the arguments!)
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
80 */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
81 static void fdifference(limb *output, const limb *in) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
82 unsigned i;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
83 for (i = 0; i < 10; ++i) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
84 output[i] = (in[i] - output[i]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
85 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
86 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
87
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
88 /* Multiply a number by a scalar: output = in * scalar */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
89 static void fscalar_product(limb *output, const limb *in, const limb scalar) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
90 unsigned i;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
91 for (i = 0; i < 10; ++i) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
92 output[i] = in[i] * scalar;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
93 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
94 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
95
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
96 /* Multiply two numbers: output = in2 * in
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
97 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
98 * output must be distinct to both inputs. The inputs are reduced coefficient
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
99 * form, the output is not.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
100 */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
101 static void fproduct(limb *output, const limb *in2, const limb *in) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
102 output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
103 output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
104 ((limb) ((s32) in2[1])) * ((s32) in[0]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
105 output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
106 ((limb) ((s32) in2[0])) * ((s32) in[2]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
107 ((limb) ((s32) in2[2])) * ((s32) in[0]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
108 output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
109 ((limb) ((s32) in2[2])) * ((s32) in[1]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
110 ((limb) ((s32) in2[0])) * ((s32) in[3]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
111 ((limb) ((s32) in2[3])) * ((s32) in[0]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
112 output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
113 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
114 ((limb) ((s32) in2[3])) * ((s32) in[1])) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
115 ((limb) ((s32) in2[0])) * ((s32) in[4]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
116 ((limb) ((s32) in2[4])) * ((s32) in[0]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
117 output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
118 ((limb) ((s32) in2[3])) * ((s32) in[2]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
119 ((limb) ((s32) in2[1])) * ((s32) in[4]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
120 ((limb) ((s32) in2[4])) * ((s32) in[1]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
121 ((limb) ((s32) in2[0])) * ((s32) in[5]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
122 ((limb) ((s32) in2[5])) * ((s32) in[0]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
123 output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
124 ((limb) ((s32) in2[1])) * ((s32) in[5]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
125 ((limb) ((s32) in2[5])) * ((s32) in[1])) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
126 ((limb) ((s32) in2[2])) * ((s32) in[4]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
127 ((limb) ((s32) in2[4])) * ((s32) in[2]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
128 ((limb) ((s32) in2[0])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
129 ((limb) ((s32) in2[6])) * ((s32) in[0]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
130 output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
131 ((limb) ((s32) in2[4])) * ((s32) in[3]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
132 ((limb) ((s32) in2[2])) * ((s32) in[5]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
133 ((limb) ((s32) in2[5])) * ((s32) in[2]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
134 ((limb) ((s32) in2[1])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
135 ((limb) ((s32) in2[6])) * ((s32) in[1]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
136 ((limb) ((s32) in2[0])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
137 ((limb) ((s32) in2[7])) * ((s32) in[0]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
138 output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
139 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
140 ((limb) ((s32) in2[5])) * ((s32) in[3]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
141 ((limb) ((s32) in2[1])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
142 ((limb) ((s32) in2[7])) * ((s32) in[1])) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
143 ((limb) ((s32) in2[2])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
144 ((limb) ((s32) in2[6])) * ((s32) in[2]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
145 ((limb) ((s32) in2[0])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
146 ((limb) ((s32) in2[8])) * ((s32) in[0]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
147 output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
148 ((limb) ((s32) in2[5])) * ((s32) in[4]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
149 ((limb) ((s32) in2[3])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
150 ((limb) ((s32) in2[6])) * ((s32) in[3]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
151 ((limb) ((s32) in2[2])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
152 ((limb) ((s32) in2[7])) * ((s32) in[2]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
153 ((limb) ((s32) in2[1])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
154 ((limb) ((s32) in2[8])) * ((s32) in[1]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
155 ((limb) ((s32) in2[0])) * ((s32) in[9]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
156 ((limb) ((s32) in2[9])) * ((s32) in[0]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
157 output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
158 ((limb) ((s32) in2[3])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
159 ((limb) ((s32) in2[7])) * ((s32) in[3]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
160 ((limb) ((s32) in2[1])) * ((s32) in[9]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
161 ((limb) ((s32) in2[9])) * ((s32) in[1])) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
162 ((limb) ((s32) in2[4])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
163 ((limb) ((s32) in2[6])) * ((s32) in[4]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
164 ((limb) ((s32) in2[2])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
165 ((limb) ((s32) in2[8])) * ((s32) in[2]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
166 output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
167 ((limb) ((s32) in2[6])) * ((s32) in[5]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
168 ((limb) ((s32) in2[4])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
169 ((limb) ((s32) in2[7])) * ((s32) in[4]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
170 ((limb) ((s32) in2[3])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
171 ((limb) ((s32) in2[8])) * ((s32) in[3]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
172 ((limb) ((s32) in2[2])) * ((s32) in[9]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
173 ((limb) ((s32) in2[9])) * ((s32) in[2]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
174 output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
175 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
176 ((limb) ((s32) in2[7])) * ((s32) in[5]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
177 ((limb) ((s32) in2[3])) * ((s32) in[9]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
178 ((limb) ((s32) in2[9])) * ((s32) in[3])) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
179 ((limb) ((s32) in2[4])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
180 ((limb) ((s32) in2[8])) * ((s32) in[4]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
181 output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
182 ((limb) ((s32) in2[7])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
183 ((limb) ((s32) in2[5])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
184 ((limb) ((s32) in2[8])) * ((s32) in[5]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
185 ((limb) ((s32) in2[4])) * ((s32) in[9]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
186 ((limb) ((s32) in2[9])) * ((s32) in[4]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
187 output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
188 ((limb) ((s32) in2[5])) * ((s32) in[9]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
189 ((limb) ((s32) in2[9])) * ((s32) in[5])) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
190 ((limb) ((s32) in2[6])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
191 ((limb) ((s32) in2[8])) * ((s32) in[6]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
192 output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
193 ((limb) ((s32) in2[8])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
194 ((limb) ((s32) in2[6])) * ((s32) in[9]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
195 ((limb) ((s32) in2[9])) * ((s32) in[6]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
196 output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
197 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
198 ((limb) ((s32) in2[9])) * ((s32) in[7]));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
199 output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
200 ((limb) ((s32) in2[9])) * ((s32) in[8]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
201 output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
202 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
203
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
204 /* Reduce a long form to a short form by taking the input mod 2^255 - 19. */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
205 static void freduce_degree(limb *output) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
206 /* Each of these shifts and adds ends up multiplying the value by 19. */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
207 output[8] += output[18] << 4;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
208 output[8] += output[18] << 1;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
209 output[8] += output[18];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
210 output[7] += output[17] << 4;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
211 output[7] += output[17] << 1;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
212 output[7] += output[17];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
213 output[6] += output[16] << 4;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
214 output[6] += output[16] << 1;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
215 output[6] += output[16];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
216 output[5] += output[15] << 4;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
217 output[5] += output[15] << 1;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
218 output[5] += output[15];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
219 output[4] += output[14] << 4;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
220 output[4] += output[14] << 1;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
221 output[4] += output[14];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
222 output[3] += output[13] << 4;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
223 output[3] += output[13] << 1;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
224 output[3] += output[13];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
225 output[2] += output[12] << 4;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
226 output[2] += output[12] << 1;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
227 output[2] += output[12];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
228 output[1] += output[11] << 4;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
229 output[1] += output[11] << 1;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
230 output[1] += output[11];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
231 output[0] += output[10] << 4;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
232 output[0] += output[10] << 1;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
233 output[0] += output[10];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
234 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
235
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
236 #if (-1 & 3) != 3
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
237 #error "This code only works on a two's complement system"
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
238 #endif
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
239
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
240 /* return v / 2^26, using only shifts and adds. */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
241 static inline limb
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
242 div_by_2_26(const limb v)
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
243 {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
244 /* High word of v; no shift needed*/
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
245 const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
246 /* Set to all 1s if v was negative; else set to 0s. */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
247 const int32_t sign = ((int32_t) highword) >> 31;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
248 /* Set to 0x3ffffff if v was negative; else set to 0. */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
249 const int32_t roundoff = ((uint32_t) sign) >> 6;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
250 /* Should return v / (1<<26) */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
251 return (v + roundoff) >> 26;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
252 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
253
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
254 /* return v / (2^25), using only shifts and adds. */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
255 static inline limb
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
256 div_by_2_25(const limb v)
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
257 {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
258 /* High word of v; no shift needed*/
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
259 const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
260 /* Set to all 1s if v was negative; else set to 0s. */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
261 const int32_t sign = ((int32_t) highword) >> 31;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
262 /* Set to 0x1ffffff if v was negative; else set to 0. */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
263 const int32_t roundoff = ((uint32_t) sign) >> 7;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
264 /* Should return v / (1<<25) */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
265 return (v + roundoff) >> 25;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
266 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
267
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
268 static inline s32
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
269 div_s32_by_2_25(const s32 v)
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
270 {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
271 const s32 roundoff = ((uint32_t)(v >> 31)) >> 7;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
272 return (v + roundoff) >> 25;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
273 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
274
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
275 /* Reduce all coefficients of the short form input so that |x| < 2^26.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
276 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
277 * On entry: |output[i]| < 2^62
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
278 */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
279 static void freduce_coefficients(limb *output) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
280 unsigned i;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
281
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
282 output[10] = 0;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
283
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
284 for (i = 0; i < 10; i += 2) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
285 limb over = div_by_2_26(output[i]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
286 output[i] -= over << 26;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
287 output[i+1] += over;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
288
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
289 over = div_by_2_25(output[i+1]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
290 output[i+1] -= over << 25;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
291 output[i+2] += over;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
292 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
293 /* Now |output[10]| < 2 ^ 38 and all other coefficients are reduced. */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
294 output[0] += output[10] << 4;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
295 output[0] += output[10] << 1;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
296 output[0] += output[10];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
297
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
298 output[10] = 0;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
299
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
300 /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19 * 2^38
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
301 * So |over| will be no more than 77825 */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
302 {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
303 limb over = div_by_2_26(output[0]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
304 output[0] -= over << 26;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
305 output[1] += over;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
306 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
307
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
308 /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 77825
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
309 * So |over| will be no more than 1. */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
310 {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
311 /* output[1] fits in 32 bits, so we can use div_s32_by_2_25 here. */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
312 s32 over32 = div_s32_by_2_25((s32) output[1]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
313 output[1] -= over32 << 25;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
314 output[2] += over32;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
315 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
316
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
317 /* Finally, output[0,1,3..9] are reduced, and output[2] is "nearly reduced":
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
318 * we have |output[2]| <= 2^26. This is good enough for all of our math,
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
319 * but it will require an extra freduce_coefficients before fcontract. */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
320 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
321
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
322 /* A helpful wrapper around fproduct: output = in * in2.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
323 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
324 * output must be distinct to both inputs. The output is reduced degree and
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
325 * reduced coefficient.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
326 */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
327 static void
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
328 fmul(limb *output, const limb *in, const limb *in2) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
329 limb t[19];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
330 fproduct(t, in, in2);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
331 freduce_degree(t);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
332 freduce_coefficients(t);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
333 memcpy(output, t, sizeof(limb) * 10);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
334 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
335
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
336 static void fsquare_inner(limb *output, const limb *in) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
337 output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
338 output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
339 output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
340 ((limb) ((s32) in[0])) * ((s32) in[2]));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
341 output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
342 ((limb) ((s32) in[0])) * ((s32) in[3]));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
343 output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
344 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
345 2 * ((limb) ((s32) in[0])) * ((s32) in[4]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
346 output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
347 ((limb) ((s32) in[1])) * ((s32) in[4]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
348 ((limb) ((s32) in[0])) * ((s32) in[5]));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
349 output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
350 ((limb) ((s32) in[2])) * ((s32) in[4]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
351 ((limb) ((s32) in[0])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
352 2 * ((limb) ((s32) in[1])) * ((s32) in[5]));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
353 output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
354 ((limb) ((s32) in[2])) * ((s32) in[5]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
355 ((limb) ((s32) in[1])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
356 ((limb) ((s32) in[0])) * ((s32) in[7]));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
357 output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
358 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
359 ((limb) ((s32) in[0])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
360 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
361 ((limb) ((s32) in[3])) * ((s32) in[5])));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
362 output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
363 ((limb) ((s32) in[3])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
364 ((limb) ((s32) in[2])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
365 ((limb) ((s32) in[1])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
366 ((limb) ((s32) in[0])) * ((s32) in[9]));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
367 output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
368 ((limb) ((s32) in[4])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
369 ((limb) ((s32) in[2])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
370 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
371 ((limb) ((s32) in[1])) * ((s32) in[9])));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
372 output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
373 ((limb) ((s32) in[4])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
374 ((limb) ((s32) in[3])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
375 ((limb) ((s32) in[2])) * ((s32) in[9]));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
376 output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
377 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
378 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
379 ((limb) ((s32) in[3])) * ((s32) in[9])));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
380 output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
381 ((limb) ((s32) in[5])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
382 ((limb) ((s32) in[4])) * ((s32) in[9]));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
383 output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
384 ((limb) ((s32) in[6])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
385 2 * ((limb) ((s32) in[5])) * ((s32) in[9]));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
386 output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
387 ((limb) ((s32) in[6])) * ((s32) in[9]));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
388 output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) +
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
389 4 * ((limb) ((s32) in[7])) * ((s32) in[9]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
390 output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
391 output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
392 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
393
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
394 static void
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
395 fsquare(limb *output, const limb *in) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
396 limb t[19];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
397 fsquare_inner(t, in);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
398 freduce_degree(t);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
399 freduce_coefficients(t);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
400 memcpy(output, t, sizeof(limb) * 10);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
401 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
402
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
403 /* Take a little-endian, 32-byte number and expand it into polynomial form */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
404 static void
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
405 fexpand(limb *output, const u8 *input) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
406 #define F(n,start,shift,mask) \
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
407 output[n] = ((((limb) input[start + 0]) | \
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
408 ((limb) input[start + 1]) << 8 | \
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
409 ((limb) input[start + 2]) << 16 | \
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
410 ((limb) input[start + 3]) << 24) >> shift) & mask;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
411 F(0, 0, 0, 0x3ffffff);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
412 F(1, 3, 2, 0x1ffffff);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
413 F(2, 6, 3, 0x3ffffff);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
414 F(3, 9, 5, 0x1ffffff);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
415 F(4, 12, 6, 0x3ffffff);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
416 F(5, 16, 0, 0x1ffffff);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
417 F(6, 19, 1, 0x3ffffff);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
418 F(7, 22, 3, 0x1ffffff);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
419 F(8, 25, 4, 0x3ffffff);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
420 F(9, 28, 6, 0x3ffffff);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
421 #undef F
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
422 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
423
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
424 #if (-32 >> 1) != -16
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
425 #error "This code only works when >> does sign-extension on negative numbers"
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
426 #endif
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
427
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
428 /* Take a fully reduced polynomial form number and contract it into a
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
429 * little-endian, 32-byte array
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
430 */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
431 static void
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
432 fcontract(u8 *output, limb *input) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
433 int i;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
434 int j;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
435
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
436 for (j = 0; j < 2; ++j) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
437 for (i = 0; i < 9; ++i) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
438 if ((i & 1) == 1) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
439 /* This calculation is a time-invariant way to make input[i] positive
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
440 by borrowing from the next-larger limb.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
441 */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
442 const s32 mask = (s32)(input[i]) >> 31;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
443 const s32 carry = -(((s32)(input[i]) & mask) >> 25);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
444 input[i] = (s32)(input[i]) + (carry << 25);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
445 input[i+1] = (s32)(input[i+1]) - carry;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
446 } else {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
447 const s32 mask = (s32)(input[i]) >> 31;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
448 const s32 carry = -(((s32)(input[i]) & mask) >> 26);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
449 input[i] = (s32)(input[i]) + (carry << 26);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
450 input[i+1] = (s32)(input[i+1]) - carry;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
451 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
452 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
453 {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
454 const s32 mask = (s32)(input[9]) >> 31;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
455 const s32 carry = -(((s32)(input[9]) & mask) >> 25);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
456 input[9] = (s32)(input[9]) + (carry << 25);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
457 input[0] = (s32)(input[0]) - (carry * 19);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
458 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
459 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
460
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
461 /* The first borrow-propagation pass above ended with every limb
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
462 except (possibly) input[0] non-negative.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
463
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
464 Since each input limb except input[0] is decreased by at most 1
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
465 by a borrow-propagation pass, the second borrow-propagation pass
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
466 could only have wrapped around to decrease input[0] again if the
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
467 first pass left input[0] negative *and* input[1] through input[9]
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
468 were all zero. In that case, input[1] is now 2^25 - 1, and this
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
469 last borrow-propagation step will leave input[1] non-negative.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
470 */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
471 {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
472 const s32 mask = (s32)(input[0]) >> 31;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
473 const s32 carry = -(((s32)(input[0]) & mask) >> 26);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
474 input[0] = (s32)(input[0]) + (carry << 26);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
475 input[1] = (s32)(input[1]) - carry;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
476 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
477
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
478 /* Both passes through the above loop, plus the last 0-to-1 step, are
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
479 necessary: if input[9] is -1 and input[0] through input[8] are 0,
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
480 negative values will remain in the array until the end.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
481 */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
482
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
483 input[1] <<= 2;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
484 input[2] <<= 3;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
485 input[3] <<= 5;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
486 input[4] <<= 6;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
487 input[6] <<= 1;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
488 input[7] <<= 3;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
489 input[8] <<= 4;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
490 input[9] <<= 6;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
491 #define F(i, s) \
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
492 output[s+0] |= input[i] & 0xff; \
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
493 output[s+1] = (input[i] >> 8) & 0xff; \
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
494 output[s+2] = (input[i] >> 16) & 0xff; \
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
495 output[s+3] = (input[i] >> 24) & 0xff;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
496 output[0] = 0;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
497 output[16] = 0;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
498 F(0,0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
499 F(1,3);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
500 F(2,6);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
501 F(3,9);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
502 F(4,12);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
503 F(5,16);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
504 F(6,19);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
505 F(7,22);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
506 F(8,25);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
507 F(9,28);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
508 #undef F
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
509 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
510
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
511 /* Input: Q, Q', Q-Q'
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
512 * Output: 2Q, Q+Q'
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
513 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
514 * x2 z3: long form
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
515 * x3 z3: long form
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
516 * x z: short form, destroyed
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
517 * xprime zprime: short form, destroyed
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
518 * qmqp: short form, preserved
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
519 */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
520 static void fmonty(limb *x2, limb *z2, /* output 2Q */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
521 limb *x3, limb *z3, /* output Q + Q' */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
522 limb *x, limb *z, /* input Q */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
523 limb *xprime, limb *zprime, /* input Q' */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
524 const limb *qmqp /* input Q - Q' */) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
525 limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19],
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
526 zzprime[19], zzzprime[19], xxxprime[19];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
527
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
528 memcpy(origx, x, 10 * sizeof(limb));
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
529 fsum(x, z);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
530 fdifference(z, origx); // does x - z
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
531
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
532 memcpy(origxprime, xprime, sizeof(limb) * 10);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
533 fsum(xprime, zprime);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
534 fdifference(zprime, origxprime);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
535 fproduct(xxprime, xprime, z);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
536 fproduct(zzprime, x, zprime);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
537 freduce_degree(xxprime);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
538 freduce_coefficients(xxprime);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
539 freduce_degree(zzprime);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
540 freduce_coefficients(zzprime);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
541 memcpy(origxprime, xxprime, sizeof(limb) * 10);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
542 fsum(xxprime, zzprime);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
543 fdifference(zzprime, origxprime);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
544 fsquare(xxxprime, xxprime);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
545 fsquare(zzzprime, zzprime);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
546 fproduct(zzprime, zzzprime, qmqp);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
547 freduce_degree(zzprime);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
548 freduce_coefficients(zzprime);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
549 memcpy(x3, xxxprime, sizeof(limb) * 10);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
550 memcpy(z3, zzprime, sizeof(limb) * 10);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
551
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
552 fsquare(xx, x);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
553 fsquare(zz, z);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
554 fproduct(x2, xx, zz);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
555 freduce_degree(x2);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
556 freduce_coefficients(x2);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
557 fdifference(zz, xx); // does zz = xx - zz
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
558 memset(zzz + 10, 0, sizeof(limb) * 9);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
559 fscalar_product(zzz, zz, 121665);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
560 /* No need to call freduce_degree here:
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
561 fscalar_product doesn't increase the degree of its input. */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
562 freduce_coefficients(zzz);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
563 fsum(zzz, xx);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
564 fproduct(z2, zz, zzz);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
565 freduce_degree(z2);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
566 freduce_coefficients(z2);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
567 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
568
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
569 /* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
570 * them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
571 * side-channel attacks.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
572 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
573 * NOTE that this function requires that 'iswap' be 1 or 0; other values give
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
574 * wrong results. Also, the two limb arrays must be in reduced-coefficient,
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
575 * reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped,
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
576 * and all all values in a[0..9],b[0..9] must have magnitude less than
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
577 * INT32_MAX.
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
578 */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
579 static void
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
580 swap_conditional(limb a[19], limb b[19], limb iswap) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
581 unsigned i;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
582 const s32 swap = (s32) -iswap;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
583
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
584 for (i = 0; i < 10; ++i) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
585 const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) );
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
586 a[i] = ((s32)a[i]) ^ x;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
587 b[i] = ((s32)b[i]) ^ x;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
588 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
589 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
590
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
591 /* Calculates nQ where Q is the x-coordinate of a point on the curve
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
592 *
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
593 * resultx/resultz: the x coordinate of the resulting curve point (short form)
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
594 * n: a little endian, 32-byte number
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
595 * q: a point of the curve (short form)
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
596 */
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
597 static void
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
598 cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
599 limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0};
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
600 limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
601 limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1};
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
602 limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
603
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
604 unsigned i, j;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
605
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
606 memcpy(nqpqx, q, sizeof(limb) * 10);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
607
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
608 for (i = 0; i < 32; ++i) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
609 u8 byte = n[31 - i];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
610 for (j = 0; j < 8; ++j) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
611 const limb bit = byte >> 7;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
612
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
613 swap_conditional(nqx, nqpqx, bit);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
614 swap_conditional(nqz, nqpqz, bit);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
615 fmonty(nqx2, nqz2,
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
616 nqpqx2, nqpqz2,
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
617 nqx, nqz,
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
618 nqpqx, nqpqz,
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
619 q);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
620 swap_conditional(nqx2, nqpqx2, bit);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
621 swap_conditional(nqz2, nqpqz2, bit);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
622
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
623 t = nqx;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
624 nqx = nqx2;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
625 nqx2 = t;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
626 t = nqz;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
627 nqz = nqz2;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
628 nqz2 = t;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
629 t = nqpqx;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
630 nqpqx = nqpqx2;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
631 nqpqx2 = t;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
632 t = nqpqz;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
633 nqpqz = nqpqz2;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
634 nqpqz2 = t;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
635
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
636 byte <<= 1;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
637 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
638 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
639
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
640 memcpy(resultx, nqx, sizeof(limb) * 10);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
641 memcpy(resultz, nqz, sizeof(limb) * 10);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
642 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
643
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
644 // -----------------------------------------------------------------------------
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
645 // Shamelessly copied from djb's code
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
646 // -----------------------------------------------------------------------------
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
647 static void
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
648 crecip(limb *out, const limb *z) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
649 limb z2[10];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
650 limb z9[10];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
651 limb z11[10];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
652 limb z2_5_0[10];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
653 limb z2_10_0[10];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
654 limb z2_20_0[10];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
655 limb z2_50_0[10];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
656 limb z2_100_0[10];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
657 limb t0[10];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
658 limb t1[10];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
659 int i;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
660
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
661 /* 2 */ fsquare(z2,z);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
662 /* 4 */ fsquare(t1,z2);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
663 /* 8 */ fsquare(t0,t1);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
664 /* 9 */ fmul(z9,t0,z);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
665 /* 11 */ fmul(z11,z9,z2);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
666 /* 22 */ fsquare(t0,z11);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
667 /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
668
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
669 /* 2^6 - 2^1 */ fsquare(t0,z2_5_0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
670 /* 2^7 - 2^2 */ fsquare(t1,t0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
671 /* 2^8 - 2^3 */ fsquare(t0,t1);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
672 /* 2^9 - 2^4 */ fsquare(t1,t0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
673 /* 2^10 - 2^5 */ fsquare(t0,t1);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
674 /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
675
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
676 /* 2^11 - 2^1 */ fsquare(t0,z2_10_0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
677 /* 2^12 - 2^2 */ fsquare(t1,t0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
678 /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
679 /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
680
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
681 /* 2^21 - 2^1 */ fsquare(t0,z2_20_0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
682 /* 2^22 - 2^2 */ fsquare(t1,t0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
683 /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
684 /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
685
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
686 /* 2^41 - 2^1 */ fsquare(t1,t0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
687 /* 2^42 - 2^2 */ fsquare(t0,t1);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
688 /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
689 /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
690
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
691 /* 2^51 - 2^1 */ fsquare(t0,z2_50_0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
692 /* 2^52 - 2^2 */ fsquare(t1,t0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
693 /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
694 /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
695
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
696 /* 2^101 - 2^1 */ fsquare(t1,z2_100_0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
697 /* 2^102 - 2^2 */ fsquare(t0,t1);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
698 /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
699 /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
700
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
701 /* 2^201 - 2^1 */ fsquare(t0,t1);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
702 /* 2^202 - 2^2 */ fsquare(t1,t0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
703 /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
704 /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
705
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
706 /* 2^251 - 2^1 */ fsquare(t1,t0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
707 /* 2^252 - 2^2 */ fsquare(t0,t1);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
708 /* 2^253 - 2^3 */ fsquare(t1,t0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
709 /* 2^254 - 2^4 */ fsquare(t0,t1);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
710 /* 2^255 - 2^5 */ fsquare(t1,t0);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
711 /* 2^255 - 21 */ fmul(out,t1,z11);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
712 }
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
713
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
714 int curve25519_donna(u8 *, const u8 *, const u8 *);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
715
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
716 int
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
717 curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
718 limb bp[10], x[10], z[11], zmone[10];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
719 uint8_t e[32];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
720 int i;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
721
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
722 for (i = 0; i < 32; ++i) e[i] = secret[i];
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
723 e[0] &= 248;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
724 e[31] &= 127;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
725 e[31] |= 64;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
726
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
727 fexpand(bp, basepoint);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
728 cmult(x, z, e, bp);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
729 crecip(zmone, z);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
730 fmul(z, x, zmone);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
731 freduce_coefficients(z);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
732 fcontract(mypublic, z);
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
733 return 0;
6c69e7df3621 curve25519
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
734 }