1 /*
2  * Copyright (c) 2018, 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 import sun.security.util.math.*;
27 
28 import java.math.BigInteger;
29 import java.nio.ByteBuffer;
30 import java.util.Arrays;
31 import java.util.Optional;
32 
33 /**
34  * Arithmetic in the field of integers modulo a prime value implemented using
35  * BigInteger. This implementation is very versatile, but it is slow and none
36  * of the operations are value-independent. This class is intended for use in
37  * testing and prototyping, and production code should probably use a more
38  * specialized arithmetic implementation.
39  */
40 
41 public class BigIntegerModuloP implements IntegerFieldModuloP {
42 
43     private final BigInteger p;
44 
BigIntegerModuloP(BigInteger p)45     public BigIntegerModuloP(BigInteger p) {
46         this.p = p;
47     }
48 
49     @Override
getSize()50     public BigInteger getSize() {
51         return p;
52     }
53 
54     @Override
get0()55     public ImmutableElement get0() {
56         return new ImmutableElement(BigInteger.ZERO);
57     }
58     @Override
get1()59     public ImmutableElement get1() {
60         return new ImmutableElement(BigInteger.ONE);
61     }
62     @Override
getElement(BigInteger v)63     public ImmutableElement getElement(BigInteger v) {
64         return new ImmutableElement(v);
65     }
66     @Override
getElement(byte[] v, int offset, int length, byte highByte)67     public ImmutableElement getElement(byte[] v, int offset, int length,
68                                        byte highByte) {
69         byte[] bigIntIn = new byte[length + 1];
70         System.arraycopy(v, offset, bigIntIn, 0, length);
71         bigIntIn[length] = highByte;
72         reverse(bigIntIn);
73         return new ImmutableElement(new BigInteger(1, bigIntIn).mod(getSize()));
74     }
75     @Override
getSmallValue(int i)76     public SmallValue getSmallValue(int i) {
77         return new SmallElement(i);
78     }
79 
80     private abstract class Element implements IntegerModuloP {
81 
82         protected BigInteger v;
83 
Element(BigInteger v)84         protected Element(BigInteger v) {
85             this.v = v;
86         }
87 
Element(boolean v)88         protected Element(boolean v) {
89             this.v = BigInteger.valueOf(v ? 1 : 0);
90         }
91 
getModulus()92         private BigInteger getModulus() {
93             return getField().getSize();
94         }
95 
96         @Override
getField()97         public IntegerFieldModuloP getField() {
98             return BigIntegerModuloP.this;
99         }
100 
101         @Override
asBigInteger()102         public BigInteger asBigInteger() {
103             return v;
104         }
105 
106         @Override
mutable()107         public MutableElement mutable() {
108             return new MutableElement(v);
109         }
110 
111         @Override
fixed()112         public ImmutableElement fixed() {
113             return new ImmutableElement(v);
114         }
115 
116         @Override
add(IntegerModuloP b)117         public ImmutableElement add(IntegerModuloP b) {
118             return new ImmutableElement(
119                 v.add(b.asBigInteger()).mod(getModulus()));
120         }
121 
122         @Override
additiveInverse()123         public ImmutableElement additiveInverse() {
124             return new ImmutableElement(v.negate().mod(getModulus()));
125         }
126 
127         @Override
multiply(IntegerModuloP b)128         public ImmutableElement multiply(IntegerModuloP b) {
129             return new ImmutableElement(
130                 v.multiply(b.asBigInteger()).mod(getModulus()));
131         }
132 
133         @Override
addModPowerTwo(IntegerModuloP arg, byte[] result)134         public void addModPowerTwo(IntegerModuloP arg, byte[] result) {
135             BigInteger biThis = asBigInteger();
136             BigInteger biArg = arg.asBigInteger();
137             bigIntAsByteArray(biThis.add(biArg), result);
138         }
139 
bigIntAsByteArray(BigInteger arg, byte[] result)140         private void bigIntAsByteArray(BigInteger arg, byte[] result) {
141             byte[] bytes = arg.toByteArray();
142             // bytes is backwards and possibly too big
143             // Copy the low-order bytes into result in reverse
144             int sourceIndex = bytes.length - 1;
145             for (int i = 0; i < result.length; i++) {
146                 if (sourceIndex >= 0) {
147                     result[i] = bytes[sourceIndex--];
148                 } else {
149                     result[i] = 0;
150                 }
151             }
152         }
153 
154         @Override
asByteArray(byte[] result)155         public void asByteArray(byte[] result) {
156             bigIntAsByteArray(v, result);
157         }
158     }
159 
160     private class ImmutableElement extends Element
161         implements ImmutableIntegerModuloP {
162 
ImmutableElement(BigInteger v)163         private ImmutableElement(BigInteger v) {
164             super(v);
165         }
166     }
167 
168     private class MutableElement extends Element
169         implements MutableIntegerModuloP {
170 
MutableElement(BigInteger v)171         private MutableElement(BigInteger v) {
172             super(v);
173         }
174 
175         @Override
conditionalSet(IntegerModuloP b, int set)176         public void conditionalSet(IntegerModuloP b, int set) {
177             if (set == 1) {
178                 v = b.asBigInteger();
179             }
180         }
181 
182         @Override
conditionalSwapWith(MutableIntegerModuloP b, int swap)183         public void conditionalSwapWith(MutableIntegerModuloP b, int swap) {
184             if (swap == 1) {
185                 BigInteger temp = v;
186                 v = b.asBigInteger();
187                 ((Element) b).v = temp;
188             }
189         }
190 
191         @Override
setValue(IntegerModuloP v)192         public MutableElement setValue(IntegerModuloP v) {
193             this.v = ((Element) v).v;
194 
195             return this;
196         }
197 
198         @Override
setValue(byte[] arr, int offset, int length, byte highByte)199         public MutableElement setValue(byte[] arr, int offset, int length,
200                                        byte highByte) {
201             byte[] bigIntIn = new byte[length + 1];
202             System.arraycopy(arr, offset, bigIntIn, 0, length);
203             bigIntIn[length] = highByte;
204             reverse(bigIntIn);
205             v = new BigInteger(bigIntIn).mod(getSize());
206 
207             return this;
208         }
209 
210         @Override
setValue(ByteBuffer buf, int length, byte highByte)211         public MutableElement setValue(ByteBuffer buf, int length,
212                                        byte highByte) {
213             byte[] bigIntIn = new byte[length + 1];
214             buf.get(bigIntIn, 0, length);
215             bigIntIn[length] = highByte;
216             reverse(bigIntIn);
217             v = new BigInteger(bigIntIn).mod(getSize());
218 
219             return this;
220         }
221 
222         @Override
setSquare()223         public MutableElement setSquare() {
224             v = v.multiply(v).mod(getSize());
225             return this;
226         }
227 
228         @Override
setProduct(IntegerModuloP b)229         public MutableElement setProduct(IntegerModuloP b) {
230             Element other = (Element) b;
231             v = v.multiply(other.v).mod(getSize());
232             return this;
233         }
234 
235         @Override
setProduct(SmallValue value)236         public MutableElement setProduct(SmallValue value) {
237             BigInteger bigIntValue = ((SmallElement) value).asBigInteger();
238             v = v.multiply(bigIntValue).mod(getSize());
239             return this;
240         }
241 
242         @Override
setSum(IntegerModuloP b)243         public MutableElement setSum(IntegerModuloP b) {
244             Element other = (Element) b;
245             v = v.add(other.v).mod(getSize());
246             return this;
247         }
248 
249         @Override
setDifference(IntegerModuloP b)250         public MutableElement setDifference(IntegerModuloP b) {
251             Element other = (Element) b;
252             v = v.subtract(other.v).mod(getSize());
253             return this;
254         }
255 
256         @Override
setAdditiveInverse()257         public MutableElement setAdditiveInverse() {
258             v = BigInteger.ZERO.subtract(v);
259             return this;
260         }
261 
262         @Override
setReduced()263         public MutableElement setReduced() {
264             // do nothing
265             return this;
266         }
267 
268     }
269 
270     private class SmallElement extends ImmutableElement implements SmallValue {
271 
SmallElement(int v)272         public SmallElement(int v) {
273             super(BigInteger.valueOf(v).mod(getSize()));
274         }
275     }
276 
swap(byte[] arr, int i, int j)277     private static void swap(byte[] arr, int i, int j) {
278         byte tmp = arr[i];
279         arr[i] = arr[j];
280         arr[j] = tmp;
281     }
282 
reverse(byte [] arr)283     private static void reverse(byte [] arr) {
284         int i = 0;
285         int j = arr.length - 1;
286 
287         while (i < j) {
288             swap(arr, i, j);
289             i++;
290             j--;
291         }
292     }
293 
294 }
295