mirror of
https://github.com/lucannez64/darling-lol.git
synced 2026-10-26 19:47:42 +00:00
495 lines
18 KiB
Diff
495 lines
18 KiB
Diff
diff --git a/src/ccder.c b/src/ccder.c
|
|
index 5543c42..e843f46 100644
|
|
--- a/src/ccder.c
|
|
+++ b/src/ccder.c
|
|
@@ -308,8 +308,15 @@ ccder_encode_body(size_t size, const uint8_t* body,
|
|
return body_start;
|
|
}
|
|
|
|
+// As in Apple's implementation, the decoders accept a NULL `der` (the failed
|
|
+// result of a previous decode step) and return NULL for input that is
|
|
+// truncated or does not carry the expected tag.
|
|
const uint8_t *ccder_decode_tag(ccder_tag *tagp, const uint8_t *der, const uint8_t *der_end) {
|
|
size_t tag_len = 1;
|
|
+
|
|
+ if (der == NULL || der >= der_end)
|
|
+ return NULL;
|
|
+
|
|
*tagp = ((ccder_tag)(der[0] >> 5)) << CCDER_TAG_MASK_SHIFT_BACK;
|
|
|
|
if ((der[0] & 0x1f) == 0x1f) {
|
|
@@ -317,11 +324,13 @@ const uint8_t *ccder_decode_tag(ccder_tag *tagp, const uint8_t *der, const uint8
|
|
// 0x80 == 0b10000000
|
|
size_t i = 0;
|
|
do {
|
|
+ if (der + i + 1 >= der_end)
|
|
+ return NULL;
|
|
// 0x7f == 0b01111111
|
|
*tagp |= (((ccder_tag)der[i + 1] & 0x7fU) << (i * 7));
|
|
++i;
|
|
++tag_len;
|
|
- } while (der[i + 1] & 0x80);
|
|
+ } while (der[i] & 0x80);
|
|
*tagp <<= 5;
|
|
*tagp |= 0x1f;
|
|
} else {
|
|
@@ -333,26 +342,40 @@ const uint8_t *ccder_decode_tag(ccder_tag *tagp, const uint8_t *der, const uint8
|
|
}
|
|
|
|
const uint8_t* ccder_decode_len(size_t* lenp, const uint8_t* der, const uint8_t* der_end) {
|
|
- size_t len_len = 1;
|
|
+ size_t len = 0;
|
|
+
|
|
+ if (der == NULL || der >= der_end)
|
|
+ return NULL;
|
|
|
|
if (der[0] & 0x80) {
|
|
// long form
|
|
- len_len = der[0] & 0x7f;
|
|
+ size_t len_len = der[0] & 0x7f;
|
|
++der;
|
|
+ if (len_len == 0 || len_len > sizeof(size_t) || (size_t)(der_end - der) < len_len)
|
|
+ return NULL;
|
|
for (size_t i = len_len; i > 0; --i)
|
|
- *lenp |= (size_t)der[len_len - i] << ((i - 1) * 8);
|
|
+ len |= (size_t)der[len_len - i] << ((i - 1) * 8);
|
|
+ der += len_len;
|
|
} else {
|
|
// short form
|
|
- *lenp = der[0] & 0x7f;
|
|
+ len = der[0] & 0x7f;
|
|
+ ++der;
|
|
}
|
|
|
|
- return der + len_len;
|
|
+ if ((size_t)(der_end - der) < len)
|
|
+ return NULL;
|
|
+
|
|
+ *lenp = len;
|
|
+ return der;
|
|
}
|
|
|
|
const uint8_t *ccder_decode_tl(ccder_tag expected_tag, size_t *lenp,
|
|
const uint8_t *der, const uint8_t *der_end) {
|
|
ccder_tag tag_found = 0;
|
|
- return ccder_decode_len(lenp, ccder_decode_tag(&tag_found, der, der_end), der_end);
|
|
+ der = ccder_decode_tag(&tag_found, der, der_end);
|
|
+ if (der == NULL || tag_found != expected_tag)
|
|
+ return NULL;
|
|
+ return ccder_decode_len(lenp, der, der_end);
|
|
}
|
|
|
|
const uint8_t *
|
|
@@ -360,6 +383,10 @@ ccder_decode_constructed_tl(ccder_tag expected_tag, const uint8_t **body_end,
|
|
const uint8_t *der, const uint8_t *der_end) {
|
|
size_t body_len = 0;
|
|
const uint8_t* body_start = ccder_decode_tl(expected_tag, &body_len, der, der_end);
|
|
+ if (body_start == NULL) {
|
|
+ *body_end = der;
|
|
+ return NULL;
|
|
+ }
|
|
*body_end = body_start + body_len;
|
|
return body_start;
|
|
}
|
|
@@ -367,21 +394,16 @@ ccder_decode_constructed_tl(ccder_tag expected_tag, const uint8_t **body_end,
|
|
const uint8_t *
|
|
ccder_decode_sequence_tl(const uint8_t **body_end,
|
|
const uint8_t *der, const uint8_t *der_end) {
|
|
- // NOTE(@facekapow):
|
|
- // we don't just call `ccder_decode_constructed_tl` because in the future,
|
|
- // that method will check that the decoded tag is a CONSTRUCTED tag
|
|
-
|
|
- size_t body_len = 0;
|
|
- const uint8_t* body_start = ccder_decode_tl(CCDER_SEQUENCE, &body_len, der, der_end);
|
|
- *body_end = body_start + body_len;
|
|
- return body_start;
|
|
+ return ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, body_end, der, der_end);
|
|
}
|
|
|
|
const uint8_t *ccder_decode_uint_n(cc_size *n,
|
|
const uint8_t *der, const uint8_t *der_end) {
|
|
size_t num_len = 0;
|
|
const uint8_t* num_start = ccder_decode_tl(CCDER_INTEGER, &num_len, der, der_end);
|
|
- while (num_start[0] == 0) {
|
|
+ if (num_start == NULL)
|
|
+ return NULL;
|
|
+ while (num_len > 0 && num_start[0] == 0) {
|
|
--num_len;
|
|
++num_start;
|
|
}
|
|
@@ -393,7 +415,9 @@ const uint8_t *ccder_decode_uint(cc_size n, cc_unit *r,
|
|
const uint8_t *der, const uint8_t *der_end) {
|
|
size_t num_len = 0;
|
|
const uint8_t* num_start = ccder_decode_tl(CCDER_INTEGER, &num_len, der, der_end);
|
|
- while (num_start[0] == 0) {
|
|
+ if (num_start == NULL)
|
|
+ return NULL;
|
|
+ while (num_len > 0 && num_start[0] == 0) {
|
|
--num_len;
|
|
++num_start;
|
|
}
|
|
@@ -405,7 +429,9 @@ const uint8_t *ccder_decode_uint64(uint64_t* r,
|
|
const uint8_t *der, const uint8_t *der_end) {
|
|
size_t num_len = 0;
|
|
const uint8_t* num_start = ccder_decode_tl(CCDER_INTEGER, &num_len, der, der_end);
|
|
- while (num_start[0] == 0) {
|
|
+ if (num_start == NULL)
|
|
+ return NULL;
|
|
+ while (num_len > 0 && num_start[0] == 0) {
|
|
--num_len;
|
|
++num_start;
|
|
}
|
|
@@ -422,13 +448,15 @@ const uint8_t *ccder_decode_uint64(uint64_t* r,
|
|
const uint8_t *ccder_decode_seqii(cc_size n, cc_unit *r, cc_unit *s,
|
|
const uint8_t *der, const uint8_t *der_end) {
|
|
size_t seq_len = 0;
|
|
- return ccder_decode_uint(n, s, ccder_decode_uint(n, r, ccder_decode_tl(CCDER_SEQUENCE, &seq_len, der, der_end), der_end), der_end);
|
|
+ return ccder_decode_uint(n, s, ccder_decode_uint(n, r, ccder_decode_tl(CCDER_CONSTRUCTED_SEQUENCE, &seq_len, der, der_end), der_end), der_end);
|
|
}
|
|
|
|
const uint8_t *ccder_decode_oid(ccoid_t *oidp,
|
|
const uint8_t *der, const uint8_t *der_end) {
|
|
size_t oid_len = 0;
|
|
const uint8_t* oid_start = ccder_decode_tl(CCDER_OBJECT_IDENTIFIER, &oid_len, der, der_end);
|
|
+ if (oid_start == NULL)
|
|
+ return NULL;
|
|
size_t total_len = (size_t)(oid_start - der) + oid_len;
|
|
|
|
CCOID(*oidp) = der;
|
|
@@ -441,6 +469,8 @@ const uint8_t *ccder_decode_bitstring(const uint8_t **bit_string,
|
|
const uint8_t *der, const uint8_t *der_end) {
|
|
size_t byte_len = 0;
|
|
const uint8_t* bit_start = ccder_decode_tl(CCDER_BIT_STRING, &byte_len, der, der_end);
|
|
+ if (bit_start == NULL)
|
|
+ return NULL;
|
|
|
|
// NOTE(@facekapow):
|
|
// i'm not sure if Apple's API meant to include the *entire* bitstring including the leading
|
|
diff --git a/src/ccec.c b/src/ccec.c
|
|
index 8efd8fb..8c8dfcc 100644
|
|
--- a/src/ccec.c
|
|
+++ b/src/ccec.c
|
|
@@ -458,18 +458,17 @@ static const struct {
|
|
CC_UNIT_FORMAT_2(01, ff),
|
|
// }
|
|
// reciprocal of modulus p {
|
|
- // full hex = 20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
|
|
- CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 01),
|
|
+ // full hex = 80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000
|
|
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
|
|
+ CC_UNIT_FORMAT_8(00, 00, 40, 00, 00, 00, 00, 00),
|
|
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
|
|
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
|
|
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
|
|
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
|
|
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
|
|
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
|
|
- CC_UNIT_FORMAT_2(02, 00),
|
|
- // necessary because the reciprocal *must* be `n + 1` units in length
|
|
- CC_UNIT_FORMAT_1(00),
|
|
+ CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
|
|
+ CC_UNIT_FORMAT_8(00, 80, 00, 00, 00, 00, 00, 00),
|
|
// }
|
|
// coefficient a {
|
|
// full hex = 01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc
|
|
@@ -532,18 +531,17 @@ static const struct {
|
|
CC_UNIT_FORMAT_2(01, ff),
|
|
// }
|
|
// reciprocal of order n {
|
|
- // full hex = 2000000000000000000000000000000000000000000000000000000000000000005ae79787c40d069948033feb708f65a2fc44a36477663b851449048e16ec79bf7
|
|
- CC_UNIT_FORMAT_8(44, 90, 48, e1, 6e, c7, 9b, f7),
|
|
- CC_UNIT_FORMAT_8(c4, 4a, 36, 47, 76, 63, b8, 51),
|
|
- CC_UNIT_FORMAT_8(80, 33, fe, b7, 08, f6, 5a, 2f),
|
|
- CC_UNIT_FORMAT_8(ae, 79, 78, 7c, 40, d0, 69, 94),
|
|
- CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 05),
|
|
+ // full hex = 8000000000000000000000000000000000000000000000000000000000000000016b9e5e1f10341a65200cffadc23d968bf1128d91dd98ee14512412385bb1e6fdc408f501c8d1cd2dad1d7f46221c
|
|
+ CC_UNIT_FORMAT_8(cd, 2d, ad, 1d, 7f, 46, 22, 1c),
|
|
+ CC_UNIT_FORMAT_8(e6, fd, c4, 08, f5, 01, c8, d1),
|
|
+ CC_UNIT_FORMAT_8(ee, 14, 51, 24, 12, 38, 5b, b1),
|
|
+ CC_UNIT_FORMAT_8(96, 8b, f1, 12, 8d, 91, dd, 98),
|
|
+ CC_UNIT_FORMAT_8(1a, 65, 20, 0c, ff, ad, c2, 3d),
|
|
+ CC_UNIT_FORMAT_8(00, 01, 6b, 9e, 5e, 1f, 10, 34),
|
|
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
|
|
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
|
|
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
|
|
- CC_UNIT_FORMAT_2(02, 00),
|
|
- // necessary because the reciprocal *must* be `n + 1` units in length
|
|
- CC_UNIT_FORMAT_1(00),
|
|
+ CC_UNIT_FORMAT_8(00, 80, 00, 00, 00, 00, 00, 00),
|
|
// }
|
|
// cofactor h {
|
|
// full hex = 01
|
|
@@ -624,7 +622,9 @@ int ccec_import_pub(ccec_const_cp_t cp, size_t in_len, const uint8_t* in, ccec_p
|
|
}
|
|
|
|
const cc_size n = cczp_n(cp.zp);
|
|
- const cc_size size = ccn_sizeof_n(n);
|
|
+ // X9.63 coordinates are as wide as the prime, not as the limbs holding it
|
|
+ // (P-521 is 66 bytes in 9 limbs, i.e. 72 bytes)
|
|
+ const size_t size = ccec_cp_prime_size(cp);
|
|
|
|
if (in_len != (2 * size) + 1) {
|
|
#if DEBUG
|
|
@@ -675,7 +675,24 @@ int ccec_verify(ccec_pub_ctx_t key, size_t digest_len, const uint8_t* digest, si
|
|
cc_unit e[n];
|
|
memset(e, 0, sizeof e);
|
|
|
|
- ccn_read_uint(n, e, (log_2_n >= 8 * digest_len) ? (log_2_n + 7) / 8 : digest_len, digest);
|
|
+ {
|
|
+ // ANSI X9.62: e is the leftmost bitlen(order) bits of the digest
|
|
+ size_t use_len = digest_len;
|
|
+ if (8 * use_len > log_2_n)
|
|
+ use_len = (log_2_n + 7) / 8;
|
|
+
|
|
+ ccn_read_uint(n, e, use_len, digest);
|
|
+
|
|
+ const size_t excess_bits = 8 * use_len - log_2_n;
|
|
+ if (8 * use_len > log_2_n && excess_bits > 0) {
|
|
+ // excess_bits is below 8, so a single pass over the units suffices
|
|
+ for (cc_size i = 0; i < n; ++i) {
|
|
+ e[i] >>= excess_bits;
|
|
+ if (i + 1 < n)
|
|
+ e[i] |= e[i + 1] << (CCN_UNIT_BITS - excess_bits);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
|
|
cc_unit r[n];
|
|
cc_unit s[n];
|
|
diff --git a/src/ccn.c b/src/ccn.c
|
|
index 3bfc8d1..e5c26b0 100644
|
|
--- a/src/ccn.c
|
|
+++ b/src/ccn.c
|
|
@@ -216,185 +216,37 @@ void ccn_lcm(cc_size n, cc_unit *r2n, const cc_unit *s, const cc_unit *t) {
|
|
#define CC_COMBINE(lo, hi) ((hi << (CCN_UNIT_BITS >> 1)) | lo)
|
|
|
|
void ccn_mul(cc_size n, cc_unit *r_2n, const cc_unit *s, const cc_unit *t) {
|
|
- // we're using the karatsuba algorithm in base 2^64
|
|
- // in the following pseudocode, B is the base of the numbers
|
|
- /*
|
|
- procedure karatsuba(num1, num2)
|
|
- if (num1 < B) and (num2 < B)
|
|
- return num1 * num2
|
|
-
|
|
- // Calculates the size of the numbers.
|
|
- m = max(size_base(num1, B), size_base(num2, B))
|
|
- m2 = floor(m / 2)
|
|
-
|
|
- // Split the digit sequences in the middle.
|
|
- high1, low1 = split_at(num1, m2)
|
|
- high2, low2 = split_at(num2, m2)
|
|
-
|
|
- // 3 calls made to numbers approximately half the size.
|
|
- z0 = karatsuba(low1, low2)
|
|
- z1 = karatsuba(high1, high2)
|
|
- z2 = karatsuba((low1 + high1), (low2 + high2))
|
|
-
|
|
- t0 = (z2 - z0 - z1) * (B ** m2)
|
|
- t1 = z1 * (B ** (m2 * 2))
|
|
- // this is equivalent to:
|
|
- // t0 = (z2 - z0 - z1) << m2
|
|
- // t1 = z1 << (m2 * 2)
|
|
-
|
|
- return t0 + t1 + z0
|
|
- */
|
|
- cc_size s_n = ccn_n(n, s);
|
|
- cc_size t_n = ccn_n(n, t);
|
|
-
|
|
+ // schoolbook multiplication; the operands here are at most a few dozen
|
|
+ // units, where it is faster than any divide and conquer scheme.
|
|
+ // the result must not overlap the operands.
|
|
memset(r_2n, 0, ccn_sizeof_n(n * 2));
|
|
|
|
- if (s_n < 2 && t_n < 2) {
|
|
- // multiplication algorithm that prevents overflow
|
|
- // based on https://stackoverflow.com/a/1815371
|
|
- const cc_unit s_hi = CC_HI_BITS(s[0]);
|
|
- const cc_unit s_lo = CC_LO_BITS(s[0]);
|
|
- const cc_unit t_hi = CC_HI_BITS(t[0]);
|
|
- const cc_unit t_lo = CC_LO_BITS(t[0]);
|
|
-
|
|
- cc_unit x = s_lo * t_lo;
|
|
- const cc_unit prod_0 = CC_LO_BITS(x);
|
|
-
|
|
- x = s_hi * t_lo + CC_HI_BITS(x);
|
|
- cc_unit prod_1 = CC_LO_BITS(x);
|
|
- cc_unit prod_2 = CC_HI_BITS(x);
|
|
-
|
|
- x = prod_1 + s_lo * t_hi;
|
|
- prod_1 = CC_LO_BITS(x);
|
|
-
|
|
- x = prod_2 + s_hi * t_hi + CC_HI_BITS(x);
|
|
+#if CCN_UNIT_SIZE == 8
|
|
+ for (cc_size i = 0; i < n; ++i) {
|
|
+ unsigned __int128 carry = 0;
|
|
+ const cc_unit s_i = s[i];
|
|
|
|
- r_2n[0] = CC_COMBINE(prod_0, prod_1);
|
|
- r_2n[1] = x;
|
|
+ for (cc_size j = 0; j < n; ++j) {
|
|
+ const unsigned __int128 accumulator = (unsigned __int128)s_i * t[j] + r_2n[i + j] + carry;
|
|
+ r_2n[i + j] = (cc_unit)accumulator;
|
|
+ carry = accumulator >> 64;
|
|
+ }
|
|
|
|
- return;
|
|
+ r_2n[i + n] = (cc_unit)carry;
|
|
}
|
|
+#else
|
|
+ for (cc_size i = 0; i < n; ++i) {
|
|
+ uint64_t carry = 0;
|
|
|
|
- cc_size max_n = s_n > t_n ? s_n : t_n;
|
|
- cc_size half_n = (max_n + 1) / 2;
|
|
- cc_size result_n = max_n * 2;
|
|
- cc_size intermediate_mul_n = (half_n * 2) + 2;
|
|
-
|
|
- cc_size max_size = ccn_sizeof_n(max_n);
|
|
- cc_size half_size = ccn_sizeof_n(half_n);
|
|
- cc_size half_size_for_addition = ccn_sizeof_n(half_n + 1);
|
|
- cc_size result_size = ccn_sizeof_n(result_n);
|
|
- cc_size intermediate_mul_size = ccn_sizeof_n(intermediate_mul_n);
|
|
- cc_size hi_half_size = max_size - half_size;
|
|
-
|
|
- // half_size_for_addition is used to allocate enough for addition
|
|
- // later when we do `hi + lo -> lo`
|
|
-
|
|
- cc_unit* s_hi = __builtin_alloca(half_size);
|
|
- cc_unit* s_lo = __builtin_alloca(half_size_for_addition);
|
|
-
|
|
- cc_unit* t_hi = __builtin_alloca(half_size);
|
|
- cc_unit* t_lo = __builtin_alloca(half_size_for_addition);
|
|
-
|
|
- memset(s_hi, 0, half_size);
|
|
- memset(s_lo, 0, half_size_for_addition);
|
|
- memset(t_hi, 0, half_size);
|
|
- memset(t_lo, 0, half_size_for_addition);
|
|
-
|
|
- // copy `half_size` bytes from `s` into `s_lo`
|
|
- memcpy(s_lo, s, half_size);
|
|
- // copy the rest into `s_hi`
|
|
- memcpy(s_hi, (uint8_t*)s + half_size, hi_half_size);
|
|
-
|
|
- // copy `half_size` bytes from `t` into `t_lo`
|
|
- memcpy(t_lo, t, half_size);
|
|
- // copy the rest into `t_hi`
|
|
- memcpy(t_hi, (uint8_t*)t + half_size, hi_half_size);
|
|
-
|
|
- cc_unit* z0 = __builtin_alloca(intermediate_mul_size);
|
|
- cc_unit* z1 = __builtin_alloca(intermediate_mul_size);
|
|
- cc_unit* z2 = __builtin_alloca(intermediate_mul_size);
|
|
-
|
|
- memset(z0, 0, intermediate_mul_size);
|
|
- memset(z1, 0, intermediate_mul_size);
|
|
- memset(z2, 0, intermediate_mul_size);
|
|
-
|
|
- // z0 = s_lo * t_lo
|
|
- ccn_mul(half_n, z0, s_lo, t_lo);
|
|
- // z1 = s_hi * t_hi
|
|
- ccn_mul(half_n, z1, s_hi, t_hi);
|
|
-
|
|
- // we add the `hi`s directly into the `lo`s to avoid additional allocations
|
|
-
|
|
- // s_lo = s_lo + s_hi
|
|
- cc_unit s_carry = ccn_add(half_n, s_lo, s_lo, s_hi);
|
|
- // t_lo = t_lo + s_hi
|
|
- cc_unit t_carry = ccn_add(half_n, t_lo, t_lo, t_hi);
|
|
-
|
|
- // this is safe; remember we already allocated an extra unit in the `lo`s
|
|
- s_lo[half_n] = s_carry;
|
|
- t_lo[half_n] = t_carry;
|
|
-
|
|
- // z2 = (s_lo + s_hi) * (t_lo + t_hi)
|
|
- ccn_mul(half_n + 1, z2, s_lo, t_lo);
|
|
-
|
|
- cc_unit* t0 = __builtin_alloca(result_size);
|
|
- cc_unit* t1 = __builtin_alloca(result_size);
|
|
-
|
|
- memset(t0, 0, result_size);
|
|
- memset(t1, 0, result_size);
|
|
-
|
|
- // since we don't use z2 anymore, we can just subtract z1 and z0
|
|
- // directly into it to avoid additional allocations
|
|
-
|
|
- // z2 = z2 - z1
|
|
- ccn_sub(intermediate_mul_n, z2, z2, z1);
|
|
- // z2 = z2 - z0
|
|
- ccn_sub(intermediate_mul_n, z2, z2, z0);
|
|
-
|
|
- // t0 = z2 - z1 - z0
|
|
- // technically, this is `t0 = z2` because we already subtracted them into z2
|
|
- ccn_set(intermediate_mul_n, t0, z2);
|
|
- // t0 = z1
|
|
- ccn_set(intermediate_mul_n, t1, z1);
|
|
-
|
|
- const cc_unit* t0_end = t0 + result_n;
|
|
- const cc_unit* t1_end = t1 + result_n;
|
|
-
|
|
- // t0 = t0 << half_n
|
|
- //
|
|
- // shift t0 to the left by `half_n` units
|
|
- // (which in little endian is actually shifting the bytes right)
|
|
- //
|
|
- // why don't we use `ccn_shift_left`? remember that we're in base 2^64
|
|
- // `ccn_shift_left` shifts base-2 bits, not base-2^64 bits (i.e. units)
|
|
- for (cc_size i = intermediate_mul_n; i > 0; --i) {
|
|
- cc_unit* tgt = t0 + half_n + (i - 1);
|
|
- // make sure that the target isn't past our boundary
|
|
- if (tgt < t0_end)
|
|
- *tgt = t0[i - 1];
|
|
- }
|
|
- // zero the previously occupied bytes
|
|
- for (cc_size i = 0; i < half_n; ++i)
|
|
- t0[i] = 0;
|
|
+ for (cc_size j = 0; j < n; ++j) {
|
|
+ const uint64_t accumulator = (uint64_t)s[i] * t[j] + r_2n[i + j] + carry;
|
|
+ r_2n[i + j] = (cc_unit)accumulator;
|
|
+ carry = accumulator >> CCN_UNIT_BITS;
|
|
+ }
|
|
|
|
- // t1 = t1 << (half_n * 2)
|
|
- //
|
|
- // shift t1 to the left by `half_n * 2` units
|
|
- for (cc_size i = intermediate_mul_n; i > 0; --i) {
|
|
- cc_unit* tgt = t1 + (half_n * 2) + (i - 1);
|
|
- // make sure that the target isn't past our boundary
|
|
- if (tgt < t1_end)
|
|
- *tgt = t1[i - 1];
|
|
+ r_2n[i + n] = (cc_unit)carry;
|
|
}
|
|
- // zero the previously occupied bytes
|
|
- for (cc_size i = 0; i < half_n * 2; ++i)
|
|
- t1[i] = 0;
|
|
-
|
|
- // r_2n = z0 + t0 + t1
|
|
- ccn_set(intermediate_mul_n, r_2n, z0);
|
|
- ccn_add(result_n, r_2n, r_2n, t0);
|
|
- ccn_add(result_n, r_2n, r_2n, t1);
|
|
+#endif
|
|
}
|
|
|
|
void ccn_mul_ws(cc_size count, cc_unit *r, const cc_unit *s, const cc_unit *t, cc_ws_t ws) {
|
|
diff --git a/src/cczp.c b/src/cczp.c
|
|
index 7a7d0a6..b4d3081 100644
|
|
--- a/src/cczp.c
|
|
+++ b/src/cczp.c
|
|
@@ -114,13 +114,11 @@ void cczp_mod(cczp_const_t zp, cc_unit* result, const cc_unit* operand, cc_ws_t
|
|
memset(r_extra, 0, normal_size);
|
|
bool underflow = ccn_sub(n + 1, r_extra, r_1, r_2);
|
|
|
|
- // `if r < 0`
|
|
- if (underflow) {
|
|
- for (cc_size i = 0; i < n + 1; ++i)
|
|
- r_extra[i] = ~r_extra[i];
|
|
-
|
|
- ccn_add1(n + 1, r_extra, r_extra, 1);
|
|
- }
|
|
+ // `if r < 0, r = r + b^(k + 1)`
|
|
+ // the subtraction above wrapped modulo b^(k + 1), which is exactly that
|
|
+ // addition. (Negating the wrapped value instead yields something close to
|
|
+ // b^(k + 1), and the loop below would then run for ~2^64 iterations.)
|
|
+ (void)underflow;
|
|
|
|
// `while r >= m`
|
|
while (ccn_cmp(n + 1, r_extra, m_copy) >= 0) {
|