package org.bouncycastle.pqc.jcajce.provider.test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import junit.framework.TestCase;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.pqc.jcajce.interfaces.PicnicKey;
import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
import org.bouncycastle.pqc.jcajce.spec.PicnicParameterSpec;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Pack;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;

public class PicnicTest
    extends TestCase
{
    byte[] msg = Strings.toByteArray("Hello World!");

    public void testPicnic3l1KAT()
        throws Exception
    {
        byte[] msg = Hex.decode("49755A7B1A7CDC5C9BDF5149968061D3C95EE67BFBAF02750C45094303A9D9CD23A08F19B9C768ADC63FFD1527186D09CA4E0356BB882E263BF015CBE3716C05B31A69DDDB790BA82C341AC9B6BE68A81B8BEF8D882304BAF0020D761A0DB04412033DC369961A5213B04E81736A580F1162780599CC029E262D67F31B2773AFB457A1ADAAA292163144F17DE384234F3303111FCD89BCB30333C6C6486F775ED099043C34E6C86450B650F1A02D03781B1D20691B767D166DADF1DCC4D8604D976EFDC9168373A7316DDA9B9FB02A4A321218D9F54E287B7167A08BC0153843BD6355AEA1310824DD5D5EC458BE694AF176119D9E588A29C650FF5500293659EA478B39A62149F819CDB7E7CB32E1D7B1284F159E2AB1B1EA41AF4D0AC94FF3111FC1CCD818F9B2CC7A259701405FDF6A51D2D3EF62789297BD16A659F14968EF902C4A23DA409BF13A4913467B5C991854B2CA6CC006D3F4197A6AA58BD5DD95C36928DA9583332C3FB134FA3890FE7E299F1C17205366C4F4230724C43E4803912E72B816658BBB1B63780865A1F66A2A49B96E93711B1BE97B827D12173402828B1A065B94310D5BD6098D");
        byte[] pk = Hex.decode("07E819482D67087A26A6C27FCF56F5F53D00DE9DBAE947BE3B65B9A827C65B99260C00");
        byte[] sk = Hex.decode("0735B153A7706109D4A13D7C4B26AA5B5680E819482D67087A26A6C27FCF56F5F53D00DE9DBAE947BE3B65B9A827C65B99260C00");
        byte[] sm = Hex.decode("[encoded data, 26260 characters]");
        byte[] seed = Hex.decode("4FDA9FB6929E3F391901D69FA0AA2F25A9657D249A620F1B9E305A5965676BA76794CAD3355EB632579C3958CA7D443D");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");
        SecureRandom random = new NISTSecureRandom(seed, null);

        kpg.initialize(PicnicParameterSpec.picnic3l1, random);

        KeyPair kp = kpg.generateKeyPair();

        SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(pubInfo.getPublicKeyData().getOctets()).getOctets(), pk));

        PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(privInfo.getPrivateKey().getOctets()).getOctets(), sk));

        Signature sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initSign(kp.getPrivate(), random);

        sig.update(msg, 0, msg.length);

        byte[] genS = sig.sign();

        assertTrue(Arrays.areEqual(Arrays.concatenate(Pack.intToLittleEndian(genS.length), msg, genS), sm));

        sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));
    }

    public void testPicnic3l3KAT()
            throws Exception
    {
        byte[] msg = Hex.decode("209658CD1D801079FFE8E950BAFD70A028CFCC35B9FB00D232C5603A1D51BA13E5DE59E0277962C4474E9F3F60FCD99C9B79665B3839D5C037B921A4DE8E144FA1D38182FBDEECDA6934E814D9186591F01C5E23349B34F4439B4D402C4072CB4D702966AB473D2C39443F41FBDD0C48E566D33E076422EE72FB47B2FFD661F367E9EFDDC988BCA02382EF93590D4FE3ECE8B1D9D8B3A653219C7D131B43E2FDE2851541F467C31129E6F9B9D124221CD52610B9F138EAC1D01F193148FA0415B29F5C86D15067EB1E26C9D51F05655E8545F734F8F244854AD76C6B04C230898BEA33EFDCEEF100D79F8E3B894BA583466749B82007067806E3A7B3BA954F6FC5ABFF0E099A24D14D865F6F4538736124ACC5EAD4169DDF2144AD558DA3C74CDABEC147D2AFA113EDFD1E2280766B18792310FB6B4FE5D0D9F65906B1CC43655BB3D6178EF9093AC9C8F1A91BF49008179394EEE79E1D8E3228F567770C1BA1E30BA4BCE2465AB68F53CE21C0D8AB2F6E535828F211D4DB957DC3AF8B7E00DABD8F1F74C959B2AFF45121C5B5ABD3136C6F55D5F5FFDBCEBC3CD7A430FF3813D23BCDC1254FE6949DA4E7694028B7FCB876099E91B92C65D85C39D4BE9325AFE81703E5B18CBD7BD9EB59A9BB9408ABD966ADE9A60303807AD1B2C14C04CDF8FAE6950A55B21C9EBB5E94713BF8C2890215C5DA94B59CB31EDC671093B15FF5014DB4CD3EA8060260DC1612E9FD6E5AB40F0656121F689C8E94212269A7B24305C83BF0583418755CE690913CB081F2893FB42BC4750F2C053C48C1552430793CDDE1A49AC9E21913210D727C4BEB5640AB9B7505EA4E59AF417A085394181784BF1BB0BC32BD71CC57CE77541581F14B8BA4B758500694796262B561A38C72893C77B548D779A3833EEB064CDDBA5471CBFFBC769E139946155BF376A56415AB743DE568CD21895ED6951B5BFE1B1629DD6510DCD4483F206954964E0517546DD96900A2540A51835818D1730B0C9123E7FD8B28E6843BFFB659945A273CEA944FF6E83C234B3E43DB4630614E0B67778EA760EE341FE68C525E90475A1560821AE6B2A85015292C36EAA2E041AC04FB55922C48204525187C7E0476A9FED04EFBBA96F369D8AE709506620127FD399613A9796C4FF96D7E");
        byte[] pk = Hex.decode("08373DBD3DA8E4B3E5E72EDC51D0CC3997110FE825D9787BD36E3210335AEF4B760E5A4CC0EB4763A8D8E6A6172D4221FE");
        byte[] sk = Hex.decode("08A6B534767A6D839FD19075AE0BA10147C46862BF7BBCBE83373DBD3DA8E4B3E5E72EDC51D0CC3997110FE825D9787BD36E3210335AEF4B760E5A4CC0EB4763A8D8E6A6172D4221FE");
        byte[] sm = Hex.decode("[encoded data, 57066 characters]");
        byte[] seed = Hex.decode("A08AD391E0FC57A83B74CA8CF44DB67F8178262ED9B20AA0163CDD8274AC2BE05F558B112B094244370C1AAAB75077E6");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");
        SecureRandom random = new NISTSecureRandom(seed, null);

        kpg.initialize(PicnicParameterSpec.picnic3l3, random);

        KeyPair kp = kpg.generateKeyPair();

        SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(pubInfo.getPublicKeyData().getOctets()).getOctets(), pk));

        PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(privInfo.getPrivateKey().getOctets()).getOctets(), sk));

        Signature sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initSign(kp.getPrivate(), random);

        sig.update(msg, 0, msg.length);

        byte[] genS = sig.sign();

        assertTrue(Arrays.areEqual(Arrays.concatenate(Pack.intToLittleEndian(genS.length), msg, genS), sm));

        sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));
    }

    public void testPicnic3l5KAT()
            throws Exception
    {
        byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8");
        byte[] pk = Hex.decode("09CFA88EDF68419EBAE02E3FF73F34AFF0BAAC560E48D4399C85F5CDAF5A7C54DE8626ED79D451140800E03B59B956F8210E556067407D13DC90FA9E8B872BFB8E");
        byte[] sk = Hex.decode("097C9935A0B07694AA0C6D10E4DB6B1ADD2FD81A25CCB148032DCD739936737F2CCFA88EDF68419EBAE02E3FF73F34AFF0BAAC560E48D4399C85F5CDAF5A7C54DE8626ED79D451140800E03B59B956F8210E556067407D13DC90FA9E8B872BFB8E");
        byte[] seed = Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");
        SecureRandom random = new NISTSecureRandom(seed, null);

        kpg.initialize(PicnicParameterSpec.picnic3l5, random);

        KeyPair kp = kpg.generateKeyPair();

        SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(pubInfo.getPublicKeyData().getOctets()).getOctets(), pk));

        PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(privInfo.getPrivateKey().getOctets()).getOctets(), sk));

        Signature sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initSign(kp.getPrivate(), random);

        sig.update(msg, 0, msg.length);

        byte[] genS = sig.sign();

