aboutsummaryrefslogtreecommitdiff
path: root/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptSigner.cs
blob: 586fa46a63555b1520f8d587d1e8262be0fdb6ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (C) 2024 Vaughn Nugent
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

using System;

using VNLib.Utils.Extensions;
using VNLib.Utils.Memory;

using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary;

namespace VNLib.Utils.Cryptography.Noscrypt
{
    /// <summary>
    /// A simple wrapper class to sign nostr message data using 
    /// the noscrypt library
    /// </summary>
    /// <param name="noscrypt">The noscrypt library instance</param>
    /// <param name="random">A random entropy pool used to source random data for signature entropy</param>
    public class NoscryptSigner(INostrCrypto noscrypt, IRandomSource random)
    {
        /// <summary>
        /// Gets the size of the buffer required to hold the signature
        /// </summary>
        public static int SignatureBufferSize => NC_SIGNATURE_SIZE;

        /// <summary>
        /// Signs a message using the specified private key and message data
        /// </summary>
        /// <param name="hexPrivateKey">The hexadecimal private key used to sign the message</param>
        /// <param name="message">The message data to sign</param>
        /// <param name="format">A encoder used to convert the signature data to an encoded string</param>
        /// <returns>The string encoded nostr signature</returns>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public string SignData(string hexPrivateKey, ReadOnlySpan<byte> message, INostrSignatureEncoder? format = null)
        {
            ArgumentException.ThrowIfNullOrWhiteSpace(hexPrivateKey);
            ArgumentOutOfRangeException.ThrowIfNotEqual(hexPrivateKey.Length / 2, NC_SEC_KEY_SIZE, nameof(hexPrivateKey));

            //Have to allocate array unfortunately
            byte[] privKey = Convert.FromHexString(hexPrivateKey);
            try
            {
                return SignData(privKey.AsSpan(), message, format);
            }
            finally
            {
                //Always zero key beofre leaving
                MemoryUtil.InitializeBlock(privKey);
            }
        }

        /// <summary>
        /// Signs a message using the specified secret key and message data
        /// </summary>
        /// <param name="secretKey">The secret key data buffer</param>
        /// <param name="message">The message data to sign</param>
        /// <param name="format">A encoder used to convert the signature data to an encoded string</param>
        /// <returns>The string encoded nostr signature</returns>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public string SignData(
            ReadOnlySpan<byte> secretKey, 
            ReadOnlySpan<byte> message, 
            INostrSignatureEncoder? format = null
        )
        {
            return SignData(in NCUtil.AsSecretKey(secretKey), message, format);
        }

        /// <summary>
        /// Signs a message using the specified secret key and message data
        /// </summary>
        /// <param name="secretkey">A reference to the secret key structurer</param>
        /// <param name="message">The message data to sign</param>
        /// <param name="format">A encoder used to convert the signature data to an encoded string</param>
        /// <returns>The string encoded nostr signature</returns>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public string SignData(
            ref readonly NCSecretKey secretkey, 
            ReadOnlySpan<byte> message, 
            INostrSignatureEncoder? format = null
        )
        {
            //Default to hex encoding because that is the default NIP-01 format
            format ??= HexSignatureEncoder.Instance;

            Span<byte> sigBuffer = stackalloc byte[SignatureBufferSize];

            SignData(message, sigBuffer);

            return format.GetString(sigBuffer);
        }


        /// <summary>
        /// Signs a message using the specified secret key and message data
        /// </summary>
        /// <param name="secretkey">A reference to the secret key structurer</param>
        /// <param name="data">The message data to sign</param>
        /// <param name="signature">A buffer to write signature data to</param>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public void SignData(
            ref readonly NCSecretKey secretkey, 
            ReadOnlySpan<byte> data, 
            Span<byte> signature
        )
        {
            ArgumentOutOfRangeException.ThrowIfLessThan(signature.Length, NC_SIGNATURE_SIZE, nameof(signature));

            //Signature generation required random entropy to be secure
            Span<byte> entropy = stackalloc byte[NC_SIG_ENTROPY_SIZE];
            random.GetRandomBytes(entropy);

            noscrypt.SignData(in secretkey, entropy, data, signature);
        }
    }

}