org.bouncycastle.crypto.commitments.GeneralHashCommitter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcprov-ext-debug-jdk18on Show documentation
Show all versions of bcprov-ext-debug-jdk18on Show documentation
The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for Java 1.8 and later with debug enabled.
The newest version!
package org.bouncycastle.crypto.commitments;
import java.security.SecureRandom;
import org.bouncycastle.crypto.Commitment;
import org.bouncycastle.crypto.Committer;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.ExtendedDigest;
import org.bouncycastle.util.Arrays;
/**
* A basic hash-committer based on the one described in "Making Mix Nets Robust for Electronic Voting by Randomized Partial Checking",
* by Jakobsson, Juels, and Rivest (11th Usenix Security Symposium, 2002).
*
* The algorithm used by this class differs from the one given in that it includes the length of the message in the hash calculation.
*
*/
public class GeneralHashCommitter
implements Committer
{
private final Digest digest;
private final int byteLength;
private final SecureRandom random;
/**
* Base Constructor. The maximum message length that can be committed to is half the length of the internal
* block size for the digest (ExtendedDigest.getBlockLength()).
*
* @param digest digest to use for creating commitments.
* @param random source of randomness for generating secrets.
*/
public GeneralHashCommitter(ExtendedDigest digest, SecureRandom random)
{
this.digest = digest;
this.byteLength = digest.getByteLength();
this.random = random;
}
/**
* Generate a commitment for the passed in message.
*
* @param message the message to be committed to,
* @return a Commitment
*/
public Commitment commit(byte[] message)
{
if (message.length > byteLength / 2)
{
throw new DataLengthException("Message to be committed to too large for digest.");
}
byte[] w = new byte[byteLength - message.length];
random.nextBytes(w);
return new Commitment(w, calculateCommitment(w, message));
}
/**
* Return true if the passed in commitment represents a commitment to the passed in message.
*
* @param commitment a commitment previously generated.
* @param message the message that was expected to have been committed to.
* @return true if commitment matches message, false otherwise.
*/
public boolean isRevealed(Commitment commitment, byte[] message)
{
if (message.length + commitment.getSecret().length != byteLength)
{
throw new DataLengthException("Message and witness secret lengths do not match.");
}
byte[] calcCommitment = calculateCommitment(commitment.getSecret(), message);
return Arrays.constantTimeAreEqual(commitment.getCommitment(), calcCommitment);
}
private byte[] calculateCommitment(byte[] w, byte[] message)
{
byte[] commitment = new byte[digest.getDigestSize()];
digest.update(w, 0, w.length);
digest.update(message, 0, message.length);
digest.update((byte)((message.length >>> 8)));
digest.update((byte)(message.length));
digest.doFinal(commitment, 0);
return commitment;
}
}