diff options
author | David Hook <dgh@cryptoworkshop.com> | 2013-05-31 11:07:45 +0400 |
---|---|---|
committer | David Hook <dgh@cryptoworkshop.com> | 2013-05-31 11:07:45 +0400 |
commit | 2b976f5364cfdbc37d3086019d93483c983eb80b (patch) | |
tree | cb846af3fd1d43f9c2562a1fb2d06b997ad8f229 /core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowSigner.java | |
parent | 5f714bd92fbd780d22406f4bc3681be005f6f04a (diff) |
initial reshuffle
Diffstat (limited to 'core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowSigner.java')
-rw-r--r-- | core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowSigner.java | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowSigner.java new file mode 100644 index 00000000..b6014a54 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowSigner.java @@ -0,0 +1,301 @@ +package org.bouncycastle.pqc.crypto.rainbow; + +import java.security.SecureRandom; + +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.pqc.crypto.MessageSigner; +import org.bouncycastle.pqc.crypto.rainbow.util.ComputeInField; +import org.bouncycastle.pqc.crypto.rainbow.util.GF2Field; + +/** + * It implements the sign and verify functions for the Rainbow Signature Scheme. + * Here the message, which has to be signed, is updated. The use of + * different hash functions is possible. + * <p/> + * Detailed information about the signature and the verify-method is to be found + * in the paper of Jintai Ding, Dieter Schmidt: Rainbow, a New Multivariable + * Polynomial Signature Scheme. ACNS 2005: 164-175 + * (http://dx.doi.org/10.1007/11496137_12) + */ +public class RainbowSigner + implements MessageSigner +{ + // Source of randomness + private SecureRandom random; + + // The length of a document that can be signed with the privKey + int signableDocumentLength; + + // Container for the oil and vinegar variables of all the layers + private short[] x; + + private ComputeInField cf = new ComputeInField(); + + RainbowKeyParameters key; + + public void init(boolean forSigning, + CipherParameters param) + { + if (forSigning) + { + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + this.random = rParam.getRandom(); + this.key = (RainbowPrivateKeyParameters)rParam.getParameters(); + + } + else + { + + this.random = new SecureRandom(); + this.key = (RainbowPrivateKeyParameters)param; + } + } + else + { + this.key = (RainbowPublicKeyParameters)param; + } + + this.signableDocumentLength = this.key.getDocLength(); + } + + + /** + * initial operations before solving the Linear equation system. + * + * @param layer the current layer for which a LES is to be solved. + * @param msg the message that should be signed. + * @return Y_ the modified document needed for solving LES, (Y_ = + * A1^{-1}*(Y-b1)) linear map L1 = A1 x + b1. + */ + private short[] initSign(Layer[] layer, short[] msg) + { + + /* preparation: Modifies the document with the inverse of L1 */ + // tmp = Y - b1: + short[] tmpVec = new short[msg.length]; + + tmpVec = cf.addVect(((RainbowPrivateKeyParameters)this.key).getB1(), msg); + + // Y_ = A1^{-1} * (Y - b1) : + short[] Y_ = cf.multiplyMatrix(((RainbowPrivateKeyParameters)this.key).getInvA1(), tmpVec); + + /* generates the vinegar vars of the first layer at random */ + for (int i = 0; i < layer[0].getVi(); i++) + { + x[i] = (short)random.nextInt(); + x[i] = (short)(x[i] & GF2Field.MASK); + } + + return Y_; + } + + /** + * This function signs the message that has been updated, making use of the + * private key. + * <p/> + * For computing the signature, L1 and L2 are needed, as well as LES should + * be solved for each layer in order to find the Oil-variables in the layer. + * <p/> + * The Vinegar-variables of the first layer are random generated. + * + * @param message the message + * @return the signature of the message. + */ + public byte[] generateSignature(byte[] message) + { + Layer[] layer = ((RainbowPrivateKeyParameters)this.key).getLayers(); + int numberOfLayers = layer.length; + + x = new short[((RainbowPrivateKeyParameters)this.key).getInvA2().length]; // all variables + + short[] Y_; // modified document + short[] y_i; // part of Y_ each polynomial + int counter; // index of the current part of the doc + + short[] solVec; // the solution of LES pro layer + short[] tmpVec; + + // the signature as an array of shorts: + short[] signature; + // the signature as a byte-array: + byte[] S = new byte[layer[numberOfLayers - 1].getViNext()]; + + short[] msgHashVals = makeMessageRepresentative(message); + + // shows if an exception is caught + boolean ok; + do + { + ok = true; + counter = 0; + try + { + Y_ = initSign(layer, msgHashVals); + + for (int i = 0; i < numberOfLayers; i++) + { + + y_i = new short[layer[i].getOi()]; + solVec = new short[layer[i].getOi()]; // solution of LES + + /* copy oi elements of Y_ into y_i */ + for (int k = 0; k < layer[i].getOi(); k++) + { + y_i[k] = Y_[counter]; + counter++; // current index of Y_ + } + + /* + * plug in the vars of the previous layer in order to get + * the vars of the current layer + */ + solVec = cf.solveEquation(layer[i].plugInVinegars(x), y_i); + + if (solVec == null) + { // LES is not solveable + throw new Exception("LES is not solveable!"); + } + + /* copy the new vars into the x-array */ + for (int j = 0; j < solVec.length; j++) + { + x[layer[i].getVi() + j] = solVec[j]; + } + } + + /* apply the inverse of L2: (signature = A2^{-1}*(b2+x)) */ + tmpVec = cf.addVect(((RainbowPrivateKeyParameters)this.key).getB2(), x); + signature = cf.multiplyMatrix(((RainbowPrivateKeyParameters)this.key).getInvA2(), tmpVec); + + /* cast signature from short[] to byte[] */ + for (int i = 0; i < S.length; i++) + { + S[i] = ((byte)signature[i]); + } + } + catch (Exception se) + { + // if one of the LESs was not solveable - sign again + ok = false; + } + } + while (!ok); + /* return the signature in bytes */ + return S; + } + + /** + * This function verifies the signature of the message that has been + * updated, with the aid of the public key. + * + * @param message the message + * @param signature the signature of the message + * @return true if the signature has been verified, false otherwise. + */ + public boolean verifySignature(byte[] message, byte[] signature) + { + short[] sigInt = new short[signature.length]; + short tmp; + + for (int i = 0; i < signature.length; i++) + { + tmp = (short)signature[i]; + tmp &= (short)0xff; + sigInt[i] = tmp; + } + + short[] msgHashVal = makeMessageRepresentative(message); + + // verify + short[] verificationResult = verifySignatureIntern(sigInt); + + // compare + boolean verified = true; + if (msgHashVal.length != verificationResult.length) + { + return false; + } + for (int i = 0; i < msgHashVal.length; i++) + { + verified = verified && msgHashVal[i] == verificationResult[i]; + } + + return verified; + } + + /** + * Signature verification using public key + * + * @param signature vector of dimension n + * @return document hash of length n - v1 + */ + private short[] verifySignatureIntern(short[] signature) + { + + short[][] coeff_quadratic = ((RainbowPublicKeyParameters)this.key).getCoeffQuadratic(); + short[][] coeff_singular = ((RainbowPublicKeyParameters)this.key).getCoeffSingular(); + short[] coeff_scalar = ((RainbowPublicKeyParameters)this.key).getCoeffScalar(); + + short[] rslt = new short[coeff_quadratic.length];// n - v1 + int n = coeff_singular[0].length; + int offset = 0; // array position + short tmp = 0; // for scalar + + for (int p = 0; p < coeff_quadratic.length; p++) + { // no of polynomials + offset = 0; + for (int x = 0; x < n; x++) + { + // calculate quadratic terms + for (int y = x; y < n; y++) + { + tmp = GF2Field.multElem(coeff_quadratic[p][offset], + GF2Field.multElem(signature[x], signature[y])); + rslt[p] = GF2Field.addElem(rslt[p], tmp); + offset++; + } + // calculate singular terms + tmp = GF2Field.multElem(coeff_singular[p][x], signature[x]); + rslt[p] = GF2Field.addElem(rslt[p], tmp); + } + // add scalar + rslt[p] = GF2Field.addElem(rslt[p], coeff_scalar[p]); + } + + return rslt; + } + + /** + * This function creates the representative of the message which gets signed + * or verified. + * + * @param message the message + * @return message representative + */ + private short[] makeMessageRepresentative(byte[] message) + { + // the message representative + short[] output = new short[this.signableDocumentLength]; + + int h = 0; + int i = 0; + do + { + if (i >= message.length) + { + break; + } + output[i] = (short)message[h]; + output[i] &= (short)0xff; + h++; + i++; + } + while (i < output.length); + + return output; + } +} |