//Given the interface that follows can you implement the SS part described below

void randstate\_init(uint64\_t seed)
Initializes the global random state named state with a Mersenne Twister algorithm, using seed as the
random seed. You should call srandom() using this seed as well. This function will also entail calls to
gmp\_randinit\_mt() and to gmp\_randseed\_ui().
void randstate\_clear(void)
Clears and frees all memory used by the initialized global random state named state. This should just
be a single call to gmp\_randclear().
void pow\_mod(mpz\_t out, mpz\_t base, mpz\_t exponent, mpz\_t modulus)
Performs fast modular exponentiation, computing base raised to the exponent power modulo modulus,
and storing the computed result in out.

bool is\_prime(mpz\_t n, uint64\_t iters)
Conducts the Miller-Rabin primality test to indicate whether or not n is prime using iters number of
Miller-Rabin iterations. 
In addition to the is\_prime() function, you are also required to implement the following function:
void make\_prime(mpz\_t p, uint64\_t bits, uint64\_t iters)

void mod\_inverse(mpz\_t i, mpz\_t a, mpz\_t n)
Computes the inverse i of a modulo n. In the event that a modular inverse cannot be found, set i to 0.
// Given the above interface implement the below specs

An SS Library

(log2 in this text means using base 2)

void ss\_make\_pub(mpz\_t p, mpz\_t q, mpz\_t n, uint64\_t nbits, uint64\_t iters)
Creates parts of a new SS public key: two large primes p and q, and n computed as p ¤ p ¤ q. Begin by
creating primes p and q using make\_prime(). We first need to decide the number of bits that go to each
prime respectively such that log2(n) ¸ nbits. Let the number of bits for p be a random number in the
range [nbits/5; (2£nbits)/5). Recall that n = p2 £q: the bits from p will be contributed to n twice,
the remaining bits will go to q. The number of Miller-Rabin iterations is specified by iters. You should
obtain this random number using random() and check that p - q-1 and q - p-1.

void ss\_write\_pub(mpz\_t n, char username[], FILE \*pbfile)
Writes a public SS key to pbfile. The format of a public key should be n, then the username, each of
which are written with a trailing newline. The value n should be written as a hexstring. See the GMP
functions for formatted output for help with writing hexstrings.
void ss\_read\_pub(mpz\_t n, char username[], FILE \*pbfile)
Reads a public SS key from pbfile. The format of a public key should be n, then the username, each
of which should have been written with a trailing newline. The value n should have been written as a
hexstring. See the GMP functions for formatted input for help with reading hexstrings.
void ss\_make\_priv(mpz\_t d, mpz\_t pq, mpz\_t p, mpz\_t q)
Creates a new SS private key d given primes p and q and the public key n. To compute d, simply compute
the inverse of n modulo (pq)=lcm(p-1;q-1).
void ss\_write\_priv(mpz\_t pq, mpz\_t d, FILE \*pvfile)
Writes a private SS key to pvfile. The format of a private key should be pq then d, both of which are
written with a trailing newline. Both these values should be written as hexstrings.

void SS\_read\_priv(mpz\_t pq, mpz\_t d, FILE \*pvfile)
Reads a private SS key from pvfile. The format of a private key should be pq then d, both of which
should have beenwritten with a trailing newline. Both these values should have beenwritten as hexstrings.

void ss\_encrypt(mpz\_t c, mpz\_t m, mpz\_t n)
Performs SS encryption, computing the ciphertext c by encrypting message m using the public key n.
Encryption with SS is defined as E(m)=c=mn (mod n).

void ss\_encrypt\_file(FILE \*infile, FILE \*outfile, mpz\_t n)
Encrypts the contents of infile, writing the encrypted contents to outfile. The data in infile should
be in encrypted in blocks. Why not encrypt the entire file? Because of n. We are working modulo n,
which means that the value of the block of data we are encrypting must be strictly less than n. We have
two additional restrictions on the values of the blocks we encrypt:
1. The value of a block cannot be 0: E(0) ´ 0 ´ 0n (mod n).
2. The value of a block cannot be 1. E(1) ´ 1 ´ 1n (mod n).
A solution to these additional restrictions is to simply prepend a single byte to the front of the block we
want to encrypt. The value of the prepended byte will be 0xFF. This solution is not unlike the padding
schemes such as PKCS and OAEP used in modern constructions of RSA. To encrypt a file, follow these
steps:
1. Calculate the block size k. This should be k=(log2(sqrt(n)-1))/8.