//        assertTrue(Arrays.areEqual(Arrays.concatenate(Pack.intToLittleEndian(genS.length), msg, genS), sm));

        sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));
    }

    public void testPicnicl1fsKAT()
            throws Exception
    {
        byte[] msg = Hex.decode("[encoded data, 4356 characters]");
        byte[] pk = Hex.decode("01C1A253F3C206AA0C525F05EF3E03BC549BF63AF7FD6B21959A3266F6A4A4CAAE");
        byte[] sk = Hex.decode("015BA8AD9B66C93CDE7E7E616A97FED8AAC1A253F3C206AA0C525F05EF3E03BC549BF63AF7FD6B21959A3266F6A4A4CAAE");
//        byte[] sm = Hex.decode("[encoded data, 69868 characters]");
        byte[] seed = Hex.decode("238461A224ABEECCF709AB6CACF4EDD372D45E5F4274095273A49AFE614F2BF713134ABF68B4DD058E6D7B612C3658C3");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");
        SecureRandom random = new NISTSecureRandom(seed, null);

        kpg.initialize(PicnicParameterSpec.picnicl1fs, random);

        KeyPair kp = kpg.generateKeyPair();

        SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(pubInfo.getPublicKeyData().getOctets()).getOctets(), pk));

        PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(privInfo.getPrivateKey().getOctets()).getOctets(), sk));

        Signature sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initSign(kp.getPrivate(), random);

        sig.update(msg, 0, msg.length);

        byte[] genS = sig.sign();

