/// <summary>
/// Constructor which attempts to redeem a completed set of three codes, and calculate the private key.
/// </summary>
public EscrowCodeSet(string code1, string code2, string code3)
{
if (code1 == null || code2 == null || code3 == null || code1 == "" || code2 == "" || code3 == "") {
throw new ArgumentException("Three codes are required to use this function.");
}
string codea = null, codeb=null, codep = null;
if (code1.StartsWith("einva")) codea = code1;
if (code2.StartsWith("einva")) codea = code2;
if (code3.StartsWith("einva")) codea = code3;
if (code1.StartsWith("einvb")) codeb = code1;
if (code2.StartsWith("einvb")) codeb = code2;
if (code3.StartsWith("einvb")) codeb = code3;
if (code1.StartsWith("einvp")) codep = code1;
if (code2.StartsWith("einvp")) codep = code2;
if (code3.StartsWith("einvp")) codep = code3;
if (codea==null || codeb == null || codep == null) {
throw new ArgumentException("In order to use this function, one code MUST be an Escrow Invitation A (starting " +
"with \"einva\"), one must be an Escrow Invitation B (starting with \"einvb\") and the last " +
"code MUST be a Payment Invitation (starting with \"einvp\").");
}
byte[] pubparta, privparta;
int identifier30a;
string failreason = parseEscrowCode(codea, out pubparta, out privparta, out identifier30a);
if (failreason != null) throw new ArgumentException("Escrow Invitation Code A: " + failreason);
byte[] pubpartb, privpartb;
int identifier30b;
failreason = parseEscrowCode(codeb, out pubpartb, out privpartb, out identifier30b);
if (failreason != null) throw new ArgumentException("Escrow Invitation Code B: " + failreason);
if (identifier30a != identifier30b) {
throw new ArgumentException("The two Escrow Invitations are not mates and cannot unlock the private key.");
}
string notvalid = "Not a valid Payment Invitation Code";
string notvalid2 = "Code is not a valid Payment Invitation Code or may have a typo or other error.";
string notvalid3 = "The Payment Invitation does not belong to the provided Escrow Invitation.";
long headp;
byte[] invbytesp;
string failReason = parseEitherCode(codep, notvalid, notvalid2, out invbytesp, out headp);
if (headp < headbaseP) throw new ArgumentException(notvalid);
long identifier30L = headp - headbaseP;
if (identifier30L < 0 || identifier30L > 0x3FFFFFFFL) throw new ArgumentException(notvalid);
if (identifier30L != (long)identifier30a) {
throw new ArgumentException("The Payment Invitation was not generated from either of the provided Escrow Invitation codes and cannot be unlocked by them.");
}
byte[] privpartz = new byte[32];
Array.Copy(invbytesp, 8 + 1 + 1, privpartz, 0, 32);
byte networkByte = invbytesp[8];
bool compressedFlag = (invbytesp[8 + 1 + 1 + 32 + 20] & 0x1) == 1;
// get private key
BigInteger xyz = new BigInteger(1, privparta).Multiply(new BigInteger(1, privpartb)).Multiply(new BigInteger(1, privpartz));
var ps = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
xyz = xyz.Mod(ps.N);
KeyPair kp = new KeyPair(xyz, compressedFlag, networkByte);
// provide everything
this.EscrowInvitationCodeA = codea;
this.EscrowInvitationCodeB = codeb;
this.PaymentInvitationCode = codep;
this.BitcoinAddress = kp.AddressBase58;
this.PrivateKey = kp.PrivateKey;
}