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