Skip to content

Commit 1a4fc21

Browse files
Add a new scalar method to set and verity a private key
1 parent cf5b429 commit 1a4fc21

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

Src/Autarkysoft.Bitcoin/Cryptography/EllipticCurve/Scalar8x32.cs

+17
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,23 @@ public bool IsHigh
296296
}
297297

298298

299+
/// <summary>
300+
/// Creates a new instance of <see cref="Scalar8x32"/> using the given big-endian array
301+
/// and reduces the result modulo curve order (n).
302+
/// Return value indicates validity of the result as a private key.
303+
/// </summary>
304+
/// <param name="data">Array to use</param>
305+
/// <param name="res">Scalar</param>
306+
/// <returns>True if value was non-zero and smaller than curve order; otherwise false</returns>
307+
public static bool TrySetPrivateKey(ReadOnlySpan<byte> data, out Scalar8x32 res)
308+
{
309+
// secp256k1_scalar_set_b32_seckey
310+
res = new Scalar8x32(data, out bool overflow);
311+
Debug.Assert(res.Verify());
312+
return !overflow && !res.IsZero;
313+
}
314+
315+
299316
/// <summary>
300317
/// Multiply a scalar with the multiplicative inverse of 2
301318
/// </summary>

Src/Tests/Bitcoin/Cryptography/EllipticCurve/Scalar8x32Tests.cs

+52
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,32 @@ internal static Scalar8x32 CreateRandom(TestRNG rng)
473473
} while (true);
474474
}
475475

476+
/// <summary>
477+
/// random_scalar_order
478+
/// </summary>
479+
private static Scalar8x32 RandomScalarOrder(TestRNG rng)
480+
{
481+
do
482+
{
483+
byte[] b32 = new byte[32];
484+
rng.Rand256(b32);
485+
Scalar8x32 num = new(b32, out bool overflow);
486+
if (!overflow && !num.IsZero)
487+
{
488+
return num;
489+
}
490+
} while (true);
491+
}
492+
493+
/// <summary>
494+
/// random_scalar_order_b32
495+
/// </summary>
496+
private static byte[] RandomScalarOrderB32(TestRNG rng)
497+
{
498+
Scalar8x32 num = RandomScalarOrder(rng);
499+
return num.ToByteArray();
500+
}
501+
476502
// scalar_test(void)
477503
private static unsafe void ScalarTest(TestRNG rng)
478504
{
@@ -622,6 +648,27 @@ private static unsafe void ScalarTest(TestRNG rng)
622648
}
623649
}
624650

651+
652+
// run_scalar_set_b32_seckey_tests
653+
private static void SetB32SeckeyTests(TestRNG rng)
654+
{
655+
// Usually set_b32 and set_b32_seckey give the same result
656+
Span<byte> b32 = RandomScalarOrderB32(rng);
657+
658+
Scalar8x32 s1 = new(b32, out _);
659+
bool b = Scalar8x32.TrySetPrivateKey(b32, out Scalar8x32 s2);
660+
Assert.True(b);
661+
Assert.True(s1.Equals(s2));
662+
663+
b32.Clear(); // b32.Fill(0);
664+
b = Scalar8x32.TrySetPrivateKey(b32, out _);
665+
Assert.False(b);
666+
667+
b32.Fill(0xff);
668+
b = Scalar8x32.TrySetPrivateKey(b32, out _);
669+
Assert.False(b);
670+
}
671+
625672
[Fact]
626673
public void Libsecp256k1Tests() // run_scalar_tests
627674
{
@@ -633,6 +680,11 @@ public void Libsecp256k1Tests() // run_scalar_tests
633680
ScalarTest(rng);
634681
}
635682

683+
for (int i = 0; i < Count; i++)
684+
{
685+
SetB32SeckeyTests(rng);
686+
}
687+
636688
// Check that the scalar constants secp256k1_scalar_zero and
637689
// secp256k1_scalar_one contain the expected values.
638690
// Note: these are tested in StaticPropTest()

0 commit comments

Comments
 (0)