1 /*
2  * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.security.util.math.intpoly;
27 
28 import java.math.BigInteger;
29 
30 /**
31  * An IntegerFieldModuloP designed for use with the Curve25519.
32  * The representation uses 10 signed long values.
33  */
34 
35 public class IntegerPolynomial25519 extends IntegerPolynomial {
36 
37     private static final int POWER = 255;
38     private static final int SUBTRAHEND = 19;
39     private static final int NUM_LIMBS = 10;
40     private static final int BITS_PER_LIMB = 26;
41     public static final BigInteger MODULUS
42         = TWO.pow(POWER).subtract(BigInteger.valueOf(SUBTRAHEND));
43 
44     // BITS_PER_LIMB does not divide POWER, so reduction is a bit complicated
45     // The constants below help split up values during reduction
46     private static final int BIT_OFFSET = NUM_LIMBS * BITS_PER_LIMB - POWER;
47     private static final int LIMB_MASK = -1 >>> (64 - BITS_PER_LIMB);
48     private static final int RIGHT_BIT_OFFSET = BITS_PER_LIMB - BIT_OFFSET;
49 
IntegerPolynomial25519()50     public IntegerPolynomial25519() {
51         super(BITS_PER_LIMB, NUM_LIMBS, 1, MODULUS);
52     }
53 
54     @Override
reduceIn(long[] limbs, long v, int i)55     protected void reduceIn(long[] limbs, long v, int i) {
56         long t0 = 19 * v;
57         limbs[i - 10] += (t0 << 5) & LIMB_MASK;
58         limbs[i - 9] += t0 >> 21;
59     }
60 
61     @Override
finalCarryReduceLast(long[] limbs)62     protected void finalCarryReduceLast(long[] limbs) {
63 
64         long reducedValue = limbs[numLimbs - 1] >> RIGHT_BIT_OFFSET;
65         limbs[numLimbs - 1] -= reducedValue << RIGHT_BIT_OFFSET;
66         limbs[0] += reducedValue * SUBTRAHEND;
67     }
68 
69     @Override
reduce(long[] a)70     protected void reduce(long[] a) {
71 
72         // carry(8, 2)
73         long carry8 = carryValue(a[8]);
74         a[8] -= (carry8 << BITS_PER_LIMB);
75         a[9] += carry8;
76 
77         long carry9 = carryValue(a[9]);
78         a[9] -= (carry9 << BITS_PER_LIMB);
79 
80         // reduce(0, 1)
81         long reducedValue10 = (carry9 * SUBTRAHEND);
82         a[0] += ((reducedValue10 << BIT_OFFSET) & LIMB_MASK);
83         a[1] += reducedValue10 >> RIGHT_BIT_OFFSET;
84 
85         // carry(0, 9)
86         carry(a, 0, 9);
87     }
88 
89     @Override
mult(long[] a, long[] b, long[] r)90     protected void mult(long[] a, long[] b, long[] r) {
91         long c0 = (a[0] * b[0]);
92         long c1 = (a[0] * b[1]) + (a[1] * b[0]);
93         long c2 = (a[0] * b[2]) + (a[1] * b[1]) + (a[2] * b[0]);
94         long c3 = (a[0] * b[3]) + (a[1] * b[2]) + (a[2] * b[1]) + (a[3] * b[0]);
95         long c4 = (a[0] * b[4]) + (a[1] * b[3]) + (a[2] * b[2]) + (a[3] * b[1]) + (a[4] * b[0]);
96         long c5 = (a[0] * b[5]) + (a[1] * b[4]) + (a[2] * b[3]) + (a[3] * b[2]) + (a[4] * b[1]) + (a[5] * b[0]);
97         long c6 = (a[0] * b[6]) + (a[1] * b[5]) + (a[2] * b[4]) + (a[3] * b[3]) + (a[4] * b[2]) + (a[5] * b[1]) + (a[6] * b[0]);
98         long c7 = (a[0] * b[7]) + (a[1] * b[6]) + (a[2] * b[5]) + (a[3] * b[4]) + (a[4] * b[3]) + (a[5] * b[2]) + (a[6] * b[1]) + (a[7] * b[0]);
99         long c8 = (a[0] * b[8]) + (a[1] * b[7]) + (a[2] * b[6]) + (a[3] * b[5]) + (a[4] * b[4]) + (a[5] * b[3]) + (a[6] * b[2]) + (a[7] * b[1]) + (a[8] * b[0]);
100         long c9 = (a[0] * b[9]) + (a[1] * b[8]) + (a[2] * b[7]) + (a[3] * b[6]) + (a[4] * b[5]) + (a[5] * b[4]) + (a[6] * b[3]) + (a[7] * b[2]) + (a[8] * b[1]) + (a[9] * b[0]);
101         long c10 = (a[1] * b[9]) + (a[2] * b[8]) + (a[3] * b[7]) + (a[4] * b[6]) + (a[5] * b[5]) + (a[6] * b[4]) + (a[7] * b[3]) + (a[8] * b[2]) + (a[9] * b[1]);
102         long c11 = (a[2] * b[9]) + (a[3] * b[8]) + (a[4] * b[7]) + (a[5] * b[6]) + (a[6] * b[5]) + (a[7] * b[4]) + (a[8] * b[3]) + (a[9] * b[2]);
103         long c12 = (a[3] * b[9]) + (a[4] * b[8]) + (a[5] * b[7]) + (a[6] * b[6]) + (a[7] * b[5]) + (a[8] * b[4]) + (a[9] * b[3]);
104         long c13 = (a[4] * b[9]) + (a[5] * b[8]) + (a[6] * b[7]) + (a[7] * b[6]) + (a[8] * b[5]) + (a[9] * b[4]);
105         long c14 = (a[5] * b[9]) + (a[6] * b[8]) + (a[7] * b[7]) + (a[8] * b[6]) + (a[9] * b[5]);
106         long c15 = (a[6] * b[9]) + (a[7] * b[8]) + (a[8] * b[7]) + (a[9] * b[6]);
107         long c16 = (a[7] * b[9]) + (a[8] * b[8]) + (a[9] * b[7]);
108         long c17 = (a[8] * b[9]) + (a[9] * b[8]);
109         long c18 = a[9] * b[9];
110 
111         carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8,
112             c9, c10, c11, c12, c13, c14, c15, c16, c17, c18);
113 
114     }
115 
carryReduce(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18)116     private void carryReduce(long[] r, long c0, long c1, long c2,
117                              long c3, long c4, long c5, long c6,
118                              long c7, long c8, long c9, long c10,
119                              long c11, long c12, long c13, long c14,
120                              long c15, long c16, long c17, long c18) {
121         // reduce(7,2)
122         long reducedValue17 = (c17 * SUBTRAHEND);
123         c7 += (reducedValue17 << BIT_OFFSET) & LIMB_MASK;
124         c8 += reducedValue17 >> RIGHT_BIT_OFFSET;
125 
126         long reducedValue18 = (c18 * SUBTRAHEND);
127         c8 += (reducedValue18 << BIT_OFFSET) & LIMB_MASK;
128         c9 += reducedValue18 >> RIGHT_BIT_OFFSET;
129 
130         // carry(8,2)
131         long carry8 = carryValue(c8);
132         r[8] = c8 - (carry8 << BITS_PER_LIMB);
133         c9 += carry8;
134 
135         long carry9 = carryValue(c9);
136         r[9] = c9 - (carry9 << BITS_PER_LIMB);
137         c10 += carry9;
138 
139         // reduce(0,7)
140         long reducedValue10 = (c10 * SUBTRAHEND);
141         r[0] = c0 + ((reducedValue10 << BIT_OFFSET) & LIMB_MASK);
142         c1 += reducedValue10 >> RIGHT_BIT_OFFSET;
143 
144         long reducedValue11 = (c11 * SUBTRAHEND);
145         r[1] = c1 + ((reducedValue11 << BIT_OFFSET) & LIMB_MASK);
146         c2 += reducedValue11 >> RIGHT_BIT_OFFSET;
147 
148         long reducedValue12 = (c12 * SUBTRAHEND);
149         r[2] = c2 + ((reducedValue12 << BIT_OFFSET) & LIMB_MASK);
150         c3 += reducedValue12 >> RIGHT_BIT_OFFSET;
151 
152         long reducedValue13 = (c13 * SUBTRAHEND);
153         r[3] = c3 + ((reducedValue13 << BIT_OFFSET) & LIMB_MASK);
154         c4 += reducedValue13 >> RIGHT_BIT_OFFSET;
155 
156         long reducedValue14 = (c14 * SUBTRAHEND);
157         r[4] = c4 + ((reducedValue14 << BIT_OFFSET) & LIMB_MASK);
158         c5 += reducedValue14 >> RIGHT_BIT_OFFSET;
159 
160         long reducedValue15 = (c15 * SUBTRAHEND);
161         r[5] = c5 + ((reducedValue15 << BIT_OFFSET) & LIMB_MASK);
162         c6 += reducedValue15 >> RIGHT_BIT_OFFSET;
163 
164         long reducedValue16 = (c16 * SUBTRAHEND);
165         r[6] = c6 + ((reducedValue16 << BIT_OFFSET) & LIMB_MASK);
166         r[7] = c7 + (reducedValue16 >> RIGHT_BIT_OFFSET);
167 
168         // carry(0,9)
169         carry(r, 0, 9);
170     }
171     @Override
square(long[] a, long[] r)172     protected void square(long[] a, long[] r) {
173 
174         // Use grade-school multiplication with a simple squaring optimization.
175         // Multiply into primitives to avoid the temporary array allocation.
176         // This is equivalent to the following code:
177         //  long[] c = new long[2 * NUM_LIMBS - 1];
178         //  for(int i = 0; i < NUM_LIMBS; i++) {
179         //      c[2 * i] = a[i] * a[i];
180         //      for(int j = i + 1; j < NUM_LIMBS; j++) {
181         //          c[i + j] += 2 * a[i] * a[j]
182         //      }
183         //  }
184 
185         long c0 = a[0] * a[0];
186         long c1 = 2 * a[0] * a[1];
187         long c2 = a[1] * a[1] + 2 * a[0] * a[2];
188         long c3 = 2 * (a[0] * a[3] + a[1] * a[2]);
189         long c4 = a[2] * a[2] + 2 * (a[0] * a[4] + a[1] * a[3]);
190         long c5 = 2 * (a[0] * a[5] + a[1] * a[4] + a[2] * a[3]);
191         long c6 = a[3] * a[3] + 2 * (a[0] * a[6] + a[1] * a[5] + a[2] * a[4]);
192         long c7 = 2 * (a[0] * a[7] + a[1] * a[6] + a[2] * a[5] + a[3] * a[4]);
193         long c8 = a[4] * a[4] + 2 * (a[0] * a[8] + a[1] * a[7] + a[2] * a[6] + a[3] * a[5]);
194         long c9 = 2 * (a[0] * a[9] + a[1] * a[8] + a[2] * a[7] + a[3] * a[6] + a[4] * a[5]);
195         long c10 = a[5] * a[5] + 2 * (a[1] * a[9] + a[2] * a[8] + a[3] * a[7] + a[4] * a[6]);
196         long c11 = 2 * (a[2] * a[9] + a[3] * a[8] + a[4] * a[7] + a[5] * a[6]);
197         long c12 = a[6] * a[6] + 2 * (a[3] * a[9] + a[4] * a[8] + a[5] * a[7]);
198         long c13 = 2 * (a[4] * a[9] + a[5] * a[8] + a[6] * a[7]);
199         long c14 = a[7] * a[7] + 2 * (a[5] * a[9] + a[6] * a[8]);
200         long c15 = 2 * (a[6] * a[9] + a[7] * a[8]);
201         long c16 = a[8] * a[8] + 2 * a[7] * a[9];
202         long c17 = 2 * a[8] * a[9];
203         long c18 = a[9] * a[9];
204 
205         carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8,
206             c9, c10, c11, c12, c13, c14, c15, c16, c17, c18);
207     }
208 
209 
210 }
211