//        assertTrue(Arrays.areEqual(Arrays.concatenate(Pack.intToLittleEndian(genS.length), msg, genS), sm));

        sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));
    }


    public void testPicnicl1fullKAT()
            throws Exception
    {
        byte[] msg = Hex.decode("AF2860129C08A1A9C7A7BB3120B3E40AFA1A4A09050C8483E7511FABF3285544D4CE3F41401DAB8C17DA547F6777A72519F6EEAAC83016FA0E0FB0B33329DD02AB8EB1F291758074EBB5B7C4C102B75BA422821E6755B37B914D689D84808A89CF88F69A446F489A260BA03CA52A4AA14E8BCF4BFE5134DD2918A88D67329B9BADC6ADA4A3071FD21CFC45235FA0A1B82D91C5877F10AE087464251C8899732AA7FC8F6C0A5BEAF4FA41E64CA97932925A06E218272500249577705804C6DD9F0F61DEE6AAE096BE0AE5E67923137933FE4D61E9A88DFD5B3BD75AEEAF5018A5153985E2837AD1AAD5EED91620D935EB9982DD2364B5413F490BF251FC783503FA146300E6ADAE0682E0597C3839C645DBE855919BB1CB80C3DC6E233909017BB31F5ADAEE05CE442EEF594FC15FEC3A2B4B81ECAAD1340B0677F27009290AB3AB8788556389047F63C2CE9390658E151CA85BAAE45ED2FE12B6667967F6B772EE683AC2E7347C7B0EFA332B3354B5043CB86200F8E4249F68030844D00A86FAA7B79A4129AD676D1E9D58828A1AF4C6BD68C29CC23002E0A0313500BA717B8756D4A18E41E381DF8D7A999A153876DB876CA4A508486A4F331CAC9CB3E7C416C6329713CAB76E1C8B63A8CAD46F8EB1E65116F89A3B4EB8FAA14A73097CA71AEA3220BE7FB7FE64919893930445D962C309E23332E4B3ED8CA768EF0ED46EAAB199827AD628A1BC20CCD9F61BEF67F7FCB017300EBC7493A7CCDAEDBFCA5F91E80B80DECBFD9EAD9BF22FE16B563512C7383D34801C504202D7A0E19821EC8495016362EDAC165904D2BBAC484DE1D4112C3A3E6EA56A78785B7CAF2A44B5BC8BECBC50BF4B521C1D086086FEB009C06ACB8FA0F53E7654FB02AD7898E35E5F3A7DCFC50124BA1F30178C707F4D36E4E7758C4CF82747753CC30A836311794A6A9017F53ABD17A1C9647AB38BA56AAC83C1812DEE8A5A75C5CC958780A3E9C3C1F39729BD365948F7FCD8104CF09660060FBAD2BE9B8D8E5BDD22286EB0BFD4010681AE7928D0FC008E21C8F877D97B5B9C7A06C02530FBC6A9D6FCEDFEDF68A9682177757CDDDFFA6CB9086B8330E61851E2761D84DA37635EA8441E3B23FD165CCEA562B0A3616B30EE5FAE00F76D6801B22F2215D80829E01DB2C0743E3074CF26C96B0EDDF97D79FB9C7FFE9B5CDB891F9E61FEFE7E1CBD28FE25B7858921C8C99C45A84B50A8233037DACC20BEEEBB9B22089DDAF2EBF0698498DA694F75ED2463D09BA2C757A986B8CA556CDF46CBCDF288C078041D497242F66411F47F35A21918855F105F24686076FA21BC1283F17245A7122A848B4BC10D996B2C5161FCE0336B2EC747A4A07FA9851AC5423D1EFC4B524E795B2E4BFFD1C5CD21F5FEC954824DCC53BC3883A7F571A9323DFDD2682C4A4C54E8862F347C9A8897779170B257AD26D90121DDE722A3F214A44CF6C5A5DDB2452A2471EBE7FC8D0EF7F1EDC7920CB42A71E4DB49A0168D51843F47D17BADE50DCB340E5F7B7E5B6A6C3AFE0FB26B5EA172A4011EEE838E5634E521483C6EDBE9994B0658406ED8F4998C7B4E869845CD16CC4368DA3BC1B025A6FFAFBF540133C372D452DD831DCAD39D61CCED0A0AD193FA9886EAC749001E3BEAD5A7962275FC62298A1BD054F4BD97ACAB2BBFDC355C73509D98B6DE5B4CD774BDCAF1398532BB3DB56524CC047ABDE6880C3B282FCE0FB2AD7E4C5F7BC138B48D194E8C8036DF4B9F3949E912AFE5D2734662F27583193D0FBA2B73C1A0D012DB853BBBE4383F6C391F3220E1B5761C337A054FC9FDF09C01864B87324A90C776EFBF5D34A68DEE38EBAACCBB61B4C79A58CC848184F605D43CF9D40BE90C1FBCF6735270132B59A636B16ED28111246270AF32EA2CB7A42A084005AEBB6161002E65B37217361BC269F5ED12F7D50613C82934A6D1D98D1308AC82827B7504F3FD351E0ACA1C62843C9219023FD092692BA4B83BE198EA");
        byte[] pk = Hex.decode("0A0FD65E69F79DB63719657DEAB3B7B2E0807D9A08D9689AF9F8F89166E66D98174000");
        byte[] sk = Hex.decode("0A5D3CCE926A795ABC5F6632CABFF8BF66000FD65E69F79DB63719657DEAB3B7B2E0807D9A08D9689AF9F8F89166E66D98174000");
        byte[] sm = Hex.decode("[encoded data, 64486 characters]");
        byte[] seed = Hex.decode("7AD6C7DF00C9E52A75290D28DA946305D83CCF6DE2515C19A8E26850C34C8C2E545E2E32108F13B9C97F87AB68D10131");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");
        SecureRandom random = new NISTSecureRandom(seed, null);

        kpg.initialize(PicnicParameterSpec.picnicl1full, random);

        KeyPair kp = kpg.generateKeyPair();

        SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(pubInfo.getPublicKeyData().getOctets()).getOctets(), pk));

        PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(privInfo.getPrivateKey().getOctets()).getOctets(), sk));

        Signature sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initSign(kp.getPrivate(), random);

        sig.update(msg, 0, msg.length);

        byte[] genS = sig.sign();

        assertTrue(Arrays.areEqual(Arrays.concatenate(Pack.intToLittleEndian(genS.length), msg, genS), sm));

        sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));
    }

    public void testPicnicl1urKAT()
            throws Exception
    {
        byte[] msg = Hex.decode("3EAC87B3D642CEAA3DC904AC3C4245CB2A260E4B74D0394D33D4B71024144180A727F80B092305F31B2526998EDF6F98E46933FDAF0E8709E98D54F13C2701C58BBE35292FD3334C5E03D345A9A2EA1E01B2C4573567FF1FF3BA7406A16F5A5805EDD760AC78A3AB8602E415F67C7CEA5B36421C79F83CBB14FA775448A832A4B28851CE215C11DCBAEE652CDD7342B6B1204727479E6208FB556CF08BF7EE230F32659E829CE4FBCE0955D01D36624BBAC18C1D25A3E187722F8F74C88B56E518CF0E78B3B0EAC56D8F13C4AFC4DA3613A41CCC2B0B0E2EBBFE5799E479F81335360D483596E9AE926751EC9B956555F271C2CCD85F0F6C1BBB2C326C29B5DDF6B5C4C11F8EED15C0143993FEB626543E92CE4D66C0BD28C79ED1ECB793A3091D6B9AB510B0D41AA42D70C2D8F26EA0B826C8C375E1DD89B3E2A48FE5D88A462DEAC33BAC35AA32EBC010AF7E47B77AD23653D747760914E0CA12864CD401787EFD96F30D82D8907DC68578067703DD19B2377DF319EB540E8AE78B2BE86BEE1C915FF3B2F4B25C0AC22CCF89BD85371961944D8A4E6D20E2D3E9DF3A07D3BF6986898786F0667545275FAC3EB0F069B457D8EBBE5F60125F94756DB04EA203451A0DE160CBCE2A34650D92F200448B097691A61361AC487FBC3C82B2BD7C1ACCA02031311971C3CF69BA459A0B640A702DB4467973713A6F2466560FFAC0592D64FF1D4A935220826EB559CFE0144EA4B8E54EAF67DDF91988DD4B3749C865008C0C1CF98BBF76D929B85C8C426C15FA56706984E0F2E90658FA3CC33EC9FC700976870C94035ECF9A0534B18D07F55923663835416E40235CC2550BD9822F0912CF101F86039830AD9102AA4A3B6777EDEC5EBE621082FCF81A1C6A528F0324EC9D39FA80B6E87D6366E7EDAA0E14337D6708F7C3D2FB1978F4F5CD594FD35B267F9CD09370D3366DCE286CCB9647A1944F8D8BE63E5EF8F6108CC5E9AFE9127DA84E1913439EC35A4E17F7782DF042DC2F7C5CAD8A659DB282E61763539B56C2AFA0F2B507D549EC8C9E76C7DB306380CD7B46C9699B6DB8BE06CCA15E8E83763137B06BFF02DE2738A46C61B70EDF4F394D54D0453DABF689FB6BA41616BC589CB9847224E74F919B6E03672EC6A52584FE81456D6E648DD6F0F9B068EB72241F067BF6B891A498A9A59356C735E10EFB37B3ECF47CC5620A35442DD81E25D2C6DB0E9E871301ADD193D628B30E3B4345751BC17E0B5B05AF758A653DE7BED3763303FFE1AF05E407F296C736CA6F4C348B25718C7A814BD0730AFFC057842AF3D9B9ADB12FCCD740ADD16218AA57E43835821A2BCD70F1027F3042D4A92F10D0A1FB8323E87869BFA8DA24DA75F8743FA3038C24FEDC0C987065421BF4B300BE3ED3F6D6D590968D3EE32A8F5E20EA6168756AA18BB78B6AA48C299C36D0E78B6F84CACAB5946C69179E461F4C2DD201D8032A29EC6C52942AC37D9C76AB4A401C9AFF96284E1E9E39BFF6D912CA33B6118067605EA65D7F611DD963F4F75F97346FFFD1DF84C79CCBA06804B3017775D8C0BF614FCF4D824709557937B22E1805A0A961ECF226F26E3706362BF6D8D1DD30BE7EEDA481A64961641DC57B9F0211F8EE43578E4C2B6507114DFFF3C3F884586BFD1278D117F7C6014FD5980CDF1E2FD1F34CCAD170842B9E819C22FAB9890AE265C3BB6946FCCFE218544D00A6BA5BEF5224EAE24002B6E83E0B35E98C2322BE2EB3D8234BE8B048C54E40782C9A24D7A8B461EC05F38A94AAEF3DA3B46D0D85B0D949CF1089408189FF97C56C7DEE50A004AEAD82C15C7C0D0965F3C65A9A715A65D29CD3614954EBD91EEB4E74F862FBC944C56F2EDEC4D344F92E8154708AD0F5575880503EF0F107A9A9DB99BAE82357C16578F3E6CBDF9B427DA88DC322D11C6AB2A6AE6F5179C94454E09DF5CAA6A519A4C1903C8F2925639E12AF793695F256BF0E55E0D45B73880358F09719ED89A4A1A07868BFBF16095A20035D5D4F99FDA19DDAE3E21CB98308F4508B5CEE706C27898F03A2BF14F29ACBF055E4AB0713A7B6FC1A7853EFD36E1290E69587FEC15D492A66B9A4FEA6E2BCDE61E02FE18E06F59A2F4E06F177B14CE4C1CF1A8D1F49C554A8A4C68B9937B4C230320C80753D4B071BAB2DEDA89C9181820336F1E766E447EA1C44E15CBB7C002C1813D2C1726DB0E4DE289466077DA9610E5F3AA313B1B01DD79A4056A8BBE9D843CE5B0439325FFDFE91FDADDEC6CB86D5CEBB68D8F9C0ED237A4648C412780ACFF48FD9CE817EA70D950DCB989EA6B11FD87EA4F30347A27488C5C15BE7FD6D1280FEA3A7C022F8D9881FAC93176DB2025B4C7914A51099893A791BF5BE851F325347484CA6ED51B2BA71548A6046EA7EC85B31A9967E7D119D2CA3A51C1E14D5A3EEF0D41BDD615DA01D45979007A1997DE281BC340C3203D5BC0075B1AA38873A9DBB9D18E6E26971E70B54E41E2C8C91D2E60FBF85435C1EBC4893C45A201B1D2391549F52A1CA3E0440ADFB746FBBF0D9933F9FA0220B3E04EBEBB29D2A9AC1");
        byte[] pk = Hex.decode("02A7EC6109197F5D7B5F5FC34882060C684382116594501B943F5333789ADA2EBA");
        byte[] sk = Hex.decode("02DAE1EBA78AD1568590348088AAE88C1AA7EC6109197F5D7B5F5FC34882060C684382116594501B943F5333789ADA2EBA");
//        byte[] sm = Hex.decode("[encoded data, 111560 characters]");
        byte[] seed = Hex.decode("C8671A5D752CC6DDF075C899797603A625C142485EAC3D57CAF14F2244D7F84D116B28F959912A758E519D588A6A07EB");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");
        SecureRandom random = new NISTSecureRandom(seed, null);

        kpg.initialize(PicnicParameterSpec.picnicl1ur, random);

        KeyPair kp = kpg.generateKeyPair();

        SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(pubInfo.getPublicKeyData().getOctets()).getOctets(), pk));

        PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(privInfo.getPrivateKey().getOctets()).getOctets(), sk));

        Signature sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initSign(kp.getPrivate(), random);

        sig.update(msg, 0, msg.length);

        byte[] genS = sig.sign();

