Example #1
0
        /// <inheritdoc />
        public override bool TryAggregateSignatures(ReadOnlySpan <byte> signatures, Span <byte> destination, out int bytesWritten)
        {
            // This is independent of the keys set, although other parameters (type of curve, variant, scheme, etc) are relevant.
            if (signatures.Length % SignatureLength != 0)
            {
                throw new ArgumentOutOfRangeException(nameof(signatures), signatures.Length, $"Signature data must be a multiple of the signature length {SignatureLength}.");
            }
            if (destination.Length < SignatureLength)
            {
                bytesWritten = 0;
                return(false);
            }

            EnsureInitialised();

            var aggregateBlsSignature = default(Bls384Interop.BlsSignature);

            for (var index = 0; index < signatures.Length; index += SignatureLength)
            {
                var signatureSlice = signatures.Slice(index, SignatureLength);
                var blsSignature   = default(Bls384Interop.BlsSignature);
                int signatureBytesRead;
                unsafe
                {
                    // Using fixed pointer for input data allows us to pass a slice
                    fixed(byte *signaturePtr = signatureSlice)
                    {
                        signatureBytesRead = Bls384Interop.SignatureDeserialize(ref blsSignature, signaturePtr, SignatureLength);
                    }
                }
                if (signatureBytesRead != SignatureLength)
                {
                    throw new Exception($"Error deserializing BLS signature, length: {signatureBytesRead}");
                }
                if (index == 0)
                {
                    aggregateBlsSignature = blsSignature;
                }
                else
                {
                    Bls384Interop.SignatureAdd(ref aggregateBlsSignature, ref blsSignature);
                }
            }

            unsafe
            {
                // Using fixed pointer for output data allows us to write directly to destination
                fixed(byte *destinationPtr = destination)
                {
                    bytesWritten = Bls384Interop.SignatureSerialize(destinationPtr, SignatureLength, ref aggregateBlsSignature);
                }
            }
            if (bytesWritten != SignatureLength)
            {
                throw new Exception($"Error serializing BLS signature, length: {bytesWritten}");
            }
            return(true);
        }
        /// <inheritdoc />
        public override bool VerifyHash(ReadOnlySpan <byte> hash, ReadOnlySpan <byte> signature, ReadOnlySpan <byte> domain = default)
        {
            if (signature.Length != SignatureLength)
            {
                throw new ArgumentOutOfRangeException(nameof(signature), signature.Length, $"Signature must be {SignatureLength} bytes long.");
            }

            EnsureInitialised();
            EnsurePublicKey();

            Bls384Interop.BlsPublicKey blsPublicKey;
            int publicKeyBytesRead;

            unsafe
            {
                fixed(byte *publicKeyPtr = _publicKey)
                {
                    publicKeyBytesRead = Bls384Interop.PublicKeyDeserialize(out blsPublicKey, publicKeyPtr, _publicKey !.Length);
                }
            }
            if (publicKeyBytesRead != _publicKey.Length)
            {
                throw new Exception($"Error deserializing BLS public key, length: {publicKeyBytesRead}");
            }

            Bls384Interop.BlsSignature blsSignature;
            int signatureBytesRead;

            unsafe
            {
                fixed(byte *signaturePtr = signature)
                {
                    signatureBytesRead = Bls384Interop.SignatureDeserialize(out blsSignature, signaturePtr, SignatureLength);
                }
            }
            if (signatureBytesRead != signature.Length)
            {
                throw new Exception($"Error deserializing BLS signature, length: {signatureBytesRead}");
            }

            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.VerifyHashWithDomain(blsSignature, blsPublicKey, hashPtr);
                    }
                }
            }
            else
            {
                unsafe
                {
                    fixed(byte *hashPtr = hash)
                    {
                        result = Bls384Interop.VerifyHash(blsSignature, blsPublicKey, hashPtr, hash.Length);
                    }
                }
            }

            return(result == 1);
        }
        /// <inheritdoc />
        public override bool VerifyAggregate(ReadOnlySpan <byte> publicKeys, ReadOnlySpan <byte> hashes, ReadOnlySpan <byte> aggregateSignature, ReadOnlySpan <byte> domain = default)
        {
            // This is independent of the keys set, although other parameters (type of curve, variant, scheme, etc) are relevant.

            if (aggregateSignature.Length != SignatureLength)
            {
                throw new ArgumentOutOfRangeException(nameof(aggregateSignature), aggregateSignature.Length, $"Signature must be {SignatureLength} bytes long.");
            }
            if (publicKeys.Length % PublicKeyLength != 0)
            {
                throw new ArgumentOutOfRangeException(nameof(publicKeys), publicKeys.Length, $"Public key data must be a multiple of the public key length {PublicKeyLength}.");
            }
            var publicKeyCount = publicKeys.Length / PublicKeyLength;

            if (hashes.Length % publicKeyCount != 0)
            {
                throw new ArgumentOutOfRangeException(nameof(hashes), hashes.Length, $"Hashes must all be the same length, with total bytes evenly divisble by the number of public keys, {publicKeyCount}.");
            }

            EnsureInitialised();

            var blsPublicKeys   = new Bls384Interop.BlsPublicKey[publicKeyCount];
            var publicKeysIndex = 0;

            for (var blsPublicKeyIndex = 0; blsPublicKeyIndex < publicKeyCount; blsPublicKeyIndex++)
            {
                var publicKey = publicKeys.Slice(publicKeysIndex, PublicKeyLength);
                int publicKeyBytesRead;
                unsafe
                {
                    fixed(byte *publicKeyPtr = publicKey)
                    {
                        publicKeyBytesRead = Bls384Interop.PublicKeyDeserialize(out blsPublicKeys[blsPublicKeyIndex], publicKeyPtr, PublicKeyLength);
                    }
                }
                if (publicKeyBytesRead != PublicKeyLength)
                {
                    throw new Exception($"Error deserializing BLS public key {blsPublicKeyIndex}, length: {publicKeyBytesRead}");
                }
                publicKeysIndex += PublicKeyLength;
            }

            Bls384Interop.BlsSignature aggregateBlsSignature;
            int signatureBytesRead;

            unsafe
            {
                fixed(byte *signaturePtr = aggregateSignature)
                {
                    signatureBytesRead = Bls384Interop.SignatureDeserialize(out aggregateBlsSignature, signaturePtr, SignatureLength);
                }
            }
            if (signatureBytesRead != aggregateSignature.Length)
            {
                throw new Exception($"Error deserializing BLS signature, length: {signatureBytesRead}");
            }

            int result;
            var hashLength = hashes.Length / publicKeyCount;

            if (domain.Length > 0)
            {
                if (hashLength != HashLength)
                {
                    throw new ArgumentOutOfRangeException(nameof(hashes), hashes.Length, $"Hashes with domain must have total length {publicKeyCount * HashLength} (each should be {HashLength} bytes long, for {publicKeyCount} public keys).");
                }
                if (domain.Length != DomainLength)
                {
                    throw new ArgumentOutOfRangeException(nameof(domain), domain.Length, $"Domain must be {DomainLength} bytes long.");
                }

                var combined      = new Span <byte>(new byte[publicKeyCount * (HashLength + DomainLength)]);
                var combinedIndex = 0;
                for (var hashIndex = 0; hashIndex < hashes.Length; hashIndex += HashLength)
                {
                    var hashSlice = hashes.Slice(hashIndex, HashLength);
                    hashSlice.CopyTo(combined.Slice(combinedIndex));
                    combinedIndex += HashLength;
                    domain.CopyTo(combined.Slice(combinedIndex));
                    combinedIndex += DomainLength;
                }

                unsafe
                {
                    fixed(byte *hashPtr = combined)
                    {
                        result = Bls384Interop.VerifyAggregatedHashWithDomain(aggregateBlsSignature, blsPublicKeys, hashPtr, publicKeyCount);
                    }
                }
            }
            else
            {
                unsafe
                {
                    fixed(byte *hashPtr = hashes)
                    {
                        result = Bls384Interop.VerifyAggregateHashes(aggregateBlsSignature, blsPublicKeys, hashPtr, hashLength, publicKeyCount);
                    }
                }
            }

            return(result == 1);
        }