1

I am trying to implement EDDSA signature with Luna HSM(Gemalto)

Signature signature = null;
signature = Signature.getInstance("EDDSA", "LunaProvider");
PrivateKey privateKey = getPrivateByAlias(privateKeyLabel);
signature.initSign(privateKey);
signature.update(payload);
byte[] byteArray = signature.sign();

But after the signing, the byteArray size is coming as 71, but EDDSA signature size is 64 as per specification. I am not sure what i am missing here. I couldn't find any document either online.

Mayuran
  • 669
  • 2
  • 8
  • 39

2 Answers2

1

This is exactly a size you would expect for an X9.63 compatible signature, which consists of a DER encoding of two signed big endian integers. If you want to have a 64 byte signature then you should convert the 2 integers inside using the following explanation. An implementation in Java of I2OSP and OS2IP can be found here.

So the steps are:

  1. parse ASN.1 signature;
  2. convert to BigInteger values using the new BigInteger(byte[]) constructor;
  3. use I2OSP to create the r and s values as byte array (32 octet output size);
  4. concatenate the r and s to create the 64 byte signature.
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Thanks for the reply, it really helps me a lot, i am trying to convert the DER format to ASN.1 now using BouncyCastle. I will post the code once i managed to do it – Mayuran Mar 15 '20 at 03:25
  • i have tried the following but it seems that the verification is still failing. – Mayuran Mar 16 '20 at 02:36
0

I have tried as follows but the verification is failing(Code updated and it works now)

        Signature signature = Signature.getInstance("SHA512withEDDSA", "LunaProvider");
        signature.setParameter(new LunaEDDSAParameterSpec(false));
        signature.initSign(privateKey);
        signature.update(payload);
        byte[] byteArray = signature.sign();

        ASN1InputStream decoder = new ASN1InputStream(byteArray);
        DERSequence seq = (DERSequence) decoder.readObject();
        DERInteger r = (DERInteger) seq.getObjectAt(0);
        DERInteger s = (DERInteger) seq.getObjectAt(1);
        LOGGER.info("R: {}", r.getValue());
        LOGGER.info("S: {}", s.getValue());
        decoder.close();

        byte[] rByte = i2osp(r.getValue(), 32);
        byte[] sByte = i2osp(s.getValue(), 32);

        byte[] concat = Bytes.concat(rByte, sByte);

        return concat;

Not sure this is the correct way of doing

Verification using stellar java library

        PublicKey publicKey = getPublicByAlias(publicKeyLabel);
        LunaPublicKeyEC lunaPublicKeyEC = (LunaPublicKeyEC) publicKey;
        byte[] pubKeySub = Arrays.copyOfRange(lunaPublicKeyEC.getP(), 2, lunaPublicKeyEC.getP().length);
        org.stellar.sdk.KeyPair keyPair = org.stellar.sdk.KeyPair.fromPublicKey(pubKeySub);
        boolean verified = keyPair.verify(payload, signatureByte);
Mayuran
  • 669
  • 2
  • 8
  • 39
  • Ir looks ok, how do you verify the signature? – Maarten Bodewes Mar 16 '20 at 08:57
  • @MaartenBodewes Thanks a lot, i managed to do it, i am posting the updated code for others reference. The reason was that the LunaEDDSAParameterSpec default was setting the prehash to true, but i set it to false, then i was able to get the same value as expected by stellar(crypto currency) verification. I am not sure about what is the default for EDDSA. – Mayuran Mar 16 '20 at 09:56
  • @MaartenBodewes i use stellar java library to verify the signature, updated the code above with verification as well – Mayuran Mar 16 '20 at 09:59
  • Code updated and it works now, does that mean the problem is solved? – Maarten Bodewes Mar 16 '20 at 10:04