//        assertTrue(Arrays.areEqual(Arrays.concatenate(Pack.intToLittleEndian(genS.length), msg, genS), sm));

        sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));
    }

    public void testPicnicl3fsKAT()
            throws Exception
    {
        byte[] msg = Hex.decode("EDD4DA833528B0511534F77857FFD16EAFB1A2AC87E6844612DBB104B9F32025B7F54E993D65CE85A061B6AC6D70A15BB42BBBBB6E2E21AEA55BB8A556120EB15EF35FD9774FC7B5C2894B747D3E4965B77DD8D5B26F38D413662783DCD332765B4DE534D08D6514CA9DC6ED7F2BDB4B5C437178710B04491708836CF2CCA08F28582107D27AC305EDE6030B1F8AADC4A1D29AD16CB4D739D8F813D47DA715CAD6B5CDE24EA95DFF4415B527DD900442D9ED1CA712C58B206D6E79F8AEFB882013358BC578638225BE79B58FB677277F072AEBCF8CCD6AB61A9D98A3B260E60AA625D78058FAE6028E4C5562A0F3473C3AD530BC4471228F27502A8F8FE2D1F72022103C3A2DEA363E68248ED8693B3B066B495561CF4468E8EBF32B454E54DF1766468AD3831D56EF7EB9C231E999C4CC3A6B0EBBF2C4F22820E256F67497427F53AD22D42C9293DC8682D0BE3517B63C6E871910ADBB3406B6B3B1CAD980AAE47BF9686E80B6E5DF2DACCCEAF9506B4667271779D00B4C1065951E21F2ACF6CF3CCCB8A633D1114CE9D531D94420E4AE496086638F031C0BAAB5722A41A66788D3885EFC7FE1C3DB54BC69E35B7489A0237A37AFE5194B5F424F792CC1D696098BCF327D87EBC50429A95ED82105C4328D0095A9775589FDB6C262FA51FFEE4D99C6D1A68FA661D1B6A0A2E0693D73B39218A6895BD83FC1D54831B7DF146FE7BD2A91B979018787B9904285A35922E22A7F1761BEA541EAF21D74E3A2F3C6F2247B042379CA4C553FD9256DD0C63E4C9DEA60912D02FBE4CE7762069A86CDE02A4E1E311B2AFDE435DA0816ACA659BD8C0650C1F118C0EA3622D72A5E96132F8B0FF8458C757648BD46E58195FAA0FC4FF8FA44238E35A25C9807B6229000EE560D8E085F27375C2F659BAA5FDE302B9529BF4699505C28DE33AB5DC2B8C02967947CD24C6A599ACB5C2D1E7D6BF3BCCEA0253FBE11D8043FED532AAFC9EE1151243BB80B92BE239BC4FD1D1CAFF502951205F2E6393B704E67141E1218963F664FE0759C15E6C0A1B40602A73990F040502867A9EDDBD4DB0E554AEA4BB9597949D5FB32C2E3AF92CF7816BEDAD5EDE1B769C823CABDEFCA1D1B85213C79EB03E065146B58E3BFBE80B4D4683B65AD1E0611372729B99A0B93934D52DDE40C19FED5A2B3DC3030E0B5F26B66474A5CCA6D741AB294BBBA6BE516105C08BDBABC97BDEC2141D035BF6C3A71553D6F6350229CA2626B8B0B56A24F2D6EECE436ECB77A70D747B6A6F830578B4792DE533879B174353424E7D0EADF6BD5A74B36A4E6EA7E39A4215559557BCE7A00FAAF0D1F81016F913A10F3C9F406C7CB53282CA8FD5FE4F5FABB96F891583E0507912BA02709764694296A5248C340A1B9EC3DB0F926F438CA96FECD40C4AD8DAED9B8A29691601835FE14283762236EF2135443307E5F0082D1C2180AE96ED0DD99A6E9172088E8B94AA2952BA5E128B202B2CBC1966E69B6E6384820D9AB624BC71788EA84B4ADFCFAA2EFA1DDAA8855D1DB3F58EEF2D54FE11A8A5D78ED46B58460E6F2FBA6CB70640700A4520AA1A2A9B336AEFB17CDE8AC78D67F194662642A0107CE38B74D731380A72AD4A0A068F09E0878E521F15CE8134780C3FD0CAB2DC2473448654F88BF1FE2020901B90C0ED670866B1BC337881292FBA885FE2BFEF6FE74765CA12372C8CBD698AC41A4C337374587DB15AFFB511D8C224F1743498D7173897FF5B8D070B89592BEBE053D5C10DCE67CA8542781AE749F3A42FAD7E4A2004A565F81D5FAECF11115C270155FB8AF6AEDA138B9C71458D6D2FF63441130EE9107C39260469521E020D2B42CB5A51098027F23890DAE8B28BF722AF9ABA6224E02FEB47E40112CCB164E8CF174BC9AC4C11AF9B482DF9C9F7F5F1B826428C21BE395EB1F07DE511E8258C84F5F035F4787ACE18C190808EFE99FCB455A54D366DDE2E230B575ED5A4A75D57C9A38DDE3D91D0D1A1C4DE7F277CAF23E0C5DD8E3B693DBC66B6BF1679B0AF74A2B9065B64CF0978115CC456AF685B22D85135727A8AAD96338611DC109B36C85A92E4A0180AADD1D25C5B3D4C681A44BACB953E50F994FCF5281366CDEC0CC50976074D91840B5079180CF643184ADCF9E4CCB44328E7BB9EB2BD06DBB7A757C35EC3DCF795A5E05ED250159EC453A1692426F624CC0737F691E475804F155E44293151E42D3C0F115ECEE53C6EEEF69788F7E8E5C422BB102237499F2638244C0C080B3639A49FFC1730EBB0CFD8A46");
        byte[] pk = Hex.decode("03E5C76D5FC02AC92E2ABCCFF779347313F4ADD744B15CEE5A64D6C65C750512A619A02BF3E98CBA9073EE368195F22185");
        byte[] sk = Hex.decode("03802E08C14F6E3446BBF7F4666C8DDF7755DC718C3E02B786E5C76D5FC02AC92E2ABCCFF779347313F4ADD744B15CEE5A64D6C65C750512A619A02BF3E98CBA9073EE368195F22185");
//        byte[] sm = Hex.decode("[encoded data, 151410 characters]");
        byte[] seed = Hex.decode("CF5A04DDB5EBC45328F703D486D24443A7692D65AA55F054E3078DB76A7939590A3F35CF1A21E82A845445DD1B64A85A");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");
        SecureRandom random = new NISTSecureRandom(seed, null);

        kpg.initialize(PicnicParameterSpec.picnicl3fs, random);

        KeyPair kp = kpg.generateKeyPair();

        SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(pubInfo.getPublicKeyData().getOctets()).getOctets(), pk));

        PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(privInfo.getPrivateKey().getOctets()).getOctets(), sk));

        Signature sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initSign(kp.getPrivate(), random);

        sig.update(msg, 0, msg.length);

        byte[] genS = sig.sign();

