From 744c0dc2958870899d8b604bc3cclalef04db5 Mon Sep 17 00:00:00 2001
From: Peter Dettman <peter.dettman@bouncycastle.org>
Date: Fri, 3 Jul 2020 23:18:22 +0700
Subject: [PATCH] Methods for generating random FEs

---
 .../org/bouncycastle/math/ec/ECCurve.java     | 90 ++++++++++++++++++-
 1 file changed, 86 insertions(+), 4 deletions(-)

diff --git a/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java b/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java
index 7c10c78..19cbd92 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java
@@ -1,6 +1,7 @@
 package org.bouncycastle.math.ec;
 
 import java.math.BigInteger;
+import java.security.SecureRandom;
 import java.util.Hashtable;
 import java.util.Random;
 
@@ -107,6 +108,10 @@ protected ECCurve(FiniteField field)
 
     public abstract boolean isValidFieldElement(BigInteger x);
 
+    public abstract ECFieldElement randomFieldElement(SecureRandom r);
+
+    public abstract ECFieldElement randomFieldElementMult(SecureRandom r);
+
     public synchronized Config configure()
     {
         return new Config(this.coord, this.endomorphism, this.multiplier);
@@ -589,6 +594,30 @@ public boolean isValidFieldElement(BigInteger x)
             return x != null && x.signum() >= 0 && x.compareTo(this.getField().getCharacteristic()) < 0;
         }
 
+        public ECFieldElement randomFieldElement(SecureRandom r)
+        {
+            /*
+             * NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we
+             * use the product of two independent elements to mitigate side-channels.
+             */
+            BigInteger p = getField().getCharacteristic();
+            ECFieldElement fe1 = fromBigInteger(implRandomFieldElement(r, p));
+            ECFieldElement fe2 = fromBigInteger(implRandomFieldElement(r, p));
+            return fe1.multiply(fe2);
+        }
+
+        public ECFieldElement randomFieldElementMult(SecureRandom r)
+        {
+            /*
+             * NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we
+             * use the product of two independent elements to mitigate side-channels.
+             */
+            BigInteger p = getField().getCharacteristic();
+            ECFieldElement fe1 = fromBigInteger(implRandomFieldElementMult(r, p));
+            ECFieldElement fe2 = fromBigInteger(implRandomFieldElementMult(r, p));
+            return fe1.multiply(fe2);
+        }
+
         protected ECPoint decompressPoint(int yTilde, BigInteger X1)
         {
             ECFieldElement x = this.fromBigInteger(X1);
@@ -611,6 +640,28 @@ protected ECPoint decompressPoint(int yTilde, BigInteger X1)
 
             return this.createRawPoint(x, y, true);
         }
+
+        private static BigInteger implRandomFieldElement(SecureRandom r, BigInteger p)
+        {
+            BigInteger x;
+            do
+            {
+                x = BigIntegers.createRandomBigInteger(p.bitLength(), r);
+            }
+            while (x.compareTo(p) >= 0);
+            return x;
+        }
+
+        private static BigInteger implRandomFieldElementMult(SecureRandom r, BigInteger p)
+        {
+            BigInteger x;
+            do
+            {
+                x = BigIntegers.createRandomBigInteger(p.bitLength(), r);
+            }
+            while (x.signum() <= 0 || x.compareTo(p) >= 0);
+            return x;
+        }
     }
 
     /**
@@ -790,10 +841,6 @@ protected AbstractF2m(int m, int k1, int k2, int k3)
             super(buildField(m, k1, k2, k3));
         }
 
-        public boolean isValidFieldElement(BigInteger x)
-        {
-            return x != null && x.signum() >= 0 && x.bitLength() <= this.getFieldSize();
-        }
 
         public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
         {
@@ -840,6 +887,30 @@ public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
             return this.createRawPoint(X, Y, withCompression);
         }
 
+        public boolean isValidFieldElement(BigInteger x)
+        {
+            return x != null && x.signum() >= 0 && x.bitLength() <= this.getFieldSize();
+        }
+
+        public ECFieldElement randomFieldElement(SecureRandom r)
+        {
+            int m = getFieldSize();
+            return fromBigInteger(BigIntegers.createRandomBigInteger(m, r));
+        }
+
+        public ECFieldElement randomFieldElementMult(SecureRandom r)
+        {
+            /*
+             * NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we
+             * use the product of two independent elements to mitigate side-channels.
+             */
+            int m = getFieldSize();
+            ECFieldElement fe1 = fromBigInteger(implRandomFieldElementMult(r, m));
+            ECFieldElement fe2 = fromBigInteger(implRandomFieldElementMult(r, m));
+            return fe1.multiply(fe2);
+        }
+
+
         /**
          * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
          * 
@@ -956,6 +1027,17 @@ public boolean isKoblitz()
         {
             return this.order != null && this.cofactor != null && this.b.isOne() && (this.a.isZero() || this.a.isOne());
         }
+
+	private static BigInteger implRandomFieldElementMult(SecureRandom r, int m)
+        {
+            BigInteger x;
+            do
+            {
+                x = BigIntegers.createRandomBigInteger(m, r);
+            }
+            while (x.signum() <= 0);
+            return x;
+        }
     }
 
     /**
-- 
2.23.0

