From: Falk Köppe on
Hello Thomas,

sorry, that my answer is late, but I had too much to do the last two
days. First I want to thank you again for your effort to help me to
better understand modular integer arithmetic. Specially your
literature paved the way for my better understanding.

> You may want to use mod() instead of remainder(): mod() will return
> a more appropriate result for a negative source value. For positive
> integers, remainder() and mod() return the same value (but 'mod' is
> shorter, thus easier to type than 'remainder').

I changed the function accordingly.

> Not necessarily. In the protocols described by Dwork and Naor, the
> prime p may be fixed; actually, it should be fixed, once and for all,
> and everybody should use that p. You then are free to select a p
> which is convenient, i.e. equal to 3 modulo 4.

I decided to go this way and use a prime modulus p congruent to 3 mod
4. This is implemented with the following function, which returns a
random prime with numBits number of bits and the characteristic of
beeing congruent to 3 mod 4. I can't decide yet, if the prime p should
be fixed or not, because I want to regulate the difficulty or time it
takes to find a square root.

private BigInteger findConvenientPrime(int numBits) {
boolean foundConvenientPrime = false;
Random random = new SecureRandom();
BigInteger result = null;

while (!foundConvenientPrime) {
result = BigInteger.probablePrime(numBits, random);

if (isCongruent(result, BigInteger.valueOf(3),
BigInteger.valueOf(4)) {
foundConvenientPrime = true;
}
}

return result;
}

> The Dwork-Naor article describes b as being computed with a hash
> function on a some data which includes the source message, the sending
> date and the destination address. The point is to make it impossible for
> the sender to reuse the same b for several messages (the pricing
> function makes sense only if the sender must 'pay' the price for each
> sent message).

I create a random BigInteger value b, with 0 <= b < p. This would be
my equivalent to the proposed hash function. Because I can't accept
values b that don't have a square root, the following algorithm
increments b by one until a value b is found that has a square root.

// finds the square root of the first integer starting with b
// that has a square root
public BigInteger findSquareRoot(BigInteger b, BigInteger p) {
BigInteger squareRoot = null;

if (p.compareTo(BigInteger.valueOf(2) == 0) {
squareRoot = b;
}
else {
boolean foundSquareRoot = false;

while (!foundSquare) {
squareRoot = b.modpow(p.add(BigInteger.ONE)
.divide(BigInteger.valueOf(4)), p)

if (isCongruent(squareRoot.multiply(squareRoot), b, p) {
foundSquareRoot = true;
} else {
b = b.add(BigInteger.ONE);
}
}
}

return squareRoot;
}

So if someone is unlucky, than she gets a value b that does not have a
square root and needs to try as long as she finds a square root. The
reason I need a square root is, that if I would accept null values,
then I can't be sure she really calculated the challenge, instead of
just returning null. To check, if she said the truth I would have to
calculate the square root myself, which defeats the purpose of the
pricing function. I'm not interested in the actual square root, but in
the fact, that she really calculated it.

I will now try to regulate the number of bits of prime p and the
number of bits of value b to figure out how it effects the time it
takes to find a square root with the given algorithm.

Greetings,
Falk Köppe
From: Lew on
Falk Köppe wrote:
> private BigInteger findConvenientPrime(int numBits) {
>     boolean foundConvenientPrime = false;
>     Random random = new SecureRandom();
>     BigInteger result = null;
>
>     while (!foundConvenientPrime) {
>         result = BigInteger.probablePrime(numBits, random);
>
>         if (isCongruent(result, BigInteger.valueOf(3),
> BigInteger.valueOf(4)) {
>             foundConvenientPrime = true;
>         }
>     }
>
>     return result;
>

Alternative idioms
1)
private BigInteger findConvenientPrime(int numBits) {
Random random = new SecureRandom();

BigInteger result;
boolean found;
do {
result = BigInteger.probablePrime( numBits, random );

found = isCongruent( result, BigInteger.valueOf(3),
BigInteger.valueOf(4) );
} while ( ! found );
return result;
}

2)
private BigInteger findConvenientPrime(int numBits) {
Random random = new SecureRandom();

BigInteger result;
for ( boolean found = false; ! found;
found = isCongruent( result, BigInteger.valueOf(3),
BigInteger.valueOf(4) )
) {
result = BigInteger.probablePrime( numBits, random );
}
return result;
}

3)
private BigInteger findConvenientPrime(int numBits) {
Random random = new SecureRandom();

while ( true ) {
final BigInteger result = BigInteger.probablePrime( numBits,
random );

if ( isCongruent( result, BigInteger.valueOf(3),
BigInteger.valueOf(4) ) {
return result;
}
}
}

This code hasn't been compiled, much less tested, so it might contain
typos.

--
Lew
From: Falk Köppe on
Hello Lew,

thanks for your improvement. I really liked your first implementation
and changed my function accordingly.

> 1)
>  private BigInteger findConvenientPrime(int numBits) {
>    Random random = new SecureRandom();
>
>    BigInteger result;
>    boolean found;
>    do {
>      result = BigInteger.probablePrime( numBits, random );
>
>      found = isCongruent( result, BigInteger.valueOf(3),
> BigInteger.valueOf(4) );
>    } while ( ! found );
>
>    return result;
>  }

Greetings,
Falk Köppe
From: Lew on
Falk Köppe wrote:
> thanks for your improvement. I really liked your first implementation
> and changed my function accordingly.
>
>> 1)
>> private BigInteger findConvenientPrime(int numBits) {
>> Random random = new SecureRandom();
>>
>> BigInteger result;
>> boolean found;
>> do {
>> result = BigInteger.probablePrime( numBits, random );
>>
>> found = isCongruent( result, BigInteger.valueOf(3),
>> BigInteger.valueOf(4) );
>> } while ( ! found );
>>
>> return result;
>> }

Each has something to recommend it. #1 is probably the easiest to read. #2
limits the scope of 'found' to the loop, a good thing since 'found' is the
most temporary of the variables. #3 (which could have used 'for(;;)' instead
of 'while(true)') eliminates 'found' altogether, limits the scope of 'result'
to the loop, and makes the 'result' variable 'final'.