//        assertTrue(Arrays.areEqual(Arrays.concatenate(Pack.intToLittleEndian(genS.length), msg, genS), sm));

        sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));
    }

    public void testPicnicl3fullKAT()
            throws Exception
    {
        byte[] msg = Hex.decode("9366ED7B3B623C411448B634446F1A3FAABDD163A6CC1E2BCAE4A98703CD8CEE441405892FBA051BE2A586A6950A5EF73A255E5F86B0D7212E0C51C3BC79BE4B88E76ED6F043FEF3204FAF044BFB1ED722D61EB5D0B74C66A257E8AC3A2206273C80D2EC2123A4DBB715D60118D99ED7322E38F1562F82379138DA3DDB8BAA7CE61AB729AFC3748C0134633CF45A9973C05C75D04E82F631845427626B5799DC07DDF830BA01E8BC6236BB6D03B37D949DBB29EEC7DFE60FBC17EA590956D251539792016E2A8B01E70476961BC9ADA43CDA682D0CAA4FCC58810BBA1A673EF8F6BC90BAEE701E8E4F7C04A346CA56C7B2862FF57756CE6CD1EE22D677BCDAA896EAE96F87870E032C18B6C6A0C1A191FAE2ED487CE55296CC4B6339EAC9E8A742BD0A44C3525CC750");
        byte[] pk = Hex.decode("0B5AC6F8D65AFD77DFBE42B3A3109427285CAF43EDBCE609AFF4EA973B229C69B772E8FD400091204DD9C4C453EF412830");
        byte[] sk = Hex.decode("0B1DADE637AE98C393260F5BBBE288373100DD7AF37EBA913C5AC6F8D65AFD77DFBE42B3A3109427285CAF43EDBCE609AFF4EA973B229C69B772E8FD400091204DD9C4C453EF412830");
//        byte[] sm = Hex.decode("[encoded data, 138352 characters]");
        byte[] seed = Hex.decode("9B42F41492530EAC81992F17613EFDF155F407D7E67F18AE193EDCE714D65D1031E7AD10839AAB46D0850EAF5997AB4D");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");
        SecureRandom random = new NISTSecureRandom(seed, null);

        kpg.initialize(PicnicParameterSpec.picnicl3full, random);

        KeyPair kp = kpg.generateKeyPair();

        SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(pubInfo.getPublicKeyData().getOctets()).getOctets(), pk));

        PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(privInfo.getPrivateKey().getOctets()).getOctets(), sk));

        Signature sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initSign(kp.getPrivate(), random);

        sig.update(msg, 0, msg.length);

        byte[] genS = sig.sign();

//        assertTrue(Arrays.areEqual(Arrays.concatenate(Pack.intToLittleEndian(genS.length), msg, genS), sm));

        sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));
    }


    public void testPicnicl3urKAT()
            throws Exception
    {
        byte[] msg = Hex.decode("0BF9A7C0F63CDCF3F850ED7C5DB6191EEEFE29E498A19F9D89BE4698821ABD72EDC34317B4F8EC2736DC83C24AC195BD55AFF00E797A83DFFADC7970FE53304F16F5DD92E6EC362B9E283E41EBF121FB2FA2A3F60124EF3EBF836AE51FDD55CA9F59B085DDD660724C072B86041B50A3A446CDB20A45BA65380ADF007E005DF2D9AA16A9D22B11DCF6F0B1964F04F45441A923691A15D80DC85003B9AE281F2B5983DD1A04D80A4D9C4372D9820BBFAE3AF7735E7C71E9F085C0A6E4BC107D9E4BA222B38FB236B2CC3A19DD6067BEAC460383FF2BCC771A7F1AAF092FC72C292FC1D5C6FC6B9715F1E1272EB22F8E0B33A2830E31BD6C531677902F6A95CABC3E9C1AE36F77037A785FEA355137A581FC14E6BD5F1F7AD1A5DD19DEDD448B47B558C22DD0FCBF296A812A726E7D1B57F4688D3F577104CFB15FC63C27F7B6051C7AED7D645186FCA63AD9C2D68BFF442466EFF76BCF0E398D2BF54C2CA4CC614839E9BCA48AB2CC53865803710A98D313AFF1DDD06A65680EB83C640052DB807EB2F38ED0CC211128044D331FEC3E6B0B2F3B675C631FDADE62C16D1719278413EA3F8E54BA34EDE7E73F3D94802D2F9CB9794D257C46679A3F00015945903190B97071F8FB55F8696253AA3F39B3FAD344FB88224F5313B43889B768171895F7AABEFF25E21E525EA01A996C764A3ACF12BFFED08F3F751F5CC094B50B325F8B62C7A5B3256964D48543690538E634E5730354358534B65EDDD44A526BB4B15E2042B6210F503EEE06D00D615CCAD10D73CDCBF5264B526674D85C0ED31BA5EE584F21FE6D13F883ACE4B094768865E43099E54671240E8E2AF8A7D7D22335B3974CE860E7238A7C1CA8A009EB51C8636F0659189AC8EF01C871E9008957CECE0A367B63BD2852BDE8690BD74C6D956435D0AB82F94A90CD00FC840DFC7036B84D51F1FF5076CA0974DB6CF25AF42EF7DC8C30C2B04CEB2510E86FFC510BF4C931639478FD1520AD571FA17958CCF8E37F5F6360030300EDE3A33871E9582808BDA2233996C5005FD0C23D99261F570AD9027767F6FC96D18BA98E8DDFC2B79AC12CDA5F2367B4BB6B99A3E07B59882E49A92AECE85339BBB18AB9644D20A3B2A795240492CE4EAF09D9EF728FB82B1DE7B64B5D391251FFB0699335CED8C7CE642FF1A79F04C3EA0DC37EA101188361AFAD236EB218CFBD1D0EBD784CE27DCBA0266DDEB87B59B66A4F75BB44665643FA358DD3D0B69B49F45A752B5C410E2299A62BE4B57B32B0924A069A8E8C15D754CC34DEBB0D967E70693A6FFA58CF7099C2C2458B437C7B205CC7E815F6CB494080F9EAF3017E5FF918558DDE415FF72E954EBC2ED4C20C8ECE38CC916060D22E582D54F74C6C181C2601400110A683F4A365E45FF1387BCE4E152A740136BB762B03A99FB68F6AB42620B2E3C00FA8D150944230A6330409B27E4AAD1693E2C3DD12216C4E2DDBC5E9CBA68B8B5417A7B2EDAE7EB67D25F4EDECBB087F93DC9C927C33076B1C71A2B83B33870D602562ED378805A690DD2A427D86C2C46BA4741F3DEFEB91A05EACE975C836E52868CFFE52CA92F97DE94768161A3E953BAB6A28016782909EC53C02F35184AA9CCBD5B793B525204B72DEB63E104376893B9452C3F2C492F423CBEF1EC87C85788CF3073FFBBCD67FF79BD038672943AE4BC68DA131DBA8D7B41C83B4E9CFB6931987B270C74919BBD40612F823114E4BB148671F1AA62BD2BDFCC8B0B24010EC112E883AEC9746D0F5DE467ADDAF51F8C070A359108B1F91643071438F098233AD9A94D0FAA665A39291A98D14A861905ECDE4755D00E690429C57580DCB6D51BB6186CE72EBB1FA8413892CAFB8713E89775013E546FDA30AEB8AF9F7155C08B25810C80CCAA5E700C124CFF59FA32E0293ADADBCC7B1A99F67E66B28DA614C5A4CCD706AFD05388C65EBCE07A543D3DC1E5A5D1F307F675728D4C629A04E9E455B4DA35236C677F26EDC622C1FBF29568D509EA0690AF4CB5DBB4E418B6162888E43B458774A31324BFD5EE8D2152E4AD43A3007D7D4AF5FDA172C2779837AD3A09E135DE953CE966727A7183BF77ADFC76430666B526692991D3C9DB5BB377552A7801C548AA63F6931D3EE91B875CDBCBB7441A4FF81F86762332D7192FBC2F7B69A58DB6CCD3558047F1940A1CACD6FA28A000B9795A2860394BF05F0120E6D85F96B1FE9DE14E3ED66A31D747924B6FF2620778E0714AEB34B79A5D935A0306E55C36506A292C5DC568403551907E49A43A6263D2915108916F1E27CF3529D1B7BD1544AF83A7CBE58547F192A93CE5C5BC6D652405FFCB95345F522B2D34E8EE0960BB85537A46121BD9A408D283A125EAA745BBAB04E2231C19AE95E13901C69E5C9C4D70B104478F4A70D64F81269A8");
        byte[] pk = Hex.decode("04BFE019823C559594AB3B442C4294722968B87E81AF65CAA0331C19CAE713F365F5D17110BDB0A1D64B2EE06E58693C60");
        byte[] sk = Hex.decode("04FA812D8CC3A9631A0239474EB93AD3A2A3480F2D973D3324BFE019823C559594AB3B442C4294722968B87E81AF65CAA0331C19CAE713F365F5D17110BDB0A1D64B2EE06E58693C60");
//        byte[] sm = Hex.decode("[encoded data, 247130 characters]");
        byte[] seed = Hex.decode("4B6B73E042CE76DBE39535E45D3BB2F3B9F8B2BDA170E76CC88666844703E32B2367460A0F6A0A2E3F4E7A6CD32BE998");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");
        SecureRandom random = new NISTSecureRandom(seed, null);

        kpg.initialize(PicnicParameterSpec.picnicl3ur, random);

        KeyPair kp = kpg.generateKeyPair();

        SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(pubInfo.getPublicKeyData().getOctets()).getOctets(), pk));

        PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(privInfo.getPrivateKey().getOctets()).getOctets(), sk));

        Signature sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initSign(kp.getPrivate(), random);

        sig.update(msg, 0, msg.length);

        byte[] genS = sig.sign();

