Ejemplo n.º 1
0
        public bool TryGetNonce(Span <byte> nonce32, ReadOnlySpan <byte> msg32, ReadOnlySpan <byte> key32, ReadOnlySpan <byte> algo16, uint counter)
        {
            Span <byte> keydata         = stackalloc byte[112];
            Span <byte> originalKeyData = keydata;
            int         offset          = 0;

            using RFC6979HMACSHA256 rng = new RFC6979HMACSHA256();
            uint i;

            /* We feed a byte array to the PRNG as input, consisting of:
             * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d.
             * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data.
             * - optionally 16 extra bytes with the algorithm name.
             * Because the arguments have distinct fixed lengths it is not possible for
             *  different argument mixtures to emulate each other and result in the same
             *  nonces.
             */

            key32.CopyTo(keydata);
            keydata = keydata.Slice(32);
            offset += 32;
            msg32.CopyTo(keydata);
            keydata = keydata.Slice(32);
            offset += 32;
            if (this.data != null)
            {
                this.data.CopyTo(keydata);
                keydata = keydata.Slice(32);
                offset += 32;
            }
            if (algo16.Length == 16)
            {
                algo16.CopyTo(keydata);
                keydata = keydata.Slice(16);
                offset += 16;
            }
            rng.Initialize(originalKeyData.Slice(0, offset));
            originalKeyData.Fill(0);
            for (i = 0; i <= counter; i++)
            {
                rng.Generate(nonce32);
            }
            return(true);
        }
Ejemplo n.º 2
0
        public void Blind(byte[]?seed32 = null)
        {
            Scalar      b;
            GEJ         gb;
            FE          s;
            Span <byte> nonce32 = stackalloc byte[32];

            using RFC6979HMACSHA256 rng = new RFC6979HMACSHA256();
            bool        retry;
            Span <byte> keydata = stackalloc byte[64];

            if (seed32 == null)
            {
                /* When seed is NULL, reset the initial point and blinding value. */
                this.initial = EC.G.ToGroupElementJacobian();
                this.initial = this.initial.Negate();
                this.blind   = new Scalar(1);
            }
            /* The prior blinding value (if not reset) is chained forward by including it in the hash. */
            this.blind.WriteToSpan(nonce32);

            /* Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data,
             *   and guards against weak or adversarial seeds.  This is a simpler and safer interface than
             *   asking the caller for blinding values directly and expecting them to retry on failure.
             */
            nonce32.CopyTo(keydata);
            if (seed32 != null)
            {
                seed32.AsSpan().CopyTo(keydata.Slice(32, 32));
            }
            else
            {
                keydata = keydata.Slice(0, 32);
            }
            rng.Initialize(keydata);
            keydata.Clear();
            /* Retry for out of range results to achieve uniformity. */
            do
            {
                rng.Generate(nonce32);
                retry  = !FE.TryCreate(nonce32, out s);
                retry |= s.IsZero;
            } while (retry);             /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */
            /* Randomize the projection to defend against multiplier sidechannels. */
            this.initial = this.initial.Rescale(s);
            FE.Clear(ref s);
            do
            {
                rng.Generate(nonce32);
                b     = new Scalar(nonce32, out int overflow);
                retry = overflow == 1;
                /* A blinding value of 0 works, but would undermine the projection hardening. */
                retry |= b.IsZero;
            } while (retry);             /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */
            rng.Dispose();
            nonce32.Fill(0);

            gb           = MultGen(b);
            b            = b.Negate();
            this.blind   = b;
            this.initial = gb;
            Scalar.Clear(ref b);
            GEJ.Clear(ref gb);
        }