internal static void crypto_sign2( byte[] sig, byte[] m, byte[] sk, int keylen) { byte[] privHash = new byte[64]; byte[] seededHash = new byte[64]; byte[] result = new byte[64]; GroupElementP3 R = new GroupElementP3(); var hasher = new KeccakDigest(512); { var reversedPrivateKey = new byte[keylen]; Array.Copy(sk, 0, reversedPrivateKey, 0, keylen); Array.Reverse(reversedPrivateKey); hasher.BlockUpdate(reversedPrivateKey, 0, keylen); hasher.DoFinal(privHash, 0); ScalarOperations.sc_clamp(privHash, 0); hasher.Reset(); hasher.BlockUpdate(privHash, 32, 32); hasher.BlockUpdate(m, 0, m.Length); hasher.DoFinal(seededHash, 0); ScalarOperations.sc_reduce(seededHash); GroupOperations.ge_scalarmult_base(out R, seededHash, 0); GroupOperations.ge_p3_tobytes(sig, 0, ref R); hasher.Reset(); hasher.BlockUpdate(sig, 0, 32); hasher.BlockUpdate(sk, keylen, 32); hasher.BlockUpdate(m, 0, m.Length); hasher.DoFinal(result, 0); ScalarOperations.sc_reduce(result); var s = new byte[32]; //todo: remove allocation Array.Copy(sig, 32, s, 0, 32); ScalarOperations.sc_muladd(s, result, privHash, seededHash); Array.Copy(s, 0, sig, 32, 32); CryptoBytes.Wipe(s); } }
internal static byte[] PublicKeyFromSeed(byte[] privateKeySeed) { KeyPairFromSeed(out byte[] publicKey, out var privateKey, privateKeySeed); CryptoBytes.Wipe(privateKey); return(publicKey); }