//        assertTrue(Arrays.areEqual(Arrays.concatenate(Pack.intToLittleEndian(genS.length), msg, genS), sm));

        sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));
    }

    public void testPicnicl5fsKAT()
            throws Exception
    {
        byte[] msg = Hex.decode("[encoded data, 4422 characters]");
        byte[] pk = Hex.decode("05429B18CB8C97B09C04880A9F452EDF7ED2436215180F1DC2788B13D96F0171516DB925E3F0C18153A88305735B7B63FBFBBAFDA43D53F6DB06B50ACFF0D75BCC");
        byte[] sk = Hex.decode("0525D957B9BF68326D2EFEC93DA464F43E3DF16DD6571CEB1AB68BD58E87734A51429B18CB8C97B09C04880A9F452EDF7ED2436215180F1DC2788B13D96F0171516DB925E3F0C18153A88305735B7B63FBFBBAFDA43D53F6DB06B50ACFF0D75BCC");
//        byte[] sm = Hex.decode("[encoded data, 258750 characters]");
        byte[] seed = Hex.decode("83C653708FAF3E5F6FBC9DFBE6FB5E83E572A7688645D75D2C4835B28695DEA4BD7093740D0FF43237354EAD1C978BC2");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");
        SecureRandom random = new NISTSecureRandom(seed, null);

        kpg.initialize(PicnicParameterSpec.picnicl5fs, random);

        KeyPair kp = kpg.generateKeyPair();

        SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(pubInfo.getPublicKeyData().getOctets()).getOctets(), pk));

        PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(privInfo.getPrivateKey().getOctets()).getOctets(), sk));

        Signature sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initSign(kp.getPrivate(), random);

        sig.update(msg, 0, msg.length);

        byte[] genS = sig.sign();

