The General Merkle signature scheme (GMSS) applies a binary tree to provide a signature which is signed by a private key and authenticated with a public key:
Generalized Merkle Signature Scheme (GMSS) |
Code
The following provides an outline of the code, where we sign "Hello" with the private key and verify with the public key:
package gmss; import java.math.BigInteger; import java.security.SecureRandom; import java.security.Signer; import org.bouncycastle.pqc.crypto.gmss.GMSSKeyPairGenerator; import org.bouncycastle.pqc.crypto.gmss.GMSSParameters; import org.bouncycastle.pqc.crypto.gmss.GMSSPrivateKeyParameters; import org.bouncycastle.pqc.crypto.gmss.GMSSPublicKeyParameters; import org.bouncycastle.pqc.crypto.gmss.GMSSSigner; import org.bouncycastle.util.BigIntegers; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA224Digest; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.pqc.crypto.DigestingMessageSigner; import org.bouncycastle.pqc.crypto.gmss.GMSSDigestProvider; import org.bouncycastle.pqc.crypto.gmss.GMSSKeyGenerationParameters; public class gmss { public static void main(String args[]){ SecureRandom keyRandom = new SecureRandom(); GMSSParameters params = new GMSSParameters(3); // new int[]{10, 3, 10}, new int[]{5, 5, 4}, new int[]{3, 3, 2}); GMSSDigestProvider digProvider = new GMSSDigestProvider() { public Digest get() { return new SHA224Digest(); } }; GMSSKeyPairGenerator gmssKeyGen = new GMSSKeyPairGenerator(digProvider); GMSSKeyGenerationParameters genParam = new GMSSKeyGenerationParameters(keyRandom, params); gmssKeyGen.init(genParam); AsymmetricCipherKeyPair pair = gmssKeyGen.generateKeyPair(); ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), keyRandom); DigestingMessageSigner gmssSigner = new DigestingMessageSigner(new GMSSSigner(digProvider), new SHA224Digest()); gmssSigner.init(true, param); String ex="hello"; if (args.length>1) ex = args[0]; byte[] message = ex.getBytes(); gmssSigner.update(message, 0, message.length); byte[] sig = gmssSigner.generateSignature(); gmssSigner.init(false, pair.getPublic()); gmssSigner.update(message, 0, message.length); System.out.println("Message:"+ex); GMSSPrivateKeyParameters priv = (GMSSPrivateKeyParameters) pair.getPrivate(); GMSSPublicKeyParameters pub = (GMSSPublicKeyParameters) pair.getPublic(); System.out.println("Public key:"+getHexString(pub.getPublicKey())); String sig_hex=getHexString(sig); String sig_out = sig_hex.substring(0, Math.min(sig_hex.length(), 20)); System.out.println("Signature Length (hex chars):"+sig_hex.length()); System.out.println("Signature Length (first 10 hex char):"+sig_out); if (!gmssSigner.verifySignature(sig)) { System.out.println("Failure"); } else { System.out.println("It Works!"); } } public static String getHexString(byte[] b) { String result = ""; for (int i=0; i < b.length; i++) { result += Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 ); } return result; } }