109 lines
3.3 KiB
Java
109 lines
3.3 KiB
Java
/*
|
|
* Copyright (c) 2015 ezivkoc
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
/**
|
|
*
|
|
*/
|
|
package zutil.algo;
|
|
|
|
import java.math.BigInteger;
|
|
|
|
/**
|
|
* The algorithm solves the discreet log equation x^2 = n mod p
|
|
*
|
|
* @author Ziver
|
|
* @see http://en.wikipedia.org/wiki/Shanks-Tonelli_algorithm
|
|
*/
|
|
public class ShanksTonelliAlgo {
|
|
public static BigInteger calc(BigInteger n, BigInteger p){
|
|
|
|
BigInteger nOrg = n;
|
|
BigInteger S = null, V, R, U, X;
|
|
BigInteger ONE = BigInteger.ONE;
|
|
BigInteger TWO = BigInteger.valueOf( 2 );
|
|
BigInteger Q = p.add( ONE ).divide( TWO );
|
|
|
|
switch( p.mod( BigInteger.valueOf(4) ).intValue() ){
|
|
case 3:
|
|
S = n.pow( Q.divide( TWO ).intValue() ).mod( p );
|
|
break;
|
|
case 1:
|
|
S = ONE;
|
|
n = n.subtract( ONE );
|
|
while (n.divide( p ).compareTo( ONE ) == 0) {
|
|
S = S.add( ONE );
|
|
//n = (n-2s+1) mod p
|
|
n = n.subtract( TWO.multiply( S ) ).add( ONE ).mod( p );
|
|
if (n.compareTo( BigInteger.ZERO ) == 0){
|
|
return S;
|
|
}
|
|
}
|
|
Q = Q.divide( TWO );
|
|
V = ONE;
|
|
R = S;
|
|
U = ONE;
|
|
while (Q.compareTo( BigInteger.ZERO ) > 0) {
|
|
X = R.pow(2).subtract( n.multiply( U.pow(2) ) ).mod( p );
|
|
U = TWO.multiply( R ).multiply( U ).mod( p );
|
|
R = X;
|
|
if ( Q.testBit(0) ){
|
|
X = S.multiply( R ).subtract( n.multiply(V).multiply(U) ).mod( p );
|
|
V = V.multiply(R).add( S.multiply(U) ).mod( p );
|
|
S = X;
|
|
}
|
|
Q = Q.divide( TWO );
|
|
}
|
|
}
|
|
|
|
if( S != null && S.multiply( S ).mod( p ).compareTo( nOrg ) != 0 ){
|
|
return null;
|
|
}
|
|
|
|
return S;
|
|
/*
|
|
|
|
//p-1 = Q*2^S
|
|
BigInteger S = null, Q = null, R = null, V = null, W = null;
|
|
|
|
//Q = ( 2^S )/( 1-p );
|
|
p-1 = ( 2^S )/( 1-p ) * 2^S;
|
|
|
|
// R = n^( (Q+1)/2 ) mod p
|
|
R = n.pow( Q.add(BigInteger.ONE).divide(BigInteger.valueOf(2)).intValue() ).mod( p );
|
|
// V = W^Q mod p
|
|
V = W.pow( Q.intValue() ).mod( p );
|
|
|
|
for(int i=S.intValue(); true ;){
|
|
while( true ){
|
|
i--;
|
|
// 1 = ( ( R^2 * n^-1 )^2^i ) mod p
|
|
if( ( R.pow(2).multiply( n.pow(-1) ) ).pow( (int)Math.pow(2, i) ).mod( p ).compareTo( BigInteger.ONE ) == 0 )
|
|
break;
|
|
}
|
|
|
|
if(i == 0) return R;
|
|
//R = ( RV^(2^(S-i-1)) ) mod p
|
|
else R = ( R.multiply( V.pow( (int)Math.pow( 2, S.intValue()-i-1) ) )).mod( p );
|
|
}
|
|
*/
|
|
}
|
|
}
|