summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2022-12-05 15:20:20 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2022-12-05 15:20:20 +0700
commit3dacc4fc708eeed68f9d714d76e1cbc02a6341a9 (patch)
tree6c67917ad3b88f3f2170b1a143432231e44032ea /crypto/src
parentRefactoring in SP80038G (diff)
downloadBouncyCastle.NET-ed25519-3dacc4fc708eeed68f9d714d76e1cbc02a6341a9.tar.xz
Fix rounding issue with FF1
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/crypto/fpe/SP80038G.cs37
1 files changed, 24 insertions, 13 deletions
diff --git a/crypto/src/crypto/fpe/SP80038G.cs b/crypto/src/crypto/fpe/SP80038G.cs
index 431fb119d..65dad0797 100644
--- a/crypto/src/crypto/fpe/SP80038G.cs
+++ b/crypto/src/crypto/fpe/SP80038G.cs
@@ -60,8 +60,8 @@ namespace Org.BouncyCastle.Crypto.Fpe
         private static ushort[] DecFF1(IBlockCipher cipher, int radix, byte[] T, int n, int u, int v, ushort[] A, ushort[] B)
         {
             int t = T.Length;
-            int b = ((int)Ceil(System.Math.Log((double)radix) * (double)v / LOG2) + 7) / 8;
-            int d = (((b + 3) / 4) * 4) + 4;
+            int b = CalculateB_FF1(radix, v);
+            int d = (b + 7) & ~3;
 
             byte[] P = CalculateP_FF1(radix, (byte)u, n, t);
 
@@ -161,8 +161,8 @@ namespace Org.BouncyCastle.Crypto.Fpe
         {
             int t = T.Length;
 
-            int b = ((int)Ceil(System.Math.Log((double)radix) * (double)v / LOG2) + 7) / 8;
-            int d = (((b + 3) / 4) * 4) + 4;
+            int b = CalculateB_FF1(radix, v);
+            int d = (b + 7) & ~3;
 
             byte[] P = CalculateP_FF1(radix, (byte)u, n, t);
 
@@ -237,6 +237,26 @@ namespace Org.BouncyCastle.Crypto.Fpe
             return EncryptFF3(cipher, radix, tweak64, buf, off, len);
         }
 
+        private static int CalculateB_FF1(int radix, int v)
+        {
+            //return (BigInteger.ValueOf(radix).Pow(v).Subtract(BigInteger.One).BitLength + 7) / 8;
+
+            int powersOfTwo = Integers.NumberOfTrailingZeros(radix);
+            int bits = powersOfTwo * v;
+
+            int oddPart = radix >> powersOfTwo;
+            if (oddPart != 1)
+            {
+                // Old version with rounding issues, especially for power of 2 radix, but maybe others.
+                //bits += (int)System.Math.Ceiling(System.Math.Log((double)oddPart) * (double)v / LOG2);
+
+                // Exact calculation, with possible performance issues if v is too large.
+                bits += BigInteger.ValueOf(oddPart).Pow(v).BitLength;
+            }
+
+            return (bits + 7) / 8;
+        }
+
         private static BigInteger[] CalculateModUV(BigInteger bigRadix, int u, int v)
         {
             BigInteger[] modUV = new BigInteger[2];
@@ -612,14 +632,5 @@ namespace Org.BouncyCastle.Crypto.Fpe
 
             return s;
         }
-
-	    private static int Ceil(double v)
-	    {
-		    int rv = (int)v;
-		    if ((double)rv < v)
-			    return rv + 1;
-
-            return rv;
-	    }
     }
 }