Add TupleWith
MODIFY
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/KnowledgeOfRepresentationTests.cs
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/KnowledgeOfRepresentationTests.cs
using NBitcoin.Secp256k1;
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Text;
using WalletWasabi.Crypto.Groups;
using WalletWasabi.Crypto.ZeroKnowledge;
@@ -24,13 +25,10 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
var secrets = new[] { new Scalar(scalarSeed1), new Scalar(scalarSeed2) };
var generators = new[] { Generators.G, Generators.Ga };
var publicPoint = GroupElement.Infinity;
- var secretGeneratorPairs = new List<(Scalar, GroupElement)>();
- for (int i = 0; i < secrets.Length; i++)
+ var secretGeneratorPairs = secrets.TupleWith(generators);
+ foreach (var (secret, generator) in secretGeneratorPairs)
{
- Scalar secret = secrets[i];
- GroupElement generator = generators[i];
publicPoint += secret * generator;
- secretGeneratorPairs.Add((secret, generator));
}
var proof = Prover.CreateProof(secretGeneratorPairs, publicPoint);
Assert.True(Verifier.Verify(proof, publicPoint, generators));

MODIFY
WalletWasabi.Tests/UnitTests/LinqExtensionsTests.cs
WalletWasabi.Tests/UnitTests/LinqExtensionsTests.cs
+using System;
+using System.Collections.Generic;
using System.Linq;
using Xunit;
@@ -67,5 +69,24 @@ namespace WalletWasabi.Tests.UnitTests
Assert.Equal("0, 2, 3, 4", asString[i++]);
Assert.Equal("1, 2, 3, 4", asString[i++]);
}
+
+ [Fact]
+ public void TuplingTests()
+ {
+ var collection1 = new int[] { 1, 3, 5, 14 };
+ var collection2 = new int[] { 7, 11, 13 };
+ Assert.ThrowsAny<InvalidOperationException>(() => collection1.TupleWith(collection2));
+ collection1 = new int[] { 1, 3, 5, 14 };
+ collection2 = new int[] { 7, 11, 13, 1, 2 };
+ Assert.ThrowsAny<InvalidOperationException>(() => collection1.TupleWith(collection2));
+ collection1 = new int[] { 1, 3, 5, 14, 3 };
+ collection2 = new int[] { 7, 11, 13, 1, 2 };
+ var tuple = collection1.TupleWith(collection2).ToArray();
+ for (int i = 0; i < tuple.Length; i++)
+ {
+ Assert.Equal(collection1[i], tuple[i].Item1);
+ Assert.Equal(collection2[i], tuple[i].Item2);
+ }
+ }
}
}

MODIFY
WalletWasabi/Crypto/ZeroKnowledge/Prover.cs
WalletWasabi/Crypto/ZeroKnowledge/Prover.cs
@@ -48,13 +48,11 @@ namespace WalletWasabi.Crypto.ZeroKnowledge
var challenge = Challenge.HashToScalar(new[] { publicPoint, nonce }.Concat(secretGeneratorPairs.Select(x => x.generator)));
- var secretArray = secretGeneratorPairs.Select(x => x.secret).ToArray();
- var randomScalarArray = randomScalars.ToArray();
var responses = new List<Scalar>();
- for (int i = 0; i < secretArray.Length; i++)
+ foreach (var (secret, randomScalar) in secretGeneratorPairs
+ .Select(x => x.secret)
+ .TupleWith(randomScalars))
{
- var secret = secretArray[i];
- var randomScalar = randomScalarArray[i];
var response = randomScalar + secret * challenge;
responses.Add(response);
}

MODIFY
WalletWasabi/Crypto/ZeroKnowledge/Verifier.cs
WalletWasabi/Crypto/ZeroKnowledge/Verifier.cs
@@ -33,15 +33,12 @@ namespace WalletWasabi.Crypto.ZeroKnowledge
var nonce = proof.Nonce;
var responses = proof.Responses.ToArray();
- var challenge = Challenge.HashToScalar(new[] { publicPoint, nonce }.Concat(generators).ToArray());
+ var challenge = Challenge.HashToScalar(new[] { publicPoint, nonce }.Concat(generators));
var a = challenge * publicPoint + nonce;
var b = GroupElement.Infinity;
- for (int i = 0; i < responses.Length; i++)
+ foreach (var (response, generator) in responses.TupleWith(generators))
{
- var response = responses[i];
- var generator = generators.ToArray()[i];
-
b += response * generator;
}
return a == b;

MODIFY
WalletWasabi/Extensions/LinqExtensions.cs
WalletWasabi/Extensions/LinqExtensions.cs
@@ -228,5 +228,17 @@ namespace System.Linq
.GroupBy(x => x.Index / chunkSize)
.Select(x => x.Select(v => v.Value));
}
+
+ /// <summary>
+ /// Creates a tuple collection from two collections. If lengths differ, exception is thrown.
+ /// </summary>
+ public static IEnumerable<(T1, T2)> TupleWith<T1, T2>(this IEnumerable<T1> source, IEnumerable<T2> otherCollection)
+ {
+ if (source.Count() != otherCollection.Count())
+ {
+ throw new InvalidOperationException($"{nameof(source)} and {nameof(otherCollection)} collections must have the same number of elements. {nameof(source)}:{source.Count()}, {nameof(otherCollection)}:{otherCollection.Count()}.");
+ }
+ return source.Zip(otherCollection, (x, y) => (x, y));
+ }
}
}

Add TupleWith