//        assertTrue(Arrays.areEqual(Arrays.concatenate(Pack.intToLittleEndian(genS.length), msg, genS), sm));

        sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));
    }

    public void testPicnicl5fullKAT()
            throws Exception
    {
        byte[] msg = Hex.decode("92D5FEEF68737ECE61C6E0078D77FBAE97B0B9235F40B97099C114B1586E107B5ED1308A8A2D20BE41AF129DA2E0B38EAF02FAEF733C7A1D1A387BC55EF008530ABC22697D0465AA3EB71F41EE72ADD236CEA9A25995F3689C5A451E2F03915D96ABEA10D356D549D68048977587326523CCD71C05FD57BFB3C7A853F535BEDDEADFB84118F6548860F6BA536277DDD7AB42123E93381A385FA3E6CC023C1458A9F94822D93248F36C48FDDC972B5D6494B26658440FFBC23B57363F3D82CCE69FEE4747A889E85343288D55D30FC54D2D0744744DBA9977720E8EDD2C0ACA1FC51B0C6A3C68BB9BB8DA0385DB1CA4E9CE660CF7EB2382E5E95D2AE19DEF904A8651DFAE53A4D0DC4D057AB1A506C3BD7E1D1EA3FC4623E7D7B410DCB312F037B7A5FDE5E0E604FC33270FAF1FFB6ECB3125DDFA5C49F25BBC98238C8AB1B903537CD67238995E81B814280A4CED61513D69A2178086D505F8DD1DF7E11CE66AE33D4C982F94231957031A258E0EC745672A57A5CE76D1170111B8882A9EB5388094EBBD53EE9EA1FCE4A275F9D7060C8DA79018487B452817280C63B01B05EFBF897387592E2BB3BB486FAE0AB09F46D9F2E176DE96C59992C10A14EC16EAC36102B1D15541607075E67C842A888C87B268E9809148A323C423220DC31566B62F45CCE1E2BC1B3BF43B87C998F00023890BCE517271BEC16EFAA33F11611FDE87F197852BC2E7A2B44F8C72A6F79B22F73BE0611B81EFE09253931545D2453939C46B6797CC5DC5A8F1AA3BD8456EEEB84EE76DBF2EBF32598750ED10670DF422C7D7993ACC55F657E6E1B3DFA1BD6C1CD55FAE97E69D2F8F5AF368F7DA0A63B4065EB6D8F02B19A34600252FDFFDF4ED8DE2EA9CD2E74D63A6CEF29BF02F92D346ECB9A61081EE5AC811F33AA5792F6A1AF570A8B0846F3E6EF38452346DD637B19ECA37BD1A6C42B20A5BEDE9A5DE3C9F169D04D8C6CF5376D3404F0C21DEAD53DA6C169F390EED7B5B54DBE47CCE0B2AD1179EA8FC80FDDC7281BD4FE31B9A26A00444AF0B4D40A1B72BE37501308906149DC6FC5CF02B6F60AFF82B975FC8F146961EBCCB4D126ADD524A9B33BB16F6A83C6F3727A72EFA2BAC116E493E07B2CA718A63FCAC8E9D52A1B61479B4EE52A5ED30FABCEA4D01A792A92676721286814F3B0F4E15E23CE0C5D59A0C3EB8573C0A2F66C25F2EB2FCFF787324721004979BE5EAC505DFD39F5538E2C1B2CC12D20C1C5CD87299766361AEDDBFFF743693081842378744879E6E6371B3FFA9DDF34966FBF8DEE91B7EDF6EEC3E4E2F410CB5351F847646C22AB594046DED63347D04A008FBF6EE9696C638ECE73B39A269DB239DF36443868AD44D26A5C40FC92DFFB008E436E5C18907F5B18B5E6C5900B41A9801DB070D2DB651187A4DA7E2647ED3E9B6E9781627EB576BEE8334374468760DD3B32985D42945D953D434BFD80D7F7BA537265FFCF27DB0DA1ABDAE89BBE94D98BC9CA197E41C0839728F964FE4CE30B8CC43CBDCDD9CCBE06FE99DEBC6F4024F3F00D43FEBCD62A1822A6D507337EE79D4517AA486870602D4F1C5368B0EAA1FF6C011A9A953AAE58C75BBD3DC78D263A578C75CDB1AB324D71B9A065A9AF3DAB854189585C68D499AE8DB887745E20AD9738705B9D2F5D429F12D6462E5E2EF9FFBA53CE2F4E75449D2A7DBC3C818E61DC546175A6E0C10AE631DF6B1EAE6D134C08466EBF6EB5F8257AA10EF8C6F27F4295F7EBFD450629F3EB4E0F4BE247AD7F5E80703B1247A4FC277311D69E5D62E0B0201A805CC4F1F807DE99420D563A703493AD35A56B2B2DC237112F5EC21C70BF139A9EAD8F7E921F086E001B4C449E42A0E3AFCD5BC757040A2865D0E5ADAF98E37E6F8A501FF39CEF0BC364EECDFFD03069B81F5E1978C397862FD56362835C059FCBE4D8E2A957FADD7D05BB195E21AD67B429621E1D6872DE2D8BFDC91544F9E6AE8C164A23255AD0E00BCB21456F8FA6AE018F49605736C81A5AC0945E2D965F1493ED5BEFCE512AE93AD91DAF6F5A151D6C9856DFDDD1F877945D932261DED67AC8231DC3CCD0B04DC1B02079C897601E363FFB9A3BCBBBDB0B0A375E69EE4A7135C094ABDC237FAA2E5F82D2556290ADCF82ADBA8402C4FC9D0724F15BB87CD7A75A1A7BF826896D8EF63C7A2A3C371756AF638706270652C376100EC42FA55196DF332820D377760448D3E7ADC42E9F5D8A7074BD0FA97433B0E2C501252DE6939AB948552663A17DD7FF05430FA76E29F0519D650B86FBB19FBED097143FC242573E3E6FA4BD4A2EF6D9CE6932A066B4F9FF935BA9BC26FC2E5031C20AE30A52970A2DF3504576108D5F26517F8577BE61E6AA9D192ED62CF36AA641DA0D274B1ED5EE864B549154EB4115658E6C60219CC5B2E22C49CE3BA76A85EFB549117E1207F6DF081D0761421262E352182239F1E34EDBEA4BCD8FA0027543824DD58A20324FD4CFE943AAE5E361C367B22F587E2F9BEE841E11875B026F12B9571512F72985F98F6D0C212DF36A60975429173E317F6ACF72E621F30654A6DEAEF9E9E455524BF07FFDF44642A1826F734D69F3EEF4D52F26C06376C8F71DFB65A24A4C57D74B5976950AF3A57B4248909524BEC47D858C69041EED34E0ED3B111BBC117AB112BBF947D646AB3B7172F5FB726DBC53AE37956E29F5B6B1E3C90BAF4E4FA544FF63815FDF4AC9A2A80CA0E8722383437B9A02F3AC538FEDA7A6D6C1635D3624A385D846E79E956DCE483B89C346C1287A1A7293168D8A885FEB6569EBDF3F47F8BBB50AA43941EB20001959AF1B9B358ABA13FD9BBC596EA42A9774A120AF091D544E79C50686C26B4FEA396BF1E4C25B8EE4929D75569A5FAC521C77B");
        byte[] pk = Hex.decode("0CDE4A29B7302C46C185D218C0E6F4CAAFCAE3218589306FA83B138CB4236C5078627EF60168EF6C8EFD1CEFB403DEE572635E57FE9504C647A4F9DA5BBD5B029A");
        byte[] sk = Hex.decode("0CB323D48B567F7EFFFFD47A7C9ABF0ADD5F11141737A8AF62B56E042EE498AD6EDE4A29B7302C46C185D218C0E6F4CAAFCAE3218589306FA83B138CB4236C5078627EF60168EF6C8EFD1CEFB403DEE572635E57FE9504C647A4F9DA5BBD5B029A");
//        byte[] sm = Hex.decode("[encoded data, 248416 characters]");
        byte[] seed = Hex.decode("09B8441F47235EFC82D71933A0037FA4F69124C3BAD4EF6A3A7178B417A3FDA874081B7EEFD7EF1BF234C752458FBBAD");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");
        SecureRandom random = new NISTSecureRandom(seed, null);

        kpg.initialize(PicnicParameterSpec.picnicl5full, random);

        KeyPair kp = kpg.generateKeyPair();

        SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(pubInfo.getPublicKeyData().getOctets()).getOctets(), pk));

        PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(privInfo.getPrivateKey().getOctets()).getOctets(), sk));

        Signature sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initSign(kp.getPrivate(), random);

        sig.update(msg, 0, msg.length);

        byte[] genS = sig.sign();

