1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/* SI 335 Spring 2013
 * Project 2, RSA program
 * YOUR NAME HERE
 */
 
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
 
#include "posint.hpp"
 
using namespace std;
 
// Prints a message on proper usage and exits with the given code
void usage (const char* progname, int ret);
 
// Function prototype. You have to fill in the implementation below.
void powmod (PosInt& result, const PosInt& a, const PosInt& b, const PosInt& n);
 
int main (int argc, char** argv) {
  // Seed the random number generator
  srand (time(NULL));
 
  // Pick the base to use in the PosInt class
  PosInt::setBase (10);
 
  if (argc < 2 || argv[1][0] != '-') usage(argv[0],1);
  if (argv[1][1] == 'k') {
    ////////////////////////////////////////////////////////////////////
    //                 KEY GENERATION                                 //
    ////////////////////////////////////////////////////////////////////
    if (argc != 2) usage(argv[0],3);
    
    // These are just "dummy" values! Replace with your actual code
    PosInt n (11);
    PosInt e (5);
    PosInt d (9);
 
    // Print out the public key and private key
    cout << e << ' ' << n << endl;
    cout << d << ' ' << n << endl;
  }
  else if (argv[1][1] == 'e') {
    ////////////////////////////////////////////////////////////////////
    //                  ENCRYPTION WITH PUBLIC KEY                    //
    ////////////////////////////////////////////////////////////////////
    if (argc != 4) usage(argv[0],3);
 
    // Get public key from command-line arguments
    PosInt e (argv[2]);
    PosInt n (argv[3]);
 
    // Read characters from standard in and encrypt them
    int c;
    PosInt M (0); // Initialize M to zero
    int twoFiftySixCubed = 256 << 16; // = 256^3
    PosInt twoFiftySix (256);
    PosInt power (twoFiftySixCubed);
    
    bool keepGoing = true;
    while (keepGoing) {
      c = cin.get();
 
      if (c == '\n') keepGoing = false;
      else {
        PosInt next (c); // next character, converted to a PosInt
        next.mul(power); // next *= power
        M.add(next);     // M = M + next
        power.div(twoFiftySix);
      }
 
      if (power.isZero() || !keepGoing) {
        // HERE'S WHERE YOU HAVE TO DO THE ENCRYPTION!
        PosInt C (M); // THIS IS JUST A "DUMMY" VALUE
        cout << C << ' ';
 
        // Now reset power and M and keep going
        power.set(twoFiftySixCubed);
        M.set(0);
      }
    }
    cout << endl;
  }
  else if (argv[1][1] == 'd') {
    ////////////////////////////////////////////////////////////////////
    //                 DECRYPTION WITH PRIVATE KEY                    //
    ////////////////////////////////////////////////////////////////////
    if (argc != 4) usage(argv[0],3);
 
    // Get private key from command-line arguments
    PosInt d (argv[2]);
    PosInt n (argv[3]);
    PosInt C;
 
    // Put the line of encoded numbers into a stringstream for reading
    string line;
    getline (cin, line);
    istringstream iss (line);
 
    while (iss >> C) {
      // You have to decrypt C and print out the four characters
      // Note: use the "convert" function to turn a PosInt into
      // a regular "int".
      cout << "abcd"; // THIS IS JUST A DUMMY!
    }
    cout << endl;
  }
  else if (argv[1][1] == 'h') usage(argv[0], 0);
  else usage(argv[0],2);
  return 0;
}
 
////////////////////////////////////////////////////////////
//              MODULAR EXPONENTIATION                    //
////////////////////////////////////////////////////////////
 
// Computes a^b mod n, and stores the answer in "result".
void powmod (PosInt& result, const PosInt& a, const PosInt& b, const PosInt& n) {
  // YOU HAVE TO FILL THIS IN!
}
 
 
////////////////////////////////////////////////////////////
//              KARATSUBA MULTIPLICATION                  //
////////////////////////////////////////////////////////////
 
// Computes x * y, and stores the result in "this" PosInt object.
PosInt& PosInt::fasterMul (const PosInt& x, const PosInt& y) {
  // This is a suggestion of how to do this one:
 
  // First figure out the larger of the two input sizes
  int n = x.digits.size();
  if (n < y.digits.size()) n = y.digits.size();
  
  // Now copy the inputs into arrays of that size, with zero-padding
  int* xcopy = new int[n];
  int* ycopy = new int[n];
  for (int i=0; i<n; ++i) {
    xcopy[i] = 0;
    ycopy[i] = 0;
  }
  for (int i=0; i<x.digits.size(); ++i)
    xcopy[i] = x.digits[i];
  for (int i=0; i<y.digits.size(); ++i)
    ycopy[i] = y.digits[i];
 
  // Set "this" digit vector to a zeroed-vector of size 2n
  digits.assign (2*n, 0);
 
  // Now call the array version to do the actual multiplication
  fastMulArray (&digits[0], xcopy, ycopy, n);
 
  // We have to call normalize in case there are leading zeros
  normalize();
 
  // And we don't want memory leaks do we?
  delete [] xcopy;
  delete [] ycopy;
 
  // Finally return a reference to "this" PosInt
  return *this;
}
 
// This does the real work of Karatsuba's algorithm
// (or whatever multiplication algorithm you might write).
// The input is two arrays of digits, x and y, which both have length len.
// The output is stored in the array dest, which is already allocated
// to the proper length.
void PosInt::fastMulArray (int* dest, const int* x, const int* y, int len) {
  // Again, this is just a suggested general outline...
  if (len == 1) {
    // base case
    // YOU FILL THIS IN
  }
  else {
    // recursive case
    // YOU FILL THIS IN TOO.
    // Hint: you will have to allocate some memory for U, V, P0, P1, and P2
    // Another hint: use the addArray and subArray helper methods from the
    // PosInt class!
  }
}
 
 
// Prints a message on proper usage and exits with the given code
void usage (const char* progname, int ret) {
  cout
    << "Generate a public-private key pair:" << endl
    << "\t" << progname << " -k" << endl
    << "Encrypt a message with public key:" << endl
    << "\t" << progname << " -e <e> <n>" << endl
    << "Decrypt a message with private key:" << endl
    << "\t" << progname << " -d <d> <n>" << endl;
  exit(ret);
}