in UProveCrypto/PresentationProof.cs [337:530]
internal static PresentationProof Generate(IssuerParameters ip, int[] disclosed, int[] committed, int pseudonymAttribIndex, GroupElement gs, byte[] message, byte[] messageD, IDevicePresentationContext deviceContext, UProveKeyAndToken upkt, byte[][] attributes, ProofGenerationRandomData preGenW, out CommitmentPrivateValues cpv)
{
if (upkt.Token.IsDeviceProtected && deviceContext == null)
{
throw new ArgumentNullException("Device context is not initialized");
}
bool generateCommitments = (committed != null && committed.Length > 0);
FieldZqElement[] tildeO = null;
// make sure disclosed and committed lists are sorted
if (disclosed == null)
{
// can't be null later, so make it an empty array
disclosed = new int[] { };
}
Array.Sort(disclosed);
if (generateCommitments)
{
Array.Sort(committed);
}
int n = 0;
if (ip.E != null)
{
n = ip.E.Length;
if (n != attributes.Length)
{
throw new ArgumentException("number of attributes is inconsistent with issuer parameters");
}
}
bool presentPseudonym = false;
if (gs != null)
{
if (pseudonymAttribIndex < 1 || (pseudonymAttribIndex > n && pseudonymAttribIndex != DeviceAttributeIndex))
{
throw new ArgumentException("pseudonymAttribIndex must be between 1 and " + n + " (inclusive)");
}
if (disclosed.Contains(pseudonymAttribIndex))
{
throw new ArgumentException("pseudonymAttribIndex cannot be in the disclosed attribute array");
}
presentPseudonym = true;
}
else if (pseudonymAttribIndex > 0)
{
throw new ArgumentNullException("gs is null");
}
else
{
pseudonymAttribIndex = 0;
}
Group Gq = ip.Gq;
FieldZq Zq = ip.Zq;
FieldZqElement xt = ProtocolHelper.ComputeXt(ip, upkt.Token.TI, upkt.Token.IsDeviceProtected);
ProofGenerationRandomData random;
if (preGenW == null)
{
random = ProofGenerationRandomData.Generate(n - disclosed.Length, generateCommitments ? committed.Length : 0, Zq, upkt.Token.IsDeviceProtected);
}
else
{
random = preGenW;
}
// set up the multi-exponentiation arrays, with h^w0 as the first term
int multiExpArraySize = 1 + (n - disclosed.Length) + (upkt.Token.IsDeviceProtected ? 1 : 0);
GroupElement[] bases = new GroupElement[multiExpArraySize];
FieldZqElement[] exponents = new FieldZqElement[multiExpArraySize];
int multiExpIndex = 0;
bases[multiExpIndex] = upkt.Token.H;
exponents[multiExpIndex++] = random.W0;
FieldZqElement[] x = new FieldZqElement[n];
int uIndex = 0;
int dIndex = 0;
int cIndex = 0;
PresentationProof proof = new PresentationProof();
proof.DisclosedAttributes = new byte[disclosed.Length][];
int pseudonymRandomizerIndex = 0;
if (generateCommitments)
{
proof.Commitments = new CommitmentValues[committed.Length];
tildeO = new FieldZqElement[committed.Length];
}
HashFunction hash = ip.HashFunction;
GroupElement[] cBases = new GroupElement[2] { Gq.G, ip.G[1] };
for (int i = 0; i < n; i++)
{
x[i] = ProtocolHelper.ComputeXi(ip, i, attributes[i]);
if (!disclosed.Contains(i + 1))
{
bases[multiExpIndex] = ip.G[i + 1];
exponents[multiExpIndex++] = random.W[uIndex];
if (presentPseudonym)
{
if (pseudonymAttribIndex == (i + 1))
{
pseudonymRandomizerIndex = uIndex;
}
}
if (generateCommitments && committed.Contains(i + 1))
{
GroupElement tildeC = ip.Gq.MultiExponentiate(cBases, new FieldZqElement[2] { x[i], random.TildeO[cIndex] });
tildeO[cIndex] = random.TildeO[cIndex];
GroupElement temp2 = ip.Gq.MultiExponentiate(cBases, new FieldZqElement[2] { random.W[uIndex], random.TildeW[cIndex] });
hash.Hash(temp2);
byte[] tildeA = hash.Digest;
proof.Commitments[cIndex] = new CommitmentValues(tildeC, tildeA, null);
cIndex++;
}
uIndex++;
}
else if (generateCommitments && committed.Contains(i + 1))
{
throw new ArgumentException("attribute " + (i + 1) + " cannot be both disclosed and committed");
}
else
{
proof.DisclosedAttributes[dIndex] = attributes[i];
dIndex++;
}
}
GroupElement aPreImage;
if (upkt.Token.IsDeviceProtected)
{
GroupElement ad;
// pseudonym computed by device
if (presentPseudonym && pseudonymAttribIndex == DeviceAttributeIndex)
{
GroupElement apPrime;
GroupElement Ps;
ad = deviceContext.GetInitialWitnessesAndPseudonym(gs, out apPrime, out Ps);
hash.Hash(apPrime * gs.Exponentiate(random.Wd));
proof.Ap = hash.Digest;
proof.Ps = Ps;
}
else
{
ad = deviceContext.GetInitialWitness();
}
bases[multiExpIndex] = ip.Gd;
exponents[multiExpIndex++] = random.Wd;
aPreImage = Gq.MultiExponentiate(bases, exponents) * ad;
}
else
{
aPreImage = Gq.MultiExponentiate(bases, exponents);
}
hash.Hash(aPreImage);
proof.a = hash.Digest;
// pseudonym derived from one token attribute
if (presentPseudonym && pseudonymAttribIndex != DeviceAttributeIndex)
{
hash.Hash(gs.Exponentiate(random.W[pseudonymRandomizerIndex]));
proof.Ap = hash.Digest;
proof.Ps = gs.Exponentiate(x[pseudonymAttribIndex - 1]);
}
byte[] mdPrime;
FieldZqElement c = ProtocolHelper.GenerateChallenge(ip, upkt.Token, proof.a, pseudonymAttribIndex, proof.ap, proof.Ps, message, messageD, disclosed, GetDisclosedX(disclosed, x), committed, proof.Commitments, out mdPrime);
proof.r = new FieldZqElement[1 + n - disclosed.Length + (upkt.Token.IsDeviceProtected ? 1 : 0)]; // r_0, {r_i} for undisclosed i, r_d
proof.r[0] = c * upkt.PrivateKey + random.W0;
uIndex = 1;
for (int i = 1; i <= n; i++)
{
if (!disclosed.Contains(i))
{
proof.r[uIndex] = c.Negate() * x[i - 1] + random.W[uIndex - 1];
uIndex++;
}
}
if (upkt.Token.IsDeviceProtected)
{
proof.r[proof.r.Length - 1] = deviceContext.GetDeviceResponse(messageD, mdPrime, ip.HashFunctionOID) + random.Wd;
}
if (generateCommitments)
{
for (int i = 0; i < committed.Length; i++)
{
proof.Commitments[i].TildeR = c.Negate() * random.TildeO[i] + random.TildeW[i];
}
}
random.Clear();
cpv = new CommitmentPrivateValues(tildeO);
return proof;
}