proc ::pki::get_prime {bits} {
	set d 1
	for {set n 1} {[string length $d] < $bits} {incr n} {
		append d [expr int(rand() * 2)]
	}
	set d [expr 0b$d]
	set d [expr $d % 2?$d:$d - 1]
	while {![::pki::_isprime $d]} {
		incr d 2
	}
	return $d
}


proc ::pki::rsa::generate {bitlength {exponent 0x10001}} {
	set e $exponent

	# Step 1. Pick 2 numbers that when multiplied together will give a number with the appropriate length
	set componentbitlen [expr {$bitlength / 2}]

	if {$bitlength % 2} {
		return -code error "bitlength must be an even number"
	}

	# Step 2. Convert the numbers into prime numbers
	# Step 3. Compute N by multiplying P and Q
	while {1} {
		set p [::pki::get_prime $componentbitlen]
		set q [::pki::get_prime $componentbitlen]

		set n [expr $q * $p]
		set quadroot_of_n [expr {isqrt(isqrt($n))}]
		set min_distance [expr {2 * $quadroot_of_n}]
		set distance [expr {abs($n)}]

		if {$distance < $min_distance} {
			#### Try again.
		} elseif {[::pki::_bits $n] != $bitlength} {
			#### Try again.
		} else {
			break
		}
	}

	# Step 4. Compute N by multiplying P and Q
	set n [expr {$p * $q}]
	set retkey(n) $n

	set retkey(p) $p
	set retkey(q) $q


	# Step 5. Compute D ...
	## Step 5.a. Generate D
	set d [::pki::rsa::_generate_private $p $q $e $bitlength]
	set retkey(d) $d

	## Step 5.b. Verify D is large enough
	### Verify that D is greater than (1/3)*n^(1/4) 
	set quadroot_of_n [expr {isqrt(isqrt($n))}]
	set min_d [expr {$quadroot_of_n / 3}]
	if {$d < $min_d} {
		#### Try again.

		return [::pki::rsa::generate $bitlength $exponent]
	}

	# Step 6. Compute Exponents 1 and 2 ...
	set retkey(e1) [expr $retkey(d) % ($p-1)]
	set retkey(e2) [expr $retkey(d) % ($q-1)]

	# Step 7. Compute Coefficient ...
	set d 1
	set r $q
	for {set c 0} {$c < $p} {incr c} {
		set d [expr (($p / $r + 1) * $d) % $p]
		set r [expr ($d * $q) % $p]
		if {$r == 1} {
			set retkey(c) $d
			break
		}
	}

	# Step 8. Encode key information
	set retkey(type) rsa
	set retkey(e) $e
	set retkey(l) $bitlength

	return [array get retkey]
}