2. Dynamically allocate an array that can hold k bytes. This array should be of type (uint8\_t \*) and
will serve as the block.
3. Set the zeroth byte of the block to 0xFF. This effectively prepends the workaround byte that we
need.
4. While there are still unprocessed bytes in infile:
(a) Read at most k-1 bytes in from infile, and let j be the number of bytes actually read. Place
the read bytes into the allocated block starting from index 1 so as to not overwrite the 0xFF.
(b) Using mpz\_import(), convert the read bytes, including the prepended 0xFF into an mpz\_t
m. You will want to set the order parameter of mpz\_import() to 1 for most significant word
first, 1 for the endian parameter, and 0 for the nails parameter.
(c) Encrypt m with ss\_encrypt(), then write the encrypted number to outfile as a hexstring
followed by a trailing newline.
void ss\_decrypt(mpz\_t m, mpz\_t c, mpz\_t d, mpz\_t pq)
Performs SS decryption, computing message m by decrypting ciphertext c using private key d and public
modulus n. Remember, decryption with SS is defined asD(c)=m=cd (mod pq).
void ss\_decrypt\_file(FILE \*infile, FILE \*outfile, mpz\_t pq, mpz\_t d)
Decrypts the contents of infile, writing the decrypted contents to outfile. The data in infile should
be decrypted in blocks to mirror how ss\_encrypt\_file() encrypts in blocks. To decrypt a file, follow
these steps:
1. Dynamically allocate an array that can hold k = (log2(sqrt(n)-1))/8 bytes. This array should be of
type (uint8\_t \*) and will serve as the block.
• We need to ensure that our buffer is able to hold at least the number of bits that were used
during the enryption process. In this context we don’t know the value of n, but we can overestimate
the number of bits in sqrt(n) using pq.

