private void btnVerify_Click(object sender, EventArgs e) { BInteger p = new BInteger("6277101735386680763835789423207666416083908700390324961279", 10); BInteger a = new BInteger("-3", 10); BInteger b = new BInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16); byte[] xG = FromHexStringToByte("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"); BInteger n = new BInteger("ffffffffffffffffffffffff99def836146bc9b1b4d22831", 16); DSGost DS = new DSGost(p, a, b, n, xG); GOST hash = new GOST(256); long start = DateTime.Now.Second * 1000 + DateTime.Now.Millisecond; byte[] H = hash.GetHash(System.Text.Encoding.Default.GetBytes(textBoxText.Text)); bool result = DS.SingVer(H, textBox2Hash.Text, Q); long finish = DateTime.Now.Second * 1000 + DateTime.Now.Millisecond; long time = finish - start; if (result) { labelIsCorrect.ForeColor = Color.Green; labelIsCorrect.Text = "Correct"; } else { labelIsCorrect.ForeColor = Color.Red; labelIsCorrect.Text = "Wrong"; } }
private void btnSign_Click(object sender, EventArgs e) { BInteger p = new BInteger("6277101735386680763835789423207666416083908700390324961279", 10); BInteger a = new BInteger("-3", 10); BInteger b = new BInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16); byte[] xG = FromHexStringToByte("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"); BInteger n = new BInteger("ffffffffffffffffffffffff99def836146bc9b1b4d22831", 16); DSGost DS = new DSGost(p, a, b, n, xG); d = DS.GenPrivateKey(192); Q = DS.GenPublicKey(d); GOST hash = new GOST(256); byte[] H = hash.GetHash(System.Text.Encoding.Default.GetBytes(textBoxText.Text)); string sign = DS.SingGen(H, d); textBox2Hash.Text = sign; bool result = DS.SingVer(H, sign, Q); }
private void btnTest_Click(object sender, EventArgs e) { BInteger p = new BInteger("3623986102229003635907788753683874306021320925534678605086546150450856166624002482588482022271496854025090823603058735163734263822371964987228582907372403", 10); BInteger x = new BInteger("1928356944067022849399309401243137598997786635459507974357075491307766592685835441065557681003184874819658004903212332884252335830250729527632383493573274", 10); BInteger y = new BInteger("2288728693371972859970012155529478416353562327329506180314497425931102860301572814141997072271708807066593850650334152381857347798885864807605098724013854", 10); BInteger a = new BInteger(7); BInteger b = new BInteger("1518655069210828534508950034714043154928747527740206436194018823352809982443793732829756914785974674866041605397883677596626326413990136959047435811826396", 10); BInteger k = new BInteger("175516356025850499540628279921125280333451031747737791650208144243182057075034446102986750962508909227235866126872473516807810541747529710309879958632945", 10); ECPoint P1 = new ECPoint(); P1.a = a; P1.b = b; P1.FieldChar = p; P1.x = x; P1.y = y; ECPoint P3 = ECPoint.multiply(k, P1); BInteger r = P3.x % p; /////// DS forming BInteger q = new BInteger("3623986102229003635907788753683874306021320925534678605086546150450856166623969164898305032863068499961404079437936585455865192212970734808812618120619743", 10); BInteger d = new BInteger("610081804136373098219538153239847583006845519069531562982388135354890606301782255383608393423372379057665527595116827307025046458837440766121180466875860", 10); BInteger E = new BInteger("2897963881682868575562827278553865049173745197871825199562947419041388950970536661109553499954248733088719748844538964641281654463513296973827706272045964", 10); BInteger s = ((r * d) + (k * E)) % q; //////// DS verification BInteger v = E.modInverse(q); BInteger z = (s * v) % q; BInteger z2 = q + ((-(r * v)) % q); BInteger x1 = new BInteger("909546853002536596556690768669830310006929272546556281596372965370312498563182320436892870052842808608262832456858223580713780290717986855863433431150561", 10); BInteger y1 = new BInteger(" 2921457203374425620632449734248415455640700823559488705164895837509539134297327397380287741428246088626609329139441895016863758984106326600572476822372076", 10); ECPoint Q = new ECPoint(); Q.a = a; Q.b = b; Q.x = x1; Q.y = y1; Q.FieldChar = p; ECPoint A = ECPoint.multiply(z, P1); ECPoint B = ECPoint.multiply(z2, Q); ECPoint C = A + B; }
public BInteger(BInteger bi) { data = new uint[maxLength]; dataLength = bi.dataLength; for (int i = 0; i < dataLength; i++) data[i] = bi.data[i]; }
private static void multiByteDivide(BInteger bi1, BInteger bi2, BInteger outQuotient, BInteger outRemainder) { uint[] result = new uint[maxLength]; int remainderLen = bi1.dataLength + 1; uint[] remainder = new uint[remainderLen]; uint mask = 0x80000000; uint val = bi2.data[bi2.dataLength - 1]; int shift = 0, resultPos = 0; while (mask != 0 && (val & mask) == 0) { shift++; mask >>= 1; } for (int i = 0; i < bi1.dataLength; i++) remainder[i] = bi1.data[i]; shiftLeft(remainder, shift); bi2 = bi2 << shift; int j = remainderLen - bi2.dataLength; int pos = remainderLen - 1; ulong firstDivisorByte = bi2.data[bi2.dataLength - 1]; ulong secondDivisorByte = bi2.data[bi2.dataLength - 2]; int divisorLen = bi2.dataLength + 1; uint[] dividendPart = new uint[divisorLen]; while (j > 0) { ulong dividend = ((ulong)remainder[pos] << 32) + remainder[pos - 1]; //Console.WriteLine("dividend = {0}", dividend); ulong q_hat = dividend / firstDivisorByte; ulong r_hat = dividend % firstDivisorByte; //Console.WriteLine("q_hat = {0:X}, r_hat = {1:X}", q_hat, r_hat); bool done = false; while (!done) { done = true; if (q_hat == 0x100000000 || (q_hat * secondDivisorByte) > ((r_hat << 32) + remainder[pos - 2])) { q_hat--; r_hat += firstDivisorByte; if (r_hat < 0x100000000) done = false; } } for (int h = 0; h < divisorLen; h++) dividendPart[h] = remainder[pos - h]; BInteger kk = new BInteger(dividendPart); BInteger ss = bi2 * (long)q_hat; //Console.WriteLine("ss before = " + ss); while (ss > kk) { q_hat--; ss -= bi2; //Console.WriteLine(ss); } BInteger yy = kk - ss; for (int h = 0; h < divisorLen; h++) remainder[pos - h] = yy.data[bi2.dataLength - h]; result[resultPos++] = (uint)q_hat; pos--; j--; } outQuotient.dataLength = resultPos; int y = 0; for (int x = outQuotient.dataLength - 1; x >= 0; x--, y++) outQuotient.data[y] = result[x]; for (; y < maxLength; y++) outQuotient.data[y] = 0; while (outQuotient.dataLength > 1 && outQuotient.data[outQuotient.dataLength - 1] == 0) outQuotient.dataLength--; if (outQuotient.dataLength == 0) outQuotient.dataLength = 1; outRemainder.dataLength = shiftRight(remainder, shift); for (y = 0; y < outRemainder.dataLength; y++) outRemainder.data[y] = remainder[y]; for (; y < maxLength; y++) outRemainder.data[y] = 0; }
public static BInteger operator ~(BInteger bi1) { BInteger result = new BInteger(bi1); for (int i = 0; i < maxLength; i++) result.data[i] = ~(bi1.data[i]); result.dataLength = maxLength; while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) result.dataLength--; return result; }
public static BInteger operator <<(BInteger bi1, int shiftVal) { BInteger result = new BInteger(bi1); result.dataLength = shiftLeft(result.data, shiftVal); return result; }
public static BInteger operator --(BInteger bi1) { BInteger result = new BInteger(bi1); long val; bool carryIn = true; int index = 0; while (carryIn && index < maxLength) { val = result.data[index]; val--; result.data[index] = (uint)(val & 0xFFFFFFFF); if (val >= 0) carryIn = false; index++; } if (index > result.dataLength) result.dataLength = index; while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) result.dataLength--; int lastPos = maxLength - 1; if ((bi1.data[lastPos] & 0x80000000) != 0 && (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) { throw (new ArithmeticException("Underflow in --.")); } return result; }
//проверяем подпись public bool SingVer(byte[] H, string sing, ECPoint Q) { string Rvector = sing.Substring(0, n.bitCount() / 4); string Svector = sing.Substring(n.bitCount() / 4, n.bitCount() / 4); BInteger r = new BInteger(Rvector, 16); BInteger s = new BInteger(Svector, 16); if ((r < 1) || (r > (n - 1)) || (s < 1) || (s > (n - 1))) return false; BInteger alpha = new BInteger(H); BInteger e = alpha % n; if (e == 0) e = 1; BInteger v = e.modInverse(n); BInteger z1 = (s * v) % n; BInteger z2 = n + ((-(r * v)) % n); this.G = GDecompression(); ECPoint A = ECPoint.multiply(z1, G); ECPoint B = ECPoint.multiply(z2, Q); ECPoint C = A + B; BInteger R = C.x % n; if (R == r) return true; else return false; }
//умножение точки на число x, по сути своей представляет x сложений точки самой с собой public static ECPoint multiply(BInteger x, ECPoint p) { ECPoint temp = p; x = x - 1; while (x != 0) { if ((x % 2) != 0) { if ((temp.x == p.x) || (temp.y == p.y)) temp = Double(temp); else temp = temp + p; x = x - 1; } x = x / 2; p = Double(p); } return temp; }
public ECPoint() { x = new BInteger(); y = new BInteger(); a = new BInteger(); b = new BInteger(); FieldChar = new BInteger(); }
public ECPoint(ECPoint p) { x = p.x; y = p.y; a = p.a; b = p.b; FieldChar = p.FieldChar; }
public static void SqrtTest(int rounds) { Random rand = new Random(); for (int count = 0; count < rounds; count++) { // generate data of random length int t1 = 0; while (t1 == 0) t1 = (int)(rand.NextDouble() * 1024); Console.Write("Round = " + count); BInteger a = new BInteger(); a.genRandomBits(t1, rand); BInteger b = a.sqrt(); BInteger c = (b + 1) * (b + 1); // check that b is the largest integer such that b*b <= a if (c <= a) { Console.WriteLine("\nError at round " + count); Console.WriteLine(a + "\n"); return; } Console.WriteLine(" <PASSED>."); } }
public static void RSATest2(int rounds) { Random rand = new Random(); byte[] val = new byte[64]; byte[] pseudoPrime1 = { 0x85, 0x84, 0x64, 0xFD, 0x70, 0x6A, 0x9F, 0xF0, 0x94, 0x0C, 0x3E, 0x2C, 0x74, 0x34, 0x05, 0xC9, 0x55, 0xB3, 0x85, 0x32, 0x98, 0x71, 0xF9, 0x41, 0x21, 0x5F, 0x02, 0x9E, 0xEA, 0x56, 0x8D, 0x8C, 0x44, 0xCC, 0xEE, 0xEE, 0x3D, 0x2C, 0x9D, 0x2C, 0x12, 0x41, 0x1E, 0xF1, 0xC5, 0x32, 0xC3, 0xAA, 0x31, 0x4A, 0x52, 0xD8, 0xE8, 0xAF, 0x42, 0xF4, 0x72, 0xA1, 0x2A, 0x0D, 0x97, 0xB1, 0x31, 0xB3, }; byte[] pseudoPrime2 = { 0x99, 0x98, 0xCA, 0xB8, 0x5E, 0xD7, 0xE5, 0xDC, 0x28, 0x5C, 0x6F, 0x0E, 0x15, 0x09, 0x59, 0x6E, 0x84, 0xF3, 0x81, 0xCD, 0xDE, 0x42, 0xDC, 0x93, 0xC2, 0x7A, 0x62, 0xAC, 0x6C, 0xAF, 0xDE, 0x74, 0xE3, 0xCB, 0x60, 0x20, 0x38, 0x9C, 0x21, 0xC3, 0xDC, 0xC8, 0xA2, 0x4D, 0xC6, 0x2A, 0x35, 0x7F, 0xF3, 0xA9, 0xE8, 0x1D, 0x7B, 0x2C, 0x78, 0xFA, 0xB8, 0x02, 0x55, 0x80, 0x9B, 0xC2, 0xA5, 0xCB, }; BInteger bi_p = new BInteger(pseudoPrime1); BInteger bi_q = new BInteger(pseudoPrime2); BInteger bi_pq = (bi_p - 1) * (bi_q - 1); BInteger bi_n = bi_p * bi_q; for (int count = 0; count < rounds; count++) { // generate private and public key BInteger bi_e = bi_pq.genCoPrime(512, rand); BInteger bi_d = bi_e.modInverse(bi_pq); Console.WriteLine("\ne =\n" + bi_e.ToString(10)); Console.WriteLine("\nd =\n" + bi_d.ToString(10)); Console.WriteLine("\nn =\n" + bi_n.ToString(10) + "\n"); // generate data of random length int t1 = 0; while (t1 == 0) t1 = (int)(rand.NextDouble() * 65); bool done = false; while (!done) { for (int i = 0; i < 64; i++) { if (i < t1) val[i] = (byte)(rand.NextDouble() * 256); else val[i] = 0; if (val[i] != 0) done = true; } } while (val[0] == 0) val[0] = (byte)(rand.NextDouble() * 256); Console.Write("Round = " + count); // encrypt and decrypt data BInteger bi_data = new BInteger(val, t1); BInteger bi_encrypted = bi_data.modPow(bi_e, bi_n); BInteger bi_decrypted = bi_encrypted.modPow(bi_d, bi_n); // compare if (bi_decrypted != bi_data) { Console.WriteLine("\nError at round " + count); Console.WriteLine(bi_data + "\n"); return; } Console.WriteLine(" <PASSED>."); } }
public static void RSATest(int rounds) { Random rand = new Random(1); byte[] val = new byte[64]; // private and public key BInteger bi_e = new BInteger("a932b948feed4fb2b692609bd22164fc9edb59fae7880cc1eaff7b3c9626b7e5b241c27a974833b2622ebe09beb451917663d47232488f23a117fc97720f1e7", 16); BInteger bi_d = new BInteger("4adf2f7a89da93248509347d2ae506d683dd3a16357e859a980c4f77a4e2f7a01fae289f13a851df6e9db5adaa60bfd2b162bbbe31f7c8f828261a6839311929d2cef4f864dde65e556ce43c89bbbf9f1ac5511315847ce9cc8dc92470a747b8792d6a83b0092d2e5ebaf852c85cacf34278efa99160f2f8aa7ee7214de07b7", 16); BInteger bi_n = new BInteger("e8e77781f36a7b3188d711c2190b560f205a52391b3479cdb99fa010745cbeba5f2adc08e1de6bf38398a0487c4a73610d94ec36f17f3f46ad75e17bc1adfec99839589f45f95ccc94cb2a5c500b477eb3323d8cfab0c8458c96f0147a45d27e45a4d11d54d77684f65d48f15fafcc1ba208e71e921b9bd9017c16a5231af7f", 16); Console.WriteLine("e =\n" + bi_e.ToString(10)); Console.WriteLine("\nd =\n" + bi_d.ToString(10)); Console.WriteLine("\nn =\n" + bi_n.ToString(10) + "\n"); for (int count = 0; count < rounds; count++) { // generate data of random length int t1 = 0; while (t1 == 0) t1 = (int)(rand.NextDouble() * 65); bool done = false; while (!done) { for (int i = 0; i < 64; i++) { if (i < t1) val[i] = (byte)(rand.NextDouble() * 256); else val[i] = 0; if (val[i] != 0) done = true; } } while (val[0] == 0) val[0] = (byte)(rand.NextDouble() * 256); Console.Write("Round = " + count); // encrypt and decrypt data BInteger bi_data = new BInteger(val, t1); BInteger bi_encrypted = bi_data.modPow(bi_e, bi_n); BInteger bi_decrypted = bi_encrypted.modPow(bi_d, bi_n); // compare if (bi_decrypted != bi_data) { Console.WriteLine("\nError at round " + count); Console.WriteLine(bi_data + "\n"); return; } Console.WriteLine(" <PASSED>."); } }
//Вычисляем символ Лежандра public BInteger Legendre(BInteger a, BInteger q) { return a.modPow((q - 1) / 2, q); }
//подписываем сообщение public string SingGen(byte[] h, BInteger d) { BInteger alpha = new BInteger(h); BInteger e = alpha % n; if (e == 0) e = 1; BInteger k = new BInteger(); ECPoint C = new ECPoint(); BInteger r = new BInteger(); BInteger s = new BInteger(); do { do { k.genRandomBits(n.bitCount(), new Random()); } while ((k < 0) || (k > n)); C = ECPoint.multiply(k, G); r = C.x % n; s = ((r * d) + (k * e)) % n; } while ((r == 0) || (s == 0)); string Rvector = padding(r.ToHexString(), n.bitCount() / 4); string Svector = padding(s.ToHexString(), n.bitCount() / 4); return Rvector + Svector; }
public static BInteger operator +(BInteger bi1, BInteger bi2) { BInteger result = new BInteger(); result.dataLength = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength; long carry = 0; for (int i = 0; i < result.dataLength; i++) { long sum = bi1.data[i] + (long)bi2.data[i] + carry; carry = sum >> 32; result.data[i] = (uint)(sum & 0xFFFFFFFF); } if (carry != 0 && result.dataLength < maxLength) { result.data[result.dataLength] = (uint)(carry); result.dataLength++; } while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) result.dataLength--; // overflow check int lastPos = maxLength - 1; if ((bi1.data[lastPos] & 0x80000000) == (bi2.data[lastPos] & 0x80000000) && (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) { throw (new ArithmeticException()); } return result; }
public static BInteger operator -(BInteger bi1, BInteger bi2) { BInteger result = new BInteger(); result.dataLength = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength; long carryIn = 0; for (int i = 0; i < result.dataLength; i++) { long diff; diff = bi1.data[i] - (long)bi2.data[i] - carryIn; result.data[i] = (uint)(diff & 0xFFFFFFFF); if (diff < 0) carryIn = 1; else carryIn = 0; } if (carryIn != 0) { for (int i = result.dataLength; i < maxLength; i++) result.data[i] = 0xFFFFFFFF; result.dataLength = maxLength; } while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) result.dataLength--; int lastPos = maxLength - 1; if ((bi1.data[lastPos] & 0x80000000) != (bi2.data[lastPos] & 0x80000000) && (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) { throw (new ArithmeticException()); } return result; }
public DSGost(BInteger p, BInteger a, BInteger b, BInteger n, byte[] xG) { this.a = a; this.b = b; this.n = n; this.p = p; this.xG = xG; }
public static BInteger operator *(BInteger bi1, BInteger bi2) { int lastPos = maxLength - 1; bool bi1Neg = false, bi2Neg = false; try { if ((bi1.data[lastPos] & 0x80000000) != 0) // bi1 negative { bi1Neg = true; bi1 = -bi1; } if ((bi2.data[lastPos] & 0x80000000) != 0) // bi2 negative { bi2Neg = true; bi2 = -bi2; } } catch (Exception) { } BInteger result = new BInteger(); try { for (int i = 0; i < bi1.dataLength; i++) { if (bi1.data[i] == 0) continue; ulong mcarry = 0; for (int j = 0, k = i; j < bi2.dataLength; j++, k++) { // k = i + j ulong val = bi1.data[i] * (ulong)bi2.data[j] + result.data[k] + mcarry; result.data[k] = (uint)(val & 0xFFFFFFFF); mcarry = (val >> 32); } if (mcarry != 0) result.data[i + bi2.dataLength] = (uint)mcarry; } } catch (Exception) { throw (new ArithmeticException("Multiplication overflow.")); } result.dataLength = bi1.dataLength + bi2.dataLength; if (result.dataLength > maxLength) result.dataLength = maxLength; while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) result.dataLength--; if ((result.data[lastPos] & 0x80000000) != 0) { if (bi1Neg != bi2Neg && result.data[lastPos] == 0x80000000) // different sign { if (result.dataLength == 1) return result; else { bool isMaxNeg = true; for (int i = 0; i < result.dataLength - 1 && isMaxNeg; i++) { if (result.data[i] != 0) isMaxNeg = false; } if (isMaxNeg) return result; } } throw (new ArithmeticException("Multiplication overflow.")); } if (bi1Neg != bi2Neg) return -result; return result; }
//Генерируем секретный ключ заданной длины public BInteger GenPrivateKey(int BitSize) { BInteger d = new BInteger(); do { d.genRandomBits(BitSize, new Random()); } while ((d < 0) || (d > n)); return d; }
public static BInteger operator >>(BInteger bi1, int shiftVal) { BInteger result = new BInteger(bi1); result.dataLength = shiftRight(result.data, shiftVal); if ((bi1.data[maxLength - 1] & 0x80000000) != 0) // negative { for (int i = maxLength - 1; i >= result.dataLength; i--) result.data[i] = 0xFFFFFFFF; uint mask = 0x80000000; for (int i = 0; i < 32; i++) { if ((result.data[result.dataLength - 1] & mask) != 0) break; result.data[result.dataLength - 1] |= mask; mask >>= 1; } result.dataLength = maxLength; } return result; }
//С помощью секретного ключа d вычисляем точку Q=d*G, это и будет наш публичный ключ public ECPoint GenPublicKey(BInteger d) { ECPoint G = GDecompression(); ECPoint Q = ECPoint.multiply(d, G); return Q; }
public static BInteger operator -(BInteger bi1) { // handle neg of zero separately since it'll cause an overflow // if we proceed. if (bi1.dataLength == 1 && bi1.data[0] == 0) return (new BInteger()); BInteger result = new BInteger(bi1); // 1's complement for (int i = 0; i < maxLength; i++) result.data[i] = ~(bi1.data[i]); // add one to result of 1's complement long val, carry = 1; int index = 0; while (carry != 0 && index < maxLength) { val = result.data[index]; val++; result.data[index] = (uint)(val & 0xFFFFFFFF); carry = val >> 32; index++; } if ((bi1.data[maxLength - 1] & 0x80000000) == (result.data[maxLength - 1] & 0x80000000)) throw (new ArithmeticException("Overflow in negation.\n")); result.dataLength = maxLength; while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) result.dataLength--; return result; }
public static BInteger operator ++(BInteger bi1) { BInteger result = new BInteger(bi1); long val, carry = 1; int index = 0; while (carry != 0 && index < maxLength) { val = result.data[index]; val++; result.data[index] = (uint)(val & 0xFFFFFFFF); carry = val >> 32; index++; } if (index > result.dataLength) result.dataLength = index; else { while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0) result.dataLength--; } int lastPos = maxLength - 1; if ((bi1.data[lastPos] & 0x80000000) == 0 && (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) { throw (new ArithmeticException("Overflow in ++.")); } return result; }
private static void singleByteDivide(BInteger bi1, BInteger bi2, BInteger outQuotient, BInteger outRemainder) { uint[] result = new uint[maxLength]; int resultPos = 0; // copy dividend to reminder for (int i = 0; i < maxLength; i++) outRemainder.data[i] = bi1.data[i]; outRemainder.dataLength = bi1.dataLength; while (outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength - 1] == 0) outRemainder.dataLength--; ulong divisor = bi2.data[0]; int pos = outRemainder.dataLength - 1; ulong dividend = outRemainder.data[pos]; //Console.WriteLine("divisor = " + divisor + " dividend = " + dividend); //Console.WriteLine("divisor = " + bi2 + "\ndividend = " + bi1); if (dividend >= divisor) { ulong quotient = dividend / divisor; result[resultPos++] = (uint)quotient; outRemainder.data[pos] = (uint)(dividend % divisor); } pos--; while (pos >= 0) { //Console.WriteLine(pos); dividend = ((ulong)outRemainder.data[pos + 1] << 32) + outRemainder.data[pos]; ulong quotient = dividend / divisor; result[resultPos++] = (uint)quotient; outRemainder.data[pos + 1] = 0; outRemainder.data[pos--] = (uint)(dividend % divisor); //Console.WriteLine(">>>> " + bi1); } outQuotient.dataLength = resultPos; int j = 0; for (int i = outQuotient.dataLength - 1; i >= 0; i--, j++) outQuotient.data[j] = result[i]; for (; j < maxLength; j++) outQuotient.data[j] = 0; while (outQuotient.dataLength > 1 && outQuotient.data[outQuotient.dataLength - 1] == 0) outQuotient.dataLength--; if (outQuotient.dataLength == 0) outQuotient.dataLength = 1; while (outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength - 1] == 0) outRemainder.dataLength--; }
//Восстанавливаем координату y из координаты x и бита четности y private ECPoint GDecompression() { byte y = xG[0]; byte[] x = new byte[xG.Length - 1]; Array.Copy(xG, 1, x, 0, xG.Length - 1); BInteger Xcord = new BInteger(x); BInteger temp = (Xcord * Xcord * Xcord + a * Xcord + b) % p; BInteger beta = ModSqrt(temp, p); BInteger Ycord = new BInteger(); if ((beta % 2) == (y % 2)) Ycord = beta; else Ycord = p - beta; ECPoint G = new ECPoint(); G.a = a; G.b = b; G.FieldChar = p; G.x = Xcord; G.y = Ycord; this.G = G; return G; }
public static BInteger operator %(BInteger bi1, BInteger bi2) { BInteger quotient = new BInteger(); BInteger remainder = new BInteger(bi1); int lastPos = maxLength - 1; bool dividendNeg = false; if ((bi1.data[lastPos] & 0x80000000) != 0) // bi1 negative { bi1 = -bi1; dividendNeg = true; } if ((bi2.data[lastPos] & 0x80000000) != 0) // bi2 negative bi2 = -bi2; if (bi1 < bi2) { return remainder; } else { if (bi2.dataLength == 1) singleByteDivide(bi1, bi2, quotient, remainder); else multiByteDivide(bi1, bi2, quotient, remainder); if (dividendNeg) return -remainder; return remainder; } }
//функция вычисления квадратоного корня по модулю простого числа q public BInteger ModSqrt(BInteger a, BInteger q) { BInteger b = new BInteger(); do { b.genRandomBits(255, new Random()); } while (Legendre(b, q) == 1); BInteger s = 0; BInteger t = q - 1; while ((t & 1) != 1) { s++; t = t >> 1; } BInteger InvA = a.modInverse(q); BInteger c = b.modPow(t, q); BInteger r = a.modPow(((t + 1) / 2), q); BInteger d = new BInteger(); for (int i = 1; i < s; i++) { BInteger temp = 2; temp = temp.modPow((s - i - 1), q); d = (r.modPow(2, q) * InvA).modPow(temp, q); if (d == (q - 1)) r = (r * c) % q; c = c.modPow(2, q); } return r; }