Browse Source

bigint: refactor to `big.Int` instead of `bigint.Int`.

Jeroen van Rijn 4 years ago
parent
commit
9dba17cf87

+ 453 - 454
core/math/bigint/basic.odin → core/math/big/basic.odin

@@ -1,455 +1,454 @@
-package bigint
-
-/*
-	Copyright 2021 Jeroen van Rijn <[email protected]>.
-	Made available under Odin's BSD-2 license.
-
-	A BigInt implementation in Odin.
-	For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
-	The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
-
-	This file contains basic arithmetic operations like `add` and `sub`.
-*/
-
-import "core:mem"
-import "core:intrinsics"
-import "core:fmt"
-
-/*
-	===========================
-		User-level routines    
-	===========================
-*/
-
-/*
-	High-level addition. Handles sign.
-*/
-add_two_ints :: proc(dest, a, b: ^Int) -> (err: Error) {
-	dest := dest; x := a; y := b;
-	assert_initialized(dest); assert_initialized(a); assert_initialized(b);
-
-	/*
-		Handle both negative or both positive.
-	*/
-	if x.sign == y.sign {
-		dest.sign = x.sign;
-		return _add(dest, x, y);
-	}
-
-	/*
-		One positive, the other negative.
-		Subtract the one with the greater magnitude from the other.
-		The result gets the sign of the one with the greater magnitude.
-	*/
-	if cmp_mag(x, y) == .Less_Than {
-		x, y = y, x;
-	}
-
-	dest.sign = x.sign;
-	return _sub(dest, x, y);
-}
-
-/*
-	Adds the unsigned `DIGIT` immediate to an `Int`,
-	such that the `DIGIT` doesn't have to be turned into an `Int` first.
-
-	dest = a + digit;
-*/
-add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
-	dest := dest; x := a; digit := digit;
-	assert_initialized(dest); assert_initialized(a);
-
-	/*
-		Fast paths for destination and input Int being the same.
-	*/
-	if dest == a {
-		/*
-			Fast path for dest.digit[0] + digit fits in dest.digit[0] without overflow.
-		*/
-		if is_pos(dest) && (dest.digit[0] + digit < _DIGIT_MAX) {
-			dest.digit[0] += digit;
-			return .OK;
-		}
-		/*
-			Can be subtracted from dest.digit[0] without underflow.
-		*/
-		if is_neg(a) && (dest.digit[0] > digit) {
-			dest.digit[0] -= digit;
-			return .OK;
-		}
-	}
-
-	/*
-		Grow destination as required.
-	*/
-	err = grow(dest, a.used + 1);
-	if err != .OK {
-		return err;
-	}
-
-	/*
-		If `a` is negative and `|a|` >= `digit`, call `dest = |a| - digit`
-	*/
-	if is_neg(a) && (a.used > 1 || a.digit[0] >= digit) {
-		/*
-			Temporarily fix `a`'s sign.
-		*/
-		t := a;
-		t.sign = .Zero_or_Positive;
-		/*
-			dest = |a| - digit
-		*/
-		err = sub(dest, t, digit);
-		/*
-			Restore sign and set `dest` sign.
-		*/
-		dest.sign = .Negative;
-		clamp(dest);
-
-		return err;
-	}
-
-	/*
-		Remember the currently used number of digits in `dest`.
-	*/
-	old_used := dest.used;
-
-	/*
-		If `a` is positive
-	*/
-	if is_pos(a) {
-		/*
-			Add digits, use `carry`.
-		*/
-		i: int;
-		carry := digit;
-		for i = 0; i < a.used; i += 1 {
-			dest.digit[i] = a.digit[i] + carry;
-			carry = dest.digit[i] >> _DIGIT_BITS;
-			dest.digit[i] &= _MASK;
-		}
-		/*
-			Set final carry.
-		*/
-		dest.digit[i] = carry;
-		/*
-			Set `dest` size.
-		*/
-		dest.used = a.used + 1;
-	} else {
-		/*
-			`a` was negative and |a| < digit.
-		*/
-		dest.used = 1;
-		/*
-			The result is a single DIGIT.
-		*/
-		dest.digit[0] = digit - a.digit[0] if a.used == 1 else digit;
-	}
-	/*
-		Sign is always positive.
-	*/
-	dest.sign = .Zero_or_Positive;
-
-	zero_count := old_used - dest.used;
-	/*
-		Zero remainder.
-	*/
-	if zero_count > 0 {
-		mem.zero_slice(dest.digit[dest.used:][:zero_count]);
-	}
-	/*
-		Adjust dest.used based on leading zeroes.
-	*/
-	clamp(dest);
-
-	return .OK;
-}
-
-add :: proc{add_two_ints, add_digit};
-
-/*
-	High-level subtraction, dest = number - decrease. Handles signs.
-*/
-sub_two_ints :: proc(dest, number, decrease: ^Int) -> (err: Error) {
-	dest := dest; x := number; y := decrease;
-	assert_initialized(number); assert_initialized(decrease); assert_initialized(dest);
-
-	if x.sign != y.sign {
-		/*
-			Subtract a negative from a positive, OR subtract a positive from a negative.
-			In either case, ADD their magnitudes and use the sign of the first number.
-		*/
-		dest.sign = x.sign;
-		return _add(dest, x, y);
-	}
-
-	/*
-		Subtract a positive from a positive, OR negative from a negative.
-		First, take the difference between their magnitudes, then...
-	*/
-	if cmp_mag(x, y) == .Less_Than {
-		/*
-			The second has a larger magnitude.
-			The result has the *opposite* sign from the first number.
-		*/
-		dest.sign = .Negative if is_pos(x) else .Zero_or_Positive;
-		x, y = y, x;
-	} else {
-		/*
-			The first has a larger or equal magnitude.
-			Copy the sign from the first.
-		*/
-		dest.sign = x.sign;
-	}
-	return _sub(dest, x, y);
-}
-
-/*
-	Adds the unsigned `DIGIT` immediate to an `Int`,
-	such that the `DIGIT` doesn't have to be turned into an `Int` first.
-
-	dest = a - digit;
-*/
-sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
-	dest := dest; x := a; digit := digit;
-	assert_initialized(dest); assert_initialized(a);
-
-	/*
-		Fast paths for destination and input Int being the same.
-	*/
-	if dest == a {
-		/*
-			Fast path for `dest` is negative and unsigned addition doesn't overflow the lowest digit.
-		*/
-		if is_neg(dest) && (dest.digit[0] + digit < _DIGIT_MAX) {
-			dest.digit[0] += digit;
-			return .OK;
-		}
-		/*
-			Can be subtracted from dest.digit[0] without underflow.
-		*/
-		if is_pos(a) && (dest.digit[0] > digit) {
-			dest.digit[0] -= digit;
-			return .OK;
-		}
-	}
-
-	/*
-		Grow destination as required.
-	*/
-	err = grow(dest, a.used + 1);
-	if err != .OK {
-		return err;
-	}
-
-	/*
-		If `a` is negative, just do an unsigned addition (with fudged signs).
-	*/
-	if is_neg(a) {
-		t := a;
-		t.sign = .Zero_or_Positive;
-
-		err = add(dest, t, digit);
-		dest.sign = .Negative;
-
-		clamp(dest);
-		return err;
-	}
-
-	old_used := dest.used;
-
-	/*
-		if `a`<= digit, simply fix the single digit.
-	*/
-	if a.used == 1 && (a.digit[0] <= digit || is_zero(a)) {
-		dest.digit[0] = digit - a.digit[0] if a.used == 1 else digit;
-		dest.sign = .Negative;
-		dest.used = 1;
-	} else {
-		dest.sign = .Zero_or_Positive;
-		dest.used = a.used;
-
-		/*
-			Subtract with carry.
-		*/
-		carry := digit;
-
-		for i := 0; i < a.used; i += 1 {
-			dest.digit[i] = a.digit[i] - carry;
-			carry := dest.digit[i] >> ((size_of(DIGIT) * 8) - 1);
-			dest.digit[i] &= _MASK;
-		}
-   	}
-
-	zero_count := old_used - dest.used;
-	/*
-		Zero remainder.
-	*/
-	if zero_count > 0 {
-		mem.zero_slice(dest.digit[dest.used:][:zero_count]);
-	}
-	/*
-		Adjust dest.used based on leading zeroes.
-	*/
-	clamp(dest);
-
-	return .OK;
-}
-
-sub :: proc{sub_two_ints, sub_digit};
-
-/*
-	==========================
-		Low-level routines    
-	==========================
-*/
-
-/*
-	Low-level addition, unsigned.
-	Handbook of Applied Cryptography, algorithm 14.7.
-*/
-_add :: proc(dest, a, b: ^Int) -> (err: Error) {
-	dest := dest; x := a; y := b;
-	assert_initialized(a); assert_initialized(b); assert_initialized(dest);
-
-	old_used, min_used, max_used, i: int;
-
-	if x.used < y.used {
-		x, y = y, x;
-	}
-
-	min_used = x.used;
-	max_used = y.used;
-	old_used = dest.used;
-
-	err = grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT));
-	if err != .OK {
-		return err;
-	}
-	dest.used = max_used + 1;
-
-	/* Zero the carry */
-	carry := DIGIT(0);
-
-	for i = 0; i < min_used; i += 1 {
-		/*
-			Compute the sum one _DIGIT at a time.
-			dest[i] = a[i] + b[i] + carry;
-		*/
-		dest.digit[i] = x.digit[i] + y.digit[i] + carry;
-
-		/*
-			Compute carry
-		*/
-		carry = dest.digit[i] >> _DIGIT_BITS;
-		/*
-			Mask away carry from result digit.
-		*/
-		dest.digit[i] &= _MASK;
-	}
-
-	if min_used != max_used {
-		/*
-			Now copy higher words, if any, in A+B.
-			If A or B has more digits, add those in.
-		*/
-		for ; i < max_used; i += 1 {
-			dest.digit[i] = x.digit[i] + carry;
-			/*
-				Compute carry
-			*/
-			carry = dest.digit[i] >> _DIGIT_BITS;
-			/*
-				Mask away carry from result digit.
-			*/
-			dest.digit[i] &= _MASK;
-		}
-	}
-	/*
-		Add remaining carry.
-	*/
-	dest.digit[i] = carry;
-
-	zero_count := old_used - dest.used;
-	/*
-		Zero remainder.
-	*/
-	if zero_count > 0 {
-		mem.zero_slice(dest.digit[dest.used:][:zero_count]);
-	}
-	/*
-		Adjust dest.used based on leading zeroes.
-	*/
-	clamp(dest);
-
-	return .OK;
-}
-
-/*
-	Low-level subtraction, dest = number - decrease. Assumes |number| > |decrease|.
-	Handbook of Applied Cryptography, algorithm 14.9.
-*/
-_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
-	dest := dest; x := number; y := decrease;
-	assert_initialized(number); assert_initialized(decrease); assert_initialized(dest);
-
-	old_used := dest.used;
-	min_used := y.used;
-	max_used := x.used;
-	i: int;
-
-	err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT));
-	if err != .OK {
-		return err;
-	}
-	dest.used = max_used;
-
-	borrow := DIGIT(0);
-
-	for i = 0; i < min_used; i += 1 {
-		dest.digit[i] = (x.digit[i] - y.digit[i] - borrow);
-		/*
-			borrow = carry bit of dest[i]
-			Note this saves performing an AND operation since if a carry does occur,
-			it will propagate all the way to the MSB.
-			As a result a single shift is enough to get the carry.
-		*/
-		borrow = dest.digit[i] >> ((size_of(DIGIT) * 8) - 1);
-		/*
-			Clear borrow from dest[i].
-		*/
-		dest.digit[i] &= _MASK;
-	}
-
-	/*
-		Now copy higher words if any, e.g. if A has more digits than B
-	*/
-	for ; i < max_used; i += 1 {
-		dest.digit[i] = x.digit[i] - borrow;
-		/*
-			borrow = carry bit of dest[i]
-			Note this saves performing an AND operation since if a carry does occur,
-			it will propagate all the way to the MSB.
-			As a result a single shift is enough to get the carry.
-		*/
-		borrow = dest.digit[i] >> ((size_of(DIGIT) * 8) - 1);
-		/*
-			Clear borrow from dest[i].
-		*/
-		dest.digit[i] &= _MASK;
-	}
-
-	zero_count := old_used - dest.used;
-	/*
-		Zero remainder.
-	*/
-	if zero_count > 0 {
-		mem.zero_slice(dest.digit[dest.used:][:zero_count]);
-	}
-	/*
-		Adjust dest.used based on leading zeroes.
-	*/
-	clamp(dest);
-	return .OK;
+package big
+
+/*
+	Copyright 2021 Jeroen van Rijn <[email protected]>.
+	Made available under Odin's BSD-2 license.
+
+	A BigInt implementation in Odin.
+	For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
+	The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
+
+	This file contains basic arithmetic operations like `add` and `sub`.
+*/
+
+import "core:mem"
+import "core:intrinsics"
+
+/*
+	===========================
+		User-level routines    
+	===========================
+*/
+
+/*
+	High-level addition. Handles sign.
+*/
+add_two_ints :: proc(dest, a, b: ^Int) -> (err: Error) {
+	dest := dest; x := a; y := b;
+	assert_initialized(dest); assert_initialized(a); assert_initialized(b);
+
+	/*
+		Handle both negative or both positive.
+	*/
+	if x.sign == y.sign {
+		dest.sign = x.sign;
+		return _add(dest, x, y);
+	}
+
+	/*
+		One positive, the other negative.
+		Subtract the one with the greater magnitude from the other.
+		The result gets the sign of the one with the greater magnitude.
+	*/
+	if cmp_mag(x, y) == .Less_Than {
+		x, y = y, x;
+	}
+
+	dest.sign = x.sign;
+	return _sub(dest, x, y);
+}
+
+/*
+	Adds the unsigned `DIGIT` immediate to an `Int`,
+	such that the `DIGIT` doesn't have to be turned into an `Int` first.
+
+	dest = a + digit;
+*/
+add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
+	dest := dest; digit := digit;
+	assert_initialized(dest); assert_initialized(a);
+
+	/*
+		Fast paths for destination and input Int being the same.
+	*/
+	if dest == a {
+		/*
+			Fast path for dest.digit[0] + digit fits in dest.digit[0] without overflow.
+		*/
+		if is_pos(dest) && (dest.digit[0] + digit < _DIGIT_MAX) {
+			dest.digit[0] += digit;
+			return .OK;
+		}
+		/*
+			Can be subtracted from dest.digit[0] without underflow.
+		*/
+		if is_neg(a) && (dest.digit[0] > digit) {
+			dest.digit[0] -= digit;
+			return .OK;
+		}
+	}
+
+	/*
+		Grow destination as required.
+	*/
+	err = grow(dest, a.used + 1);
+	if err != .OK {
+		return err;
+	}
+
+	/*
+		If `a` is negative and `|a|` >= `digit`, call `dest = |a| - digit`
+	*/
+	if is_neg(a) && (a.used > 1 || a.digit[0] >= digit) {
+		/*
+			Temporarily fix `a`'s sign.
+		*/
+		t := a;
+		t.sign = .Zero_or_Positive;
+		/*
+			dest = |a| - digit
+		*/
+		err = sub(dest, t, digit);
+		/*
+			Restore sign and set `dest` sign.
+		*/
+		dest.sign = .Negative;
+		clamp(dest);
+
+		return err;
+	}
+
+	/*
+		Remember the currently used number of digits in `dest`.
+	*/
+	old_used := dest.used;
+
+	/*
+		If `a` is positive
+	*/
+	if is_pos(a) {
+		/*
+			Add digits, use `carry`.
+		*/
+		i: int;
+		carry := digit;
+		for i = 0; i < a.used; i += 1 {
+			dest.digit[i] = a.digit[i] + carry;
+			carry = dest.digit[i] >> _DIGIT_BITS;
+			dest.digit[i] &= _MASK;
+		}
+		/*
+			Set final carry.
+		*/
+		dest.digit[i] = carry;
+		/*
+			Set `dest` size.
+		*/
+		dest.used = a.used + 1;
+	} else {
+		/*
+			`a` was negative and |a| < digit.
+		*/
+		dest.used = 1;
+		/*
+			The result is a single DIGIT.
+		*/
+		dest.digit[0] = digit - a.digit[0] if a.used == 1 else digit;
+	}
+	/*
+		Sign is always positive.
+	*/
+	dest.sign = .Zero_or_Positive;
+
+	zero_count := old_used - dest.used;
+	/*
+		Zero remainder.
+	*/
+	if zero_count > 0 {
+		mem.zero_slice(dest.digit[dest.used:][:zero_count]);
+	}
+	/*
+		Adjust dest.used based on leading zeroes.
+	*/
+	clamp(dest);
+
+	return .OK;
+}
+
+add :: proc{add_two_ints, add_digit};
+
+/*
+	High-level subtraction, dest = number - decrease. Handles signs.
+*/
+sub_two_ints :: proc(dest, number, decrease: ^Int) -> (err: Error) {
+	dest := dest; x := number; y := decrease;
+	assert_initialized(number); assert_initialized(decrease); assert_initialized(dest);
+
+	if x.sign != y.sign {
+		/*
+			Subtract a negative from a positive, OR subtract a positive from a negative.
+			In either case, ADD their magnitudes and use the sign of the first number.
+		*/
+		dest.sign = x.sign;
+		return _add(dest, x, y);
+	}
+
+	/*
+		Subtract a positive from a positive, OR negative from a negative.
+		First, take the difference between their magnitudes, then...
+	*/
+	if cmp_mag(x, y) == .Less_Than {
+		/*
+			The second has a larger magnitude.
+			The result has the *opposite* sign from the first number.
+		*/
+		dest.sign = .Negative if is_pos(x) else .Zero_or_Positive;
+		x, y = y, x;
+	} else {
+		/*
+			The first has a larger or equal magnitude.
+			Copy the sign from the first.
+		*/
+		dest.sign = x.sign;
+	}
+	return _sub(dest, x, y);
+}
+
+/*
+	Adds the unsigned `DIGIT` immediate to an `Int`,
+	such that the `DIGIT` doesn't have to be turned into an `Int` first.
+
+	dest = a - digit;
+*/
+sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
+	dest := dest; digit := digit;
+	assert_initialized(dest); assert_initialized(a);
+
+	/*
+		Fast paths for destination and input Int being the same.
+	*/
+	if dest == a {
+		/*
+			Fast path for `dest` is negative and unsigned addition doesn't overflow the lowest digit.
+		*/
+		if is_neg(dest) && (dest.digit[0] + digit < _DIGIT_MAX) {
+			dest.digit[0] += digit;
+			return .OK;
+		}
+		/*
+			Can be subtracted from dest.digit[0] without underflow.
+		*/
+		if is_pos(a) && (dest.digit[0] > digit) {
+			dest.digit[0] -= digit;
+			return .OK;
+		}
+	}
+
+	/*
+		Grow destination as required.
+	*/
+	err = grow(dest, a.used + 1);
+	if err != .OK {
+		return err;
+	}
+
+	/*
+		If `a` is negative, just do an unsigned addition (with fudged signs).
+	*/
+	if is_neg(a) {
+		t := a;
+		t.sign = .Zero_or_Positive;
+
+		err = add(dest, t, digit);
+		dest.sign = .Negative;
+
+		clamp(dest);
+		return err;
+	}
+
+	old_used := dest.used;
+
+	/*
+		if `a`<= digit, simply fix the single digit.
+	*/
+	if a.used == 1 && (a.digit[0] <= digit || is_zero(a)) {
+		dest.digit[0] = digit - a.digit[0] if a.used == 1 else digit;
+		dest.sign = .Negative;
+		dest.used = 1;
+	} else {
+		dest.sign = .Zero_or_Positive;
+		dest.used = a.used;
+
+		/*
+			Subtract with carry.
+		*/
+		carry := digit;
+
+		for i := 0; i < a.used; i += 1 {
+			dest.digit[i] = a.digit[i] - carry;
+			carry := dest.digit[i] >> ((size_of(DIGIT) * 8) - 1);
+			dest.digit[i] &= _MASK;
+		}
+   	}
+
+	zero_count := old_used - dest.used;
+	/*
+		Zero remainder.
+	*/
+	if zero_count > 0 {
+		mem.zero_slice(dest.digit[dest.used:][:zero_count]);
+	}
+	/*
+		Adjust dest.used based on leading zeroes.
+	*/
+	clamp(dest);
+
+	return .OK;
+}
+
+sub :: proc{sub_two_ints, sub_digit};
+
+/*
+	==========================
+		Low-level routines    
+	==========================
+*/
+
+/*
+	Low-level addition, unsigned.
+	Handbook of Applied Cryptography, algorithm 14.7.
+*/
+_add :: proc(dest, a, b: ^Int) -> (err: Error) {
+	dest := dest; x := a; y := b;
+	assert_initialized(a); assert_initialized(b); assert_initialized(dest);
+
+	old_used, min_used, max_used, i: int;
+
+	if x.used < y.used {
+		x, y = y, x;
+	}
+
+	min_used = x.used;
+	max_used = y.used;
+	old_used = dest.used;
+
+	err = grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT));
+	if err != .OK {
+		return err;
+	}
+	dest.used = max_used + 1;
+
+	/* Zero the carry */
+	carry := DIGIT(0);
+
+	for i = 0; i < min_used; i += 1 {
+		/*
+			Compute the sum one _DIGIT at a time.
+			dest[i] = a[i] + b[i] + carry;
+		*/
+		dest.digit[i] = x.digit[i] + y.digit[i] + carry;
+
+		/*
+			Compute carry
+		*/
+		carry = dest.digit[i] >> _DIGIT_BITS;
+		/*
+			Mask away carry from result digit.
+		*/
+		dest.digit[i] &= _MASK;
+	}
+
+	if min_used != max_used {
+		/*
+			Now copy higher words, if any, in A+B.
+			If A or B has more digits, add those in.
+		*/
+		for ; i < max_used; i += 1 {
+			dest.digit[i] = x.digit[i] + carry;
+			/*
+				Compute carry
+			*/
+			carry = dest.digit[i] >> _DIGIT_BITS;
+			/*
+				Mask away carry from result digit.
+			*/
+			dest.digit[i] &= _MASK;
+		}
+	}
+	/*
+		Add remaining carry.
+	*/
+	dest.digit[i] = carry;
+
+	zero_count := old_used - dest.used;
+	/*
+		Zero remainder.
+	*/
+	if zero_count > 0 {
+		mem.zero_slice(dest.digit[dest.used:][:zero_count]);
+	}
+	/*
+		Adjust dest.used based on leading zeroes.
+	*/
+	clamp(dest);
+
+	return .OK;
+}
+
+/*
+	Low-level subtraction, dest = number - decrease. Assumes |number| > |decrease|.
+	Handbook of Applied Cryptography, algorithm 14.9.
+*/
+_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
+	dest := dest; x := number; y := decrease;
+	assert_initialized(number); assert_initialized(decrease); assert_initialized(dest);
+
+	old_used := dest.used;
+	min_used := y.used;
+	max_used := x.used;
+	i: int;
+
+	err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT));
+	if err != .OK {
+		return err;
+	}
+	dest.used = max_used;
+
+	borrow := DIGIT(0);
+
+	for i = 0; i < min_used; i += 1 {
+		dest.digit[i] = (x.digit[i] - y.digit[i] - borrow);
+		/*
+			borrow = carry bit of dest[i]
+			Note this saves performing an AND operation since if a carry does occur,
+			it will propagate all the way to the MSB.
+			As a result a single shift is enough to get the carry.
+		*/
+		borrow = dest.digit[i] >> ((size_of(DIGIT) * 8) - 1);
+		/*
+			Clear borrow from dest[i].
+		*/
+		dest.digit[i] &= _MASK;
+	}
+
+	/*
+		Now copy higher words if any, e.g. if A has more digits than B
+	*/
+	for ; i < max_used; i += 1 {
+		dest.digit[i] = x.digit[i] - borrow;
+		/*
+			borrow = carry bit of dest[i]
+			Note this saves performing an AND operation since if a carry does occur,
+			it will propagate all the way to the MSB.
+			As a result a single shift is enough to get the carry.
+		*/
+		borrow = dest.digit[i] >> ((size_of(DIGIT) * 8) - 1);
+		/*
+			Clear borrow from dest[i].
+		*/
+		dest.digit[i] &= _MASK;
+	}
+
+	zero_count := old_used - dest.used;
+	/*
+		Zero remainder.
+	*/
+	if zero_count > 0 {
+		mem.zero_slice(dest.digit[dest.used:][:zero_count]);
+	}
+	/*
+		Adjust dest.used based on leading zeroes.
+	*/
+	clamp(dest);
+	return .OK;
 }