//        assertTrue(Arrays.areEqual(Arrays.concatenate(Pack.intToLittleEndian(genS.length), msg, genS), sm));

        sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));
    }

    public void testPicnicl5urKAT()
            throws Exception
    {
        byte[] msg = Hex.decode("9D84E1DD28C513987D5587A4427853762B7D7AF668FF9EC2E90211D6CF5C0DE6C7E54B298C1A6C67EA9A693CEDC4FCA1A6ADC2C6DD0E5BBCEE7266B9C6AC8FA8AF5E50078A6151F938161F1FEACDE4D8079B5A9D563423258CF3AE9E47D8E75740314F2FFA63865A8B30743F773A53E1AEDEAC45CAAE01993B75C8116FB0B431631AC001AA8BD02E5B83DE627AF0CCB3A3D86F66A7E5FB658F9226DF31095780A6E8262A247D70F4E7C971D108567FFBD7FED0E16B7FFDDD93F5764C3E02A61998C32146564D46589538B2E071AF86A26321A3523354F4F0C396B863FC8E9E2E3A173901D0D178A9D2828D0E0974B72CEDFB17937D6054F185A81D4F853787E6C3681A74FE25FAA6C256A9F9E9A9253F98B9AE4B8FA0068DC28BC7E8D5785CFAD20F7DDD643DAE6A2DDB02713C9CAFC2EB2FD18EFDECED05CC24913061BDC38E932DB5E8181FC0D3DE26A94E2138800B3C01E07E83B3B0BE187EDC75DA576AF1CC7B7122367EFFD6EBF05F4C2EEB0AB6E9F91201A4237910A87DE9FEF777981D48FBA28AB8D64D76380911F2A6621335DFA96B331AE8B3242EA1F2A260260244196B0B9596C411218A17D0A58D3B5735B9AD7B6259655CF6E2D0FE5B37D0A0B02E67951F5D3FB277B6E1EC87528B08229AB0EBD895CBA2D075A47CC8100E9DD17DE7D951BF0A68D710AAC21C8226D8CA95AC49FCBE9D493A8D3C7F93FA61685BE57FF422FAD036304F317A3DBCFEE7A4610C8C1DDAA79E37C19D6414F47230E01EF1CD5C7C2FFC319A29AE6A9C95B06C603F2CFC1D1FC914B036CDA6CF9A876946983B06123C2E5C7D09BC190647CDC0512F35DB9E214C77D3D7D0234C3F2590941236A367700F9C04D3AFB949DCA2067571BF28E78ED35FC026BD801C4AFEE9BF31C97580953950D2E81EE6426E78D6F8134ED19707473F0874367C86C9BE170BE63405A9BF7C46A420724B6CCFF9C21B015E21BB02C5A7AEABCA873B46571530DE56E47288C3424DA398517ABB6502A9A6A65D4983D97E479941C44CF0136D225991226F70837E2A7D1E9CB1226F40BF59D52C66549BF8E360096954F5875C466160A0C75A252E5FE6B8F1841FE210BF08520CE74D77B69692086EF50BB64732F19D1A49E5800F077700553290635D418168A6B9E3AE980112AFB9D58A18B94F972845C309E86FEC7E456191D8760A1C2106036E44C5C9A5F2CFBC67D741E8E937E99ED7820AB0787E39C385356EF0F05CD3E31C44115A8892224197B1D1F554D5098B72058FAD49C665F716A266CB4DB6204666E1DC07B6CFDE0EA00345661E0F94A5025D2EC98483CF482058D2EDDB018CEC11D91EB46B63971AB29367DB46137CD7690D5782E3A3DDC8CABD545FC1AAD8A9A0A39542AEC55CC3D58A5BB5E4A559DB1FCD2932EFF6E81C8B8E5AD5B4E0424A444BC55D96DF63C8971A5890310FE19DFF8ACBA72D96FD3F32D67D41A2F3D0B343489C7FDEE7556012C2D88E2BA9D512B71E7D04F92E6BE3A9386565271D755BED752C853E4539F95C3287A275004F76B9A93837C6EFC6760BE4A39B8AA92C7605AC369472FB29E11ACAD98FC91B1B9BB3505638D4D46A3AE3C10C8DC115C35725F06649BFB00BA1EF214B9F2FE98BE2DA99AB23E7B9F014F5C5D0248A9E0E088AC175C8048C6BEB5108DA59DC234E9EDFBE603BA912BEA22505C2A9EAAE766FF55AAC8392AEA5C722DF25BC6C9FCF9B0275DF71206A4E5290FC5E71D79928E357400DCB04EFD7CC9BD0B86E04BFED9BDBCE5787E40FCD6041ADDA615B5ECF03C30AB9B2809E3514E9AC87226C55F259C5F157945B0073431715E1740DCB319EDDDD1B5F2763F0439CC0D6ED5867D9D98C227CA3008F30D1B2AEA40DC73FF8289E4A21586EFF519520F888E7E2F6D29A269C12607D13D398F437CD7F0A07C94EE1E1E3D8518D0C97BE1E250D79C5AE1709AD8A638F55");
        byte[] pk = Hex.decode("06ADB9725B0D0E8294B88DFDED8779A83E044C5EFA0B0395546245CB344973FEE2048ADD9DDB845F46A4C1E3338DC78AAC49FB30623F649FE4FABE6B9FE23F5B2C");
        byte[] sk = Hex.decode("06F92FFA3A36F43F9177763AD320FD651D9357C6D99F09549FE6AF12943B58BE90ADB9725B0D0E8294B88DFDED8779A83E044C5EFA0B0395546245CB344973FEE2048ADD9DDB845F46A4C1E3338DC78AAC49FB30623F649FE4FABE6B9FE23F5B2C");
//        byte[] sm = Hex.decode("[encoded data, 421792 characters]");
        byte[] seed = Hex.decode("1C13369824A3FDD41B1065E17297574715D9BD9CE5BB733D36D22C31B62BB1033989A604D78BFB1A0746BD4A2271FC0C");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");
        SecureRandom random = new NISTSecureRandom(seed, null);

        kpg.initialize(PicnicParameterSpec.picnicl5ur, random);

        KeyPair kp = kpg.generateKeyPair();

        SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(pubInfo.getPublicKeyData().getOctets()).getOctets(), pk));

        PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded());

        assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(privInfo.getPrivateKey().getOctets()).getOctets(), sk));

        Signature sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initSign(kp.getPrivate(), random);

        sig.update(msg, 0, msg.length);

        byte[] genS = sig.sign();

//        assertTrue(Arrays.areEqual(Arrays.concatenate(Pack.intToLittleEndian(genS.length), msg, genS), sm));

        sig = Signature.getInstance("Picnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHA512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        sig = Signature.getInstance("SHAKE256WITHPICNIC", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(genS));
    }

    public void setUp()
    {
        if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null)
        {
            Security.addProvider(new BouncyCastlePQCProvider());
        }
    }

    public void testPrivateKeyRecovery()
            throws Exception
    {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");

        kpg.initialize(PicnicParameterSpec.picnic3l1, new PicnicTest.RiggedRandom());

        KeyPair kp = kpg.generateKeyPair();

        KeyFactory kFact = KeyFactory.getInstance("Picnic", "BCPQC");

        PicnicKey privKey = (PicnicKey)kFact.generatePrivate(new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded()));

        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        ObjectOutputStream oOut = new ObjectOutputStream(bOut);

        oOut.writeObject(privKey);

        oOut.close();

        ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray()));

        PicnicKey privKey2 = (PicnicKey)oIn.readObject();

        assertEquals(privKey, privKey2);
    }

    public void testPublicKeyRecovery()
            throws Exception
    {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");

        kpg.initialize(PicnicParameterSpec.picnic3l1, new PicnicTest.RiggedRandom());

        KeyPair kp = kpg.generateKeyPair();

        KeyFactory kFact = KeyFactory.getInstance("Picnic", "BCPQC");

        PicnicKey pubKey = (PicnicKey)kFact.generatePublic(new X509EncodedKeySpec(kp.getPublic().getEncoded()));

        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        ObjectOutputStream oOut = new ObjectOutputStream(bOut);

        oOut.writeObject(pubKey);

        oOut.close();

        ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray()));

        PicnicKey pubKey2 = (PicnicKey)oIn.readObject();

        assertEquals(pubKey, pubKey2);
    }

    public void testPicnicRandomSigSHAKE()
            throws Exception
    {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Picnic", "BCPQC");

        kpg.initialize(PicnicParameterSpec.picnic3l1, new SecureRandom());

        KeyPair kp = kpg.generateKeyPair();

        Signature sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        byte[] s = sig.sign();

        sig = Signature.getInstance("SHA3-512WITHPicnic", "BCPQC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(s));
    }

    private static class RiggedRandom
            extends SecureRandom
    {
        public void nextBytes(byte[] bytes)
        {
            for (int i = 0; i != bytes.length; i++)
            {
                bytes[i] = (byte)(i & 0xff);
            }
        }
    }

}