log2 (sqrt(n)) < log2 (pq) 
2. Iterating over the lines in infile:
(a) Scan in a hexstring, saving the hexstring as a mpz\_t c. Remember, each block is written as a
hexstring with a trailing newline when encrypting a file.
(b) First decrypt c back into its original value m. Then using mpz\_export(), convert m back into
bytes, storing them in the allocated block. Let j be the number of bytes actually converted.
You willwant to set the order parameter of mpz\_export() to 1 for most significant word first,
1 for the endian parameter, and 0 for the nails parameter.
(c) Write out j-1 bytes starting from index 1 of the block to outfile. This is because index 0
must be prepended 0xFF. Do not output the 0xFF.
/다음 인터페이스가 주어지면 아래에 설명된 SS 부분을 구현할 수 있습니다.void randstate\_init(uint64\_t seed)seed를 무작위 시드(seed)로 사용해 메르센 트위스터 알고리즘으로 전역 랜덤 상태인 state를 초기화합니다.랜덤 시드로 사용합니다. 이 시드를 사용하여 srandom()도 호출해야 합니다. 이 함수는 또한gmp\_randinit\_mt() 및 gmp\_randseed\_ui()에 대한 호출도 수반합니다.void randstate\_clear(void)초기화된 전역 랜덤 상태 state가 사용하는 모든 메모리를 지우고 해제합니다. 이것은 단지gmp\_randclear()를 한 번만 호출하면 됩니다.void pow\_mod(mpz\_t out, mpz\_t base, mpz\_t exponent, mpz\_t modulus)빠른 모듈식 지수를 수행하여 지수의 제곱 모듈로 올라간 기저를 계산합니다,계산된 결과를 아웃에 저장합니다.bool is\_prime(mpz\_t n, uint64\_t iters)밀러-라빈 소수성 테스트를 수행하여 반복 횟수를 사용하여 n이 소수인지 여부를 나타냅니다.반복 횟수를 사용합니다. is\_prime() 함수 외에도 다음 함수도 구현해야 합니다:void make\_prime(mpz\_t p, uint64\_t bits, uint64\_t iters)void mod\_inverse(mpz\_t i, mpz\_t a, mpz\_t n)모듈러 n의 역수 i를 계산합니다. 모듈러 역수를 찾을 수 없는 경우, i를 0으로 설정합니다.// 위의 인터페이스가 주어지면 아래 사양을 구현합니다.SS 라이브러리(이 텍스트에서 log2는 기본 2를 사용함을 의미합니다.)void ss\_make\_pub(mpz\_t p, mpz\_t q, mpz\_t n, uint64\_t nbits, uint64\_t iters)새 SS 공개키의 일부를 생성합니다: 두 개의 큰 소수 p와 q, 그리고 p ¤ p ¤ q로 계산된 n. 다음과 같이 시작합니다.make\_prime()을 사용하여 소수 p와 q를 생성합니다. 먼저 각 소수에 들어가는 비트 수를 결정해야 합니다.소수에 각각 들어가는 비트 수를 결정해야 합니다. p의 비트 수는 다음 범위의 난수라고 가정합니다.범위의 임의의 숫자입니다. n = p2 £q를 기억하세요: p의 비트는 n에 두 번 기여합니다,나머지 비트는 q로 이동합니다. 밀러-라빈 반복의 횟수는 이터로 지정됩니다. 다음과 같이 해야 합니다.random()을 사용하여 이 난수를 구하고 p - q-1 및 q - p-1을 확인합니다.void ss\_write\_pub(mpz\_t n, char username[], FILE \*pbfile)공개 SS 키를 pbfile에 씁니다. 공개 키의 형식은 n, 사용자 이름, 그리고 각각은이 뒤따르는 개행으로 기록됩니다. 값 n은 16진수로 작성해야 합니다. 형식이 지정된 출력에 대한 도움말은 GMP형식의 출력에 대한 함수를 참조하세요.void ss\_read\_pub(mpz\_t n, char username[], FILE \*pbfile)pbfile에서 공개 SS키를 읽습니다. 공개 키의 형식은 n, 사용자 이름이어야 합니다.은 후행 개행으로 작성되어야 합니다. 값 n은헥스트링으로 작성해야 합니다. 16진수 문자열 읽기에 대한 도움말은 형식화된 입력에 대한 GMP 함수를 참조하세요.void SS\_make\_PRIV(MPZ\_t D, MPZ\_t PQ, MPZ\_t P, MPZ\_t Q)소수 p와 q, 공개 키 n이 주어지면 새 SS 개인 키 d를 생성합니다. d를 계산하려면 간단히n 모듈로(pq)=lcm(p-1;q-1)의 역을 계산하면 됩니다.void ss\_write\_priv(mpz\_t pq, mpz\_t d, FILE \*pvfile)개인 SS키를 pv파일에 씁니다. 개인 키의 형식은 pq 다음에 d여야 하며, 둘 다 뒤에 줄 바꿈으로뒤에 줄 바꿈이 있어야 합니다. 이 두 값은 모두 16진수로 작성해야 합니다.void SS\_read\_priv(mpz\_t pq, mpz\_t d, FILE \*pvfile)pv파일에서 개인 SS키를 읽습니다. 개인 키의 형식은 pq 다음에 d여야 하며, 둘 다뒤에 개행이 있어야 합니다. 이 두 값은 모두 헥스트링으로 작성되어야 합니다.void SS\_ENCRYPT(MPZ\__C, MPZ\__M, MPZ\__N)공개 키 n을 사용하여 메시지 m을 암호화하여 암호문 c를 계산하는 SS 암호화를 수행합니다.SS를 사용한 암호화는 E(m)=c=mn(mod n)으로 정의됩니다.void ss\_encrypt\_file(FILE \*인파일, FILE \*아웃파일, mpz\_t n)인파일의 내용을 암호화하고 암호화된 내용을 아웃파일에 씁니다. 인파일의 데이터는 다음과 같아야 합니다.블록 단위로 암호화되어 있어야 합니다. 왜 전체 파일을 암호화하지 않나요? n 때문에. 우리는 모듈로 n을 작업하고 있습니다,즉, 암호화하는 데이터 블록의 값은 엄밀히 말해 n보다 작아야 합니다.암호화하는 블록의 값에 대한 두 가지 추가 제한이 있습니다:1. 블록의 값은 0이 될 수 없습니다: E(0) ´ 0 ´ 0n (mod n).2. 블록의 값은 1이 될 수 없습니다. E(1) ´ 1 ´ 1n (mod n).이러한 추가 제한 사항에 대한 해결책은 단순히 암호화하려는 블록 앞에 단일 바이트를 추가하는 것입니다.를 추가하는 것입니다. 앞에 추가되는 바이트의 값은 0xFF가 됩니다. 이 솔루션은 패딩과 다르지 않습니다.방식과 다르지 않습니다. 파일을 암호화하려면 다음 단계를 따르세요.단계를 따르세요:1. 블록 크기 k를 계산합니다. k=(log2(sqrt(n)-1))/8이 되어야 합니다.2. 2. k 바이트를 담을 수 있는 배열을 동적으로 할당합니다. 이 배열은 (uint8\_t \*) 유형이어야 하며가 블록 역할을 합니다.3. 3. 블록의 0번째 바이트를 0xFF로 설정합니다. 이렇게 하면 필요한 해결 방법 바이트를 효과적으로 추가할 수 있습니다.필요합니다.4. 인파일에 아직 처리되지 않은 바이트가 있는 동안:(a) 인파일에서 최대 k-1 바이트까지 읽고, j를 실제로 읽은 바이트 수로 합니다. 읽은 바이트들을읽은 바이트를 인덱스 1부터 시작하여 할당된 블록에 배치합니다. 