+ 9 - 3
core/math/bigint/bigint.odin → core/math/big/bigint.odin

@@ -1,4 +1,4 @@
-package bigint
+package big
 
 /*
 	Copyright 2021 Jeroen van Rijn <[email protected]>.
@@ -35,7 +35,13 @@ _DEFAULT_SQR_KARATSUBA_CUTOFF :: 120;
 _DEFAULT_MUL_TOOM_CUTOFF      :: 350;
 _DEFAULT_SQR_TOOM_CUTOFF      :: 400;
 
+/*
+	TODO(Jeroen): Decide whether to turn `Sign` into `Flags :: bit_set{Flag; u8}`.
+	This would hold the sign and float class, as appropriate, and would allow us
+	to set an `Int` to +/- Inf, or NaN.
 
+	The operations would need to be updated to propagate these as expected.
+*/
 Sign :: enum u8 {
 	Zero_or_Positive = 0,
 	Negative         = 1,
@@ -44,8 +50,8 @@ Sign :: enum u8 {
 Int :: struct {
 	used:      int,
 	allocated: int,
-	sign:      Sign,
 	digit:     [dynamic]DIGIT,
+	sign:      Sign,
 };
 
 Comparison_Flag :: enum i8 {
@@ -72,7 +78,7 @@ Error :: enum i8 {
 Primality_Flag :: enum u8 {
 	Blum_Blum_Shub = 0,	/* BBS style prime */
 	Safe           = 1,	/* Safe prime (p-1)/2 == prime */
-	Second_MSB_On  = 3, /* force 2nd MSB to 1 */
+	Second_MSB_On  = 3,  /* force 2nd MSB to 1 */
 };
 Primality_Flags :: bit_set[Primality_Flag; u8];
 

+ 2 - 0
core/math/big/build.bat

@@ -0,0 +1,2 @@
+@echo off
+odin run . -vet

+ 1 - 1
core/math/bigint/compare.odin → core/math/big/compare.odin

@@ -1,4 +1,4 @@
-package bigint
+package big
 
 /*
 	Copyright 2021 Jeroen van Rijn <[email protected]>.

+ 9 - 3
core/math/bigint/example.odin → core/math/big/example.odin

@@ -1,5 +1,5 @@
 //+ignore
-package bigint
+package big
 
 /*
 	Copyright 2021 Jeroen van Rijn <[email protected]>.
@@ -60,9 +60,9 @@ demo :: proc() {
 	defer destroy(b);
 	defer destroy(c);
 
-	a, err = init(1+4+16+64);
+	a, err = init(512);
 
-	b, err = init(1+2+8+32+128);
+	b, err = init(a);
 
 	c, err = init(-4);
 
@@ -108,4 +108,10 @@ main :: proc() {
 			fmt.printf("Leaked %v bytes @ %v\n", v.size, v.location);
 		}
 	}
+	if len(ta.bad_free_array) > 0 {
+		fmt.println("Bad frees:");
+		for v in ta.bad_free_array {
+			fmt.println(v);
+		}
+	}
 }

+ 23 - 6
core/math/bigint/helpers.odin → core/math/big/helpers.odin

@@ -1,4 +1,4 @@
-package bigint
+package big
 
 /*
 	Copyright 2021 Jeroen van Rijn <[email protected]>.
@@ -11,7 +11,6 @@ package bigint
 
 import "core:mem"
 import "core:intrinsics"
-import "core:fmt"
 
 /*
 	Deallocates the backing memory of an Int.
@@ -62,7 +61,7 @@ init_new :: proc(allocator_zeroes := true, allocator := context.allocator, size
 	Initialize from a signed or unsigned integer.
 	Inits a new `Int` and then calls the appropriate `set` routine.
 */
-init_new_integer :: proc(u: $T, minimize := false, allocator_zeroes := true, allocator := context.allocator) -> (a: ^Int, err: Error) where intrinsics.type_is_integer(T) {
+init_from_integer :: proc(src: $T, minimize := false, allocator_zeroes := true, allocator := context.allocator) -> (a: ^Int, err: Error) where intrinsics.type_is_integer(T) {
 
 	n := _DEFAULT_DIGIT_COUNT;
 	if minimize {
@@ -71,12 +70,27 @@ init_new_integer :: proc(u: $T, minimize := false, allocator_zeroes := true, all
 
 	a, err = init_new(allocator_zeroes, allocator, n);
 	if err == .OK {
-		set(a, u, minimize);
+		set(a, src, minimize);
 	}
 	return;
 }
 
-init :: proc{init_new, init_new_integer};
+/*
+	Initialize an `Int` as a copy from another `Int`.
+*/
+init_copy :: proc(src: ^Int, minimize := false, allocator_zeroes := true, allocator := context.allocator) -> (a: ^Int, err: Error) {
+	if !is_initialized(src) {
+		return nil, .Invalid_Input;
+	}
+
+	a, err = init_new(allocator_zeroes, allocator, src.used);
+	if err == .OK {
+		copy(a, src);
+	}
+	return;
+}
+
+init :: proc{init_new, init_from_integer, init_copy};
 
 /*
 	Helpers to set an `Int` to a specific value.
@@ -123,7 +137,7 @@ copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 	/*
 		Grow `dest` to fit `src`.
 	*/
-	if err = grow(dest, min(src.used, _DEFAULT_DIGIT_COUNT)); err != .OK {
+	if err = grow(dest, src.used); err != .OK {
 		return err;
 	}
 
@@ -226,6 +240,9 @@ extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
 	return 1 if ((a.digit[limb] & i) != 0) else 0, .OK;
 }
 
+/*
+	TODO: Optimize.
+*/
 extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
 	if count > _WORD_BITS || count < 1 {
 		return 0, .Invalid_Input;

+ 122 - 124
core/math/bigint/log.odin → core/math/big/log.odin

@@ -1,125 +1,123 @@
-package bigint
-
-/*
-	Copyright 2021 Jeroen van Rijn <[email protected]>.
-	Made available under Odin's BSD-2 license.
-
-	A BigInt implementation in Odin.
-	For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
-	The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
-*/
-
-import "core:fmt"
-
-log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
-	assert_initialized(a);
-	if is_neg(a) || is_zero(a) || base < 2 || DIGIT(base) > _DIGIT_MAX {
-		return -1, .Invalid_Input;
-	}
-
-	/*
-		Fast path for bases that are a power of two.
-	*/
-	if is_power_of_two(int(base)) {
-		return _log_power_of_two(a, base), .OK;
-	}
-
-	/*
-		Fast path for `Int`s that fit within a single `DIGIT`.
-	*/
-	if a.used == 1 {
-		return log_n_digit(a.digit[0], DIGIT(base)), .OK;
-	}
-
-    // if (MP_HAS(S_MP_LOG)) {
-    //    return s_mp_log(a, (mp_digit)base, c);
-    // }
-
-	return -1, .Unimplemented;
-}
-
-log_n :: proc{log_n_int, log_n_digit};
-
-/*
-	Returns the log2 of an `Int`, provided `base` is a power of two.
-	Don't call it if it isn't.
-*/
-_log_power_of_two :: proc(a: ^Int, base: DIGIT) -> (log: int) {
-	base := base;
-	y: int;
-	for y = 0; base & 1 == 0; {
-		y += 1;
-		base >>= 1;
-	}
-	return (count_bits(a) - 1) / y;
-}
-
-/*
-
-*/
-small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD) {
-	exponent := exponent; base := base;
-   	result = _WORD(1);
-
-   	for exponent != 0 {
-   		if exponent & 1 == 1 {
-   			result *= base;
-   		}
-   		exponent >>= 1;
-   		base *= base;
-   	}
-   	return result;
-}
-
-log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int) {
-	/*
-		If the number is smaller than the base, it fits within a fraction.
-		Therefore, we return 0.
-	*/
-	if a < base {
-		return 0;
-	}
-
-	/*
-		If a number equals the base, the log is 1.
-	*/
-	if a == base {
-		return 1;
-	}
-
-	N := _WORD(a);
-	bracket_low  := _WORD(1);
-	bracket_high := _WORD(base);
-	high := 1;
-	low  := 0;
-
-	for bracket_high < N {
-		low = high;
-		bracket_low = bracket_high;
-		high <<= 1;
-		bracket_high *= bracket_high;
-	}
-
-	for high - low > 1 {
-		mid := (low + high) >> 1;
-		bracket_mid := bracket_low * small_pow(_WORD(base), _WORD(mid - low));
-
-		if N < bracket_mid {
-			high = mid;
-			bracket_high = bracket_mid;
-		}
-		if N > bracket_mid {
-			low = mid;
-			bracket_low = bracket_mid;
-		}
-		if N == bracket_mid {
-			return mid;
-		}
-   	}
-
-   	if bracket_high == N {
-   		return high;
-   	} else {
-   		return low;
-   	}
+package big
+
+/*
+	Copyright 2021 Jeroen van Rijn <[email protected]>.
+	Made available under Odin's BSD-2 license.
+
+	A BigInt implementation in Odin.
+	For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
+	The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
+*/
+
+log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
+	assert_initialized(a);
+	if is_neg(a) || is_zero(a) || base < 2 || DIGIT(base) > _DIGIT_MAX {
+		return -1, .Invalid_Input;
+	}
+
+	/*
+		Fast path for bases that are a power of two.
+	*/
+	if is_power_of_two(int(base)) {
+		return _log_power_of_two(a, base), .OK;
+	}
+
+	/*
+		Fast path for `Int`s that fit within a single `DIGIT`.
+	*/
+	if a.used == 1 {
+		return log_n_digit(a.digit[0], DIGIT(base)), .OK;
+	}
+
+    // if (MP_HAS(S_MP_LOG)) {
+    //    return s_mp_log(a, (mp_digit)base, c);
+    // }
+
+	return -1, .Unimplemented;
+}
+
+log_n :: proc{log_n_int, log_n_digit};
+
+/*
+	Returns the log2 of an `Int`, provided `base` is a power of two.
+	Don't call it if it isn't.
+*/
+_log_power_of_two :: proc(a: ^Int, base: DIGIT) -> (log: int) {
+	base := base;
+	y: int;
+	for y = 0; base & 1 == 0; {
+		y += 1;
+		base >>= 1;
+	}
+	return (count_bits(a) - 1) / y;
+}
+
+/*
+
+*/
+small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD) {
+	exponent := exponent; base := base;
+   	result = _WORD(1);
+
+   	for exponent != 0 {
+   		if exponent & 1 == 1 {
+   			result *= base;
+   		}
+   		exponent >>= 1;
+   		base *= base;
+   	}
+   	return result;
+}
+
+log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int) {
+	/*
+		If the number is smaller than the base, it fits within a fraction.
+		Therefore, we return 0.
+	*/
+	if a < base {
+		return 0;
+	}
+
+	/*
+		If a number equals the base, the log is 1.
+	*/
+	if a == base {
+		return 1;
+	}
+
+	N := _WORD(a);
+	bracket_low  := _WORD(1);
+	bracket_high := _WORD(base);
+	high := 1;
+	low  := 0;
+
+	for bracket_high < N {
+		low = high;
+		bracket_low = bracket_high;
+		high <<= 1;
+		bracket_high *= bracket_high;
+	}
+
+	for high - low > 1 {
+		mid := (low + high) >> 1;
+		bracket_mid := bracket_low * small_pow(_WORD(base), _WORD(mid - low));
+
+		if N < bracket_mid {
+			high = mid;
+			bracket_high = bracket_mid;
+		}
+		if N > bracket_mid {
+			low = mid;
+			bracket_low = bracket_mid;
+		}
+		if N == bracket_mid {
+			return mid;
+		}
+   	}
+
+   	if bracket_high == N {
+   		return high;
+   	} else {
+   		return low;
+   	}
 }

+ 206 - 0
core/math/big/logical.odin

@@ -0,0 +1,206 @@
+package big
+
+/*
+	Copyright 2021 Jeroen van Rijn <[email protected]>.
+	Made available under Odin's BSD-2 license.
+
+	A BigInt implementation in Odin.
+	For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
+	The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
+
+	This file contains logical operations like `and`, `or` and `xor`.
+*/
+
+/*
+	The `and`, `or` and `xor` binops differ in two lines only.
+	We could handle those with a switch, but that adds overhead.
+*/
+
+/*
+	2's complement `and`, returns `dest = a & b;`
+*/
+and :: proc(dest, a, b: ^Int) -> (err: Error) {
+	assert_initialized(dest); assert_initialized(a); assert_initialized(b);
+
+	used := max(a.used, b.used) + 1;
+	neg: bool;
+
+	neg  = is_neg(a) && is_neg(b);
+
+	ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
+
+	/*
+		Grow the destination to accomodate the result.
+	*/
+	if err = grow(dest, used); err != .OK {
+		return err;
+	}
+
+	for i := 0; i < used; i += 1 {
+		x, y: DIGIT;
+
+		/*
+			Convert to 2's complement if negative.
+		*/
+		if is_neg(a) {
+			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
+			x = ac & _MASK;
+			ac >>= _DIGIT_BITS;
+		} else {
+			x = 0 if i >= a.used else a.digit[i];
+		}
+
+		/*
+			Convert to 2's complement if negative.
+		*/
+		if is_neg(a) {
+			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
+			y = bc & _MASK;
+			bc >>= _DIGIT_BITS;
+		} else {
+			y = 0 if i >= b.used else b.digit[i];
+		}
+
+		dest.digit[i] = x & y;
+
+		/*
+			Convert to to sign-magnitude if negative.
+		*/
+		if neg {
+			cc += ~dest.digit[i] & _MASK;
+			dest.digit[i] = cc & _MASK;
+			cc >>= _DIGIT_BITS;
+		}
+	}
+
+	dest.used = used;
+	dest.sign = .Negative if neg else .Zero_or_Positive;
+	clamp(dest);
+	return .OK;
+}
+
+/*
+	2's complement `or`, returns `dest = a | b;`
+*/
+or :: proc(dest, a, b: ^Int) -> (err: Error) {
+	assert_initialized(dest); assert_initialized(a); assert_initialized(b);
+
+	used := max(a.used, b.used) + 1;
+	neg: bool;
+
+	neg  = is_neg(a) || is_neg(b);
+
+	ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
+
+	/*
+		Grow the destination to accomodate the result.
+	*/
+	if err = grow(dest, used); err != .OK {
+		return err;
+	}
+
+	for i := 0; i < used; i += 1 {
+		x, y: DIGIT;
+
+		/*
+			Convert to 2's complement if negative.
+		*/
+		if is_neg(a) {
+			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
+			x = ac & _MASK;
+			ac >>= _DIGIT_BITS;
+		} else {
+			x = 0 if i >= a.used else a.digit[i];
+		}
+
+		/*
+			Convert to 2's complement if negative.
+		*/
+		if is_neg(a) {
+			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
+			y = bc & _MASK;
+			bc >>= _DIGIT_BITS;
+		} else {
+			y = 0 if i >= b.used else b.digit[i];
+		}
+
+		dest.digit[i] = x | y;
+
+		/*
+			Convert to to sign-magnitude if negative.
+		*/
+		if neg {
+			cc += ~dest.digit[i] & _MASK;
+			dest.digit[i] = cc & _MASK;
+			cc >>= _DIGIT_BITS;
+		}
+	}
+
+	dest.used = used;
+	dest.sign = .Negative if neg else .Zero_or_Positive;
+	clamp(dest);
+	return .OK;
+}
+
+/*
+	2's complement `xor`, returns `dest = a ~ b;`
+*/
+xor :: proc(dest, a, b: ^Int) -> (err: Error) {
+	assert_initialized(dest); assert_initialized(a); assert_initialized(b);
+
+	used := max(a.used, b.used) + 1;
+	neg: bool;
+
+	neg  = is_neg(a) != is_neg(b);
+
+	ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
+
+	/*
+		Grow the destination to accomodate the result.
+	*/
+	if err = grow(dest, used); err != .OK {
+		return err;
+	}
+
+	for i := 0; i < used; i += 1 {
+		x, y: DIGIT;
+
+		/*
+			Convert to 2's complement if negative.
+		*/
+		if is_neg(a) {
+			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
+			x = ac & _MASK;
+			ac >>= _DIGIT_BITS;
+		} else {
+			x = 0 if i >= a.used else a.digit[i];
+		}
+
+		/*
+			Convert to 2's complement if negative.
+		*/
+		if is_neg(a) {
+			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
+			y = bc & _MASK;
+			bc >>= _DIGIT_BITS;
+		} else {
+			y = 0 if i >= b.used else b.digit[i];
+		}
+
+		dest.digit[i] = x ~ y;
+
+		/*
+			Convert to to sign-magnitude if negative.
+		*/
+		if neg {
+			cc += ~dest.digit[i] & _MASK;
+			dest.digit[i] = cc & _MASK;
+			cc >>= _DIGIT_BITS;
+		}
+	}
+
+	dest.used = used;
+	dest.sign = .Negative if neg else .Zero_or_Positive;
+	clamp(dest);
+	return .OK;
+}

+ 9 - 8
core/math/bigint/radix.odin → core/math/big/radix.odin

@@ -1,4 +1,4 @@
-package bigint
+package big
 
 /*
 	Copyright 2021 Jeroen van Rijn <[email protected]>.
@@ -11,21 +11,20 @@ package bigint
 	This file contains radix conversions, `string_to_int` (atoi) and `int_to_string` (itoa).
 */
 
-import "core:mem"
 import "core:intrinsics"
 import "core:fmt"
 import "core:strings"
-import "core:slice"
 
 /*
 	This version of `itoa` allocates one behalf of the caller. The caller must free the string.
 */
 itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) {
+	radix := radix;
 	assert_initialized(a);
 	/*
 		Radix defaults to 10.
 	*/
-	radix := radix if radix > 0 else 10;
+	radix = radix if radix > 0 else 10;
 
 	/*
 		TODO: If we want to write a prefix for some of the radixes, we can oversize the buffer.
@@ -87,11 +86,12 @@ itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator
 	This version of `itoa` allocates one behalf of the caller. The caller must free the string.
 */
 itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -> (res: cstring, err: Error) {
+	radix := radix;
 	assert_initialized(a);
 	/*
 		Radix defaults to 10.
 	*/
-	radix := radix if radix > 0 else 10;
+	radix = radix if radix > 0 else 10;
 
 	s: string;
 	s, err = itoa_string(a, radix, true, allocator);
@@ -119,11 +119,12 @@ itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -
 	and having to perform a buffer overflow check each character.
 */
 itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
+	radix := radix;
 	assert_initialized(a); size := size;
 	/*
 		Radix defaults to 10.
 	*/
-	radix := radix if radix > 0 else 10;
+	radix = radix if radix > 0 else 10;
 	if radix < 2 || radix > 64 {
 		return 0, .Invalid_Input;
 	}
@@ -197,10 +198,10 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
 			buffer[available] = 0;
 		}
 
-		mask  := _WORD(radix - 1);
+		// mask  := _WORD(radix - 1);
 		shift := int(log_n(DIGIT(radix), 2));
 		count := int(count_bits(a));
-		digit: _WORD;
+		// digit: _WORD;
 
 		for offset := 0; offset < count; offset += 4 {
 			bits_to_get := int(min(count - offset, shift));

+ 0 - 3
core/math/bigint/build.bat

@@ -1,3 +0,0 @@
-@echo off
-odin run .
-rem -vet

+ 0 - 113
core/math/bigint/logical.odin

@@ -1,113 +0,0 @@
-package bigint
-
-/*
-	Copyright 2021 Jeroen van Rijn <[email protected]>.
-	Made available under Odin's BSD-2 license.
-
-	A BigInt implementation in Odin.
-	For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
-	The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
-
-	This file contains logical operations like `and`, `or` and `xor`.
-*/
-
-import "core:fmt"
-
-@private
-Operator :: enum u8 {
-	And = 1,
-	Or  = 2,
-	Xor = 3,
-}
-
-/*
-	2's complement `and`, returns `dest = a & b;`
-*/
-
-_binary_op :: proc(dest, a, b: ^Int, op: Operator) -> (err: Error) {
-	assert_initialized(dest); assert_initialized(a); assert_initialized(b);
-
-	used := max(a.used, b.used) + 1;
-	neg: bool;
-
-	switch(op) {
-	case .And:
-		neg  = is_neg(a) && is_neg(b);
-	case .Or:
-		neg  = is_neg(a) || is_neg(b);
-	case .Xor:
-		neg  = is_neg(a) != is_neg(b);
-	case:
-		return .Invalid_Input;
-	}
-
-	ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
-
-	/*
-		Grow the destination to accomodate the result.
-	*/
-	if err = grow(dest, used); err != .OK {
-		return err;
-	}
-
-	for i := 0; i < used; i += 1 {
-		x, y: DIGIT;
-
-		/*
-			Convert to 2's complement if negative.
-		*/
-		if is_neg(a) {
-			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
-			x = ac & _MASK;
-			ac >>= _DIGIT_BITS;
-		} else {
-			x = 0 if i >= a.used else a.digit[i];
-		}
-
-		/*
-			Convert to 2's complement if negative.
-		*/
-		if is_neg(a) {
-			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
-			y = bc & _MASK;
-			bc >>= _DIGIT_BITS;
-		} else {
-			y = 0 if i >= b.used else b.digit[i];
-		}
-
-		switch(op) {
-		case .And:
-			dest.digit[i] = x & y;
-		case .Or:
-			dest.digit[i] = x | y;
-		case .Xor:
-			dest.digit[i] = x ~ y;
-		}
-
-		/*
-			Convert to to sign-magnitude if negative.
-		*/
-		if neg {
-			cc += ~dest.digit[i] & _MASK;
-			dest.digit[i] = cc & _MASK;
-			cc >>= _DIGIT_BITS;
-		}
-	}
-
-	dest.used = used;
-	dest.sign = .Negative if neg else .Zero_or_Positive;
-	clamp(dest);
-	return .OK;
-}
-
-and :: proc(dest, a, b: ^Int) -> (err: Error) {
-	return _binary_op(dest, a, b, .And);
-}
-
-or  :: proc(dest, a, b: ^Int) -> (err: Error) {
-	return _binary_op(dest, a, b, .Or);
-}
-
-xor :: proc(dest, a, b: ^Int) -> (err: Error) {
-	return _binary_op(dest, a, b, .Xor);
-}