--
Lew
From: Thomas Pornin on
According to Falk K�ppe <falk.koeppe(a)googlemail.com>:
> I create a random BigInteger value b, with 0 <= b < p. This would be
> my equivalent to the proposed hash function. Because I can't accept
> values b that don't have a square root, the following algorithm
> increments b by one until a value b is found that has a square root.

You have several other ways.

I assume that your protocol is some kind of interactive protocol where
one party dynamically issues the challenge, and the other party returns
the square root. You want the first party (let's call it A) to use much
less CPU than the second party (B).

1. Party A creates a random integer a modulo p (0 < a < p), computes
b = a^2 mod p (in Java, b = a.multiply(a).mod(p)). b is the challenge.
Party B must then respond with c, a square root of b modulo p. Party
A verifies that either c = a, or c = p-a.

2. Party A creates a random integer b modulo p (0 < b < p). b is the
challenge. If b is a square, -b is not, and vice versa. Party B
computes c which is a square root of b or -b. Party A verifies that
the c^2 mod p is equal to either b or p-b.

Either of those protocols makes things substantially easier to
implement. Only the second protocol is amenable to non-interactive use,
i.e. replacing party A with a hash function.


> I will now try to regulate the number of bits of prime p and the
> number of bits of value b to figure out how it effects the time it
> takes to find a square root with the given algorithm.

Note that BigInteger, while being quite fine in many ways, is not the
fastest implementation of modular arithmetics that you may find. For
modular square root extraction, native code libraries such as gmp will
crunch numbers about ten times faster on a recent PC (in 64-bit mode).


--Thomas Pornin