Example #1
0
        /// <inheritdoc />
        public override bool TrySignHash(ReadOnlySpan <byte> privateKey, ReadOnlySpan <byte> hash, Span <byte> destination,
                                         out int bytesWritten, ReadOnlySpan <byte> domain = default)
        {
            if (destination.Length < SignatureLength)
            {
                bytesWritten = 0;
                return(false);
            }

            EnsureInitialised();

            // TODO: Generate random key if null
            // EnsurePrivateKey();

            var blsSecretKey = default(Bls384Interop.BlsSecretKey);
            int bytesRead;

            unsafe
            {
                fixed(byte *privateKeyPtr = privateKey)
                {
                    bytesRead = Bls384Interop.SecretKeyDeserialize(ref blsSecretKey, privateKeyPtr, privateKey !.Length);
                }
            }

            if (bytesRead != privateKey.Length)
            {
                throw new Exception($"Error deserializing BLS private key, length: {bytesRead}");
            }

            var blsSignature = default(Bls384Interop.BlsSignature);
            int result;

            if (domain.Length > 0)
            {
                if (hash.Length != HashLength)
                {
                    throw new ArgumentOutOfRangeException(nameof(hash), hash.Length,
                                                          $"Hash with domain must be {HashLength} bytes long.");
                }

                if (domain.Length != DomainLength)
                {
                    throw new ArgumentOutOfRangeException(nameof(domain), domain.Length,
                                                          $"Domain must be {DomainLength} bytes long.");
                }

                var hashWithDomain = new Span <byte>(new byte[HashLength + DomainLength]);
                hash.CopyTo(hashWithDomain);
                domain.CopyTo(hashWithDomain.Slice(HashLength));

                unsafe
                {
                    fixed(byte *hashPtr = hashWithDomain)
                    {
                        result = Bls384Interop.SignHashWithDomain(ref blsSignature, ref blsSecretKey, hashPtr);
                    }
                }
            }
            else
            {
                unsafe
                {
                    fixed(byte *hashPtr = hash)
                    {
                        result = Bls384Interop.SignHash(ref blsSignature, ref blsSecretKey, hashPtr, hash.Length);
                    }
                }
            }

            // ReadOnlySpan<byte> hashToSign;
            // if (domain.Length > 0)
            // {
            //     var combined = new byte[2 * InitialXPartLength];
            //     var combineSuccess = TryCombineHashAndDomain(hash, domain, combined, out var combineBytesWritten);
            //     if (!combineSuccess || combineBytesWritten != 2 * InitialXPartLength)
            //     {
            //         throw new Exception("Error combining the hash and domain.");
            //     }
            //     hashToSign = combined;
            // }
            // else
            // {
            //     hashToSign = hash;
            // }
            // unsafe
            // {
            //     fixed (byte* hashPtr = hash)
            //     {
            //         result = Bls384Interop.SignHash(out blsSignature, blsSecretKey, hashPtr, hash.Length);
            //     }
            // }

            if (result != 0)
            {
                throw new Exception($"Error generating BLS signature for hash. Error: {result}");
            }

            unsafe
            {
                fixed(byte *destinationPtr = destination)
                {
                    bytesWritten = Bls384Interop.SignatureSerialize(destinationPtr, SignatureLength, ref blsSignature);
                }
            }

            if (bytesWritten != SignatureLength)
            {
                throw new Exception($"Error serializing BLS signature, length: {bytesWritten}");
            }

            return(true);
        }