corecrypto/ccn/crypto_test/crypto_test_ccn.c

694 lines
22 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Copyright (c) (2015,2016,2017,2018,2019,2020) Apple Inc. All rights reserved.
*
* corecrypto is licensed under Apple Inc.s Internal Use License Agreement (which
* is contained in the License.txt file distributed with corecrypto) and only to
* people who accept that license. IMPORTANT: Any license rights granted to you by
* Apple Inc. (if any) are limited to internal use within your organization only on
* devices and computers you own or control, for the sole purpose of verifying the
* security characteristics and correct functioning of the Apple Software. You may
* not, directly or indirectly, redistribute the Apple Software or any portions thereof.
*/
#include "cc_debug.h"
#include <corecrypto/cczp.h>
#include <corecrypto/ccrng.h>
#include <corecrypto/ccn.h>
#include "crypto_test_ccn.h"
#include "testmore.h"
#include "testbyteBuffer.h"
#include "testccnBuffer.h"
#include "ccn_op.h"
#include "ccn_internal.h"
#include "cc_memory.h"
#include <corecrypto/cc.h>
#include "cczp_internal.h"
static int test_ccn_sqr()
{
ccnBuffer input = hexStringToCcn("FFFFFFFFffffffffFFFFFFFFffffffffFFFFFFFFffffffff");
cc_size n = input->len;
cc_unit square_result[n * 2];
cc_unit square_ws_result[n * 2];
cc_unit mult_result[n * 2];
CC_DECL_WORKSPACE_OR_FAIL(workspace, CCN_MUL_WS_WORKSPACE_N(n));
ccn_sqr_ws(workspace, n, square_ws_result, input->units);
CC_FREE_WORKSPACE(workspace);
ccn_sqr(n, square_result, input->units);
ccn_mul(n, mult_result, input->units, input->units);
ok_ccn_cmp(n, square_result, mult_result, "ccn_sqr failed");
ok_ccn_cmp(n, square_ws_result, mult_result, "ccn_sqr_ws failed");
free(input);
return 1;
}
static void mult(cc_unit *r, cc_size ns, const cc_unit *s, cc_size nt, const cc_unit *t)
{
cc_assert(r != s);
cc_assert(r != t);
r[ns] = ccn_mul1(ns, r, s, t[0]);
while (nt > 1) {
r += 1;
t += 1;
nt -= 1;
r[ns] = ccn_addmul1(ns, r, s, t[0]);
}
}
static int verify_ccn_div_euclid(cc_size nq,
const cc_unit *q,
cc_size nr,
const cc_unit *r,
cc_size na,
const cc_unit *a,
cc_size nd,
const cc_unit *d)
{
cc_unit v[nq + nd];
// ccn_zero(nq+nd, v);
mult(v, nq, q, nd, d);
ccn_addn(nq + nd, v, v, nr, r);
int rc = ccn_cmp(na, a, v);
return rc;
}
#define CCN_READ_WRITE_TEST_N 3
#define CCN_READ_WRITE_TEST_BYTES ccn_sizeof_n(CCN_READ_WRITE_TEST_N)
static int test_ccn_write_test(size_t size) {
int rc = 1;
cc_assert(size<=CCN_READ_WRITE_TEST_BYTES);
cc_unit t [CCN_READ_WRITE_TEST_N];
uint8_t t_bytes[size+1+CCN_UNIT_SIZE];
uint8_t expected_t_bytes[size+2+CCN_UNIT_SIZE];
size_t MSByte_index = sizeof(expected_t_bytes)-size-1;
size_t LSByte_index = sizeof(expected_t_bytes)-2;
// Set a big integer with the given size
ccn_clear(CCN_READ_WRITE_TEST_N,t);
cc_clear(sizeof(expected_t_bytes),expected_t_bytes);
if (size>0) {
ccn_set_bit(t, 0, 1);
ccn_set_bit(t, size*8-1, 1);
expected_t_bytes[LSByte_index]=0x01;
expected_t_bytes[MSByte_index]|=0x80;
}
if (size>1) {
ccn_set_bit(t, 9, 1);
expected_t_bytes[LSByte_index-1]|=0x02;
}
// Test ccn_write_uint, which supports truncation
if(size>0) {
ccn_write_uint(CCN_READ_WRITE_TEST_N,t,size-1,t_bytes);
rc&=ok_memcmp(t_bytes, &expected_t_bytes[MSByte_index], size-1, "Size %zu: Truncated output",size);
}
ccn_write_uint(CCN_READ_WRITE_TEST_N,t,size,t_bytes);
rc&=ok_memcmp(t_bytes, &expected_t_bytes[MSByte_index], size, "Size %zu: Exact output",size);
ccn_write_uint(CCN_READ_WRITE_TEST_N,t,size+1,t_bytes);
rc&=ok_memcmp(t_bytes, &expected_t_bytes[MSByte_index], size, "Size %zu: Extra output",size);
// Test ccn_write_uint_padded, which supports truncation and padding
if(size>0) {
rc&=is(ccn_write_uint_padded(CCN_READ_WRITE_TEST_N,t,size-1,t_bytes), 0, "Size %zu: return value",size);
rc&=ok_memcmp(t_bytes, &expected_t_bytes[MSByte_index], size-1, "Size %zu: Truncated output",size);
}
rc&=is(ccn_write_uint_padded(CCN_READ_WRITE_TEST_N,t,size,t_bytes), 0, "Size %zu: Truncated output",size);
rc&=ok_memcmp(t_bytes, &expected_t_bytes[MSByte_index], size, "Size %zu: Exact output",size);
rc&=is(ccn_write_uint_padded(CCN_READ_WRITE_TEST_N,t,size+1,t_bytes), 1, "Size %zu: return value",size);
rc&=ok_memcmp(t_bytes, &expected_t_bytes[MSByte_index-1], size+1, "Size %zu: Extra output",size);
rc&=is(ccn_write_uint_padded(CCN_READ_WRITE_TEST_N,t,size+CCN_UNIT_SIZE,t_bytes), CCN_UNIT_SIZE, "Size %zu: return value",size);
rc&=ok_memcmp(t_bytes, &expected_t_bytes[MSByte_index-CCN_UNIT_SIZE], size+1, "Size %zu: Extra output",size);
rc&=is(ccn_write_uint_padded(CCN_READ_WRITE_TEST_N,t,size+1+CCN_UNIT_SIZE,t_bytes), 1+CCN_UNIT_SIZE, "Size %zu: return value",size);
rc&=ok_memcmp(t_bytes, &expected_t_bytes[MSByte_index-1-CCN_UNIT_SIZE], size+1, "Size %d: Extra output",size);
// Test ccn_write_uint_padded_ct, which supports padding, but not truncation
if(size>0) {
rc&=is(ccn_write_uint_padded_ct(CCN_READ_WRITE_TEST_N,t,size-1,t_bytes), CCERR_PARAMETER, "Size %zu: return value",size);
}
rc&=is(ccn_write_uint_padded_ct(CCN_READ_WRITE_TEST_N,t,size,t_bytes), 0, "Size %zu: return value",size);
rc&=ok_memcmp(t_bytes, &expected_t_bytes[MSByte_index], size, "Size %zu: Exact output",size);
rc&=is(ccn_write_uint_padded_ct(CCN_READ_WRITE_TEST_N,t,size+1,t_bytes), 1, "Size %zu: return value",size);
rc&=ok_memcmp(t_bytes, &expected_t_bytes[MSByte_index-1], size+1, "Size %zu: Extra output",size);
rc&=is(ccn_write_uint_padded_ct(CCN_READ_WRITE_TEST_N,t,size+CCN_UNIT_SIZE,t_bytes), CCN_UNIT_SIZE, "Size %zu: return value",size);
rc&=ok_memcmp(t_bytes, &expected_t_bytes[MSByte_index-CCN_UNIT_SIZE], size+1, "Size %zu: Extra output",size);
rc&=is(ccn_write_uint_padded_ct(CCN_READ_WRITE_TEST_N,t,size+1+CCN_UNIT_SIZE,t_bytes), 1+CCN_UNIT_SIZE, "Size %zu: return value",size);
rc&=ok_memcmp(t_bytes, &expected_t_bytes[MSByte_index-1-CCN_UNIT_SIZE], size+1, "Size %zu: Extra output",size);
return rc;
}
static int test_ccn_read_test(size_t size) {
int rc = 1;
cc_assert(size<=CCN_READ_WRITE_TEST_BYTES);
cc_unit expected_t [CCN_READ_WRITE_TEST_N];
cc_unit t [CCN_READ_WRITE_TEST_N];
uint8_t t_bytes[CCN_READ_WRITE_TEST_BYTES];
// Set a big integer with the given size
size_t MSByte_index = sizeof(t_bytes)-size;
size_t LSByte_index = sizeof(t_bytes)-1;
ccn_clear(CCN_READ_WRITE_TEST_N,expected_t);
cc_clear(sizeof(t_bytes),t_bytes);
if (size>0) {
ccn_set_bit(expected_t, 0, 1);
ccn_set_bit(expected_t, size*8-1, 1);
t_bytes[LSByte_index]=0x01;
t_bytes[MSByte_index]|=0x80;
}
if (size>1) {
ccn_set_bit(expected_t, 9, 1);
t_bytes[LSByte_index-1]|=0x02;
}
rc&=is(ccn_read_uint(CCN_READ_WRITE_TEST_N,t,CCN_READ_WRITE_TEST_BYTES,t_bytes),0,"Size %zu: Return value",size);
rc&=ok_ccn_cmp(CCN_READ_WRITE_TEST_N, t, expected_t, "Size %zu: Exact size",size);
if (size>0) {
rc&=is(ccn_read_uint(ccn_nof_size(size)-1,t,size,&t_bytes[MSByte_index]),CCERR_PARAMETER,"Size %zu: Overflow protection",size);
}
return rc;
}
#define num_of_tests_ccn_read_write 621 // Keep track of number of tests below so we can add to total testplan count
static int test_ccn_read_write() {
int rc = 1;
for (size_t i=0;i<=CCN_READ_WRITE_TEST_BYTES;i++) {
rc&=test_ccn_read_test(i);
rc&=test_ccn_write_test(i);
}
return rc;
}
static int test_ccn_div(size_t modulus_bits, size_t modulus_real_bits, size_t divisor_bits)
{
struct ccrng_state *rng = global_test_rng;
if (modulus_real_bits > modulus_bits)
modulus_real_bits = modulus_bits;
// create divisor
cc_size nd = ccn_nof(modulus_bits);
cc_unit d[nd];
cc_unit r[nd];
ccn_zero(nd, d);
ccn_random_bits(modulus_real_bits, d, rng);
// create random dividend
cc_size na = ccn_nof(divisor_bits);
cc_unit a[na];
ccn_zero(na, a);
cc_unit q[na];
ccn_zero(na, q);
ccn_random_bits(divisor_bits, a, rng);
// other rc's are input parameter error and are considered fine here
int rc = ccn_div_euclid(na, q, nd, r, na, a, nd, d);
ok(rc != -1, "ccn_div_euclid() returned error");
if (rc == 0) {
rc = verify_ccn_div_euclid(na, q, nd, r, na, a, nd, d);
} else
rc = 0;
return rc;
}
static void ccn_addn_kat()
{
ccnBuffer s = hexStringToCcn("FFFFFFFFffffffffFFFFFFFFffffffffFFFFFFFFffffffff");
ccnBuffer t = hexStringToCcn("00000000000000000000000000000001");
cc_size n = s->len;
cc_unit r[n];
cc_unit cr = ccn_add(t->len, r, s->units, t->units);
ok(cr == 1, "ccn_add carry KAT");
ok(ccn_is_zero(t->len, r), "ccn_add KAT");
cr = ccn_addn(n, r, s->units, t->len, t->units);
ok(cr == 1, "ccn_addn KAT");
ok(ccn_is_zero(n, r), "ccn_addn KAT");
cr = ccn_addn(t->len, r, s->units, t->len, t->units);
ok(cr == 1, "ccn_addn carry KAT");
ok(ccn_is_zero(t->len, r), "ccn_add KAT");
cr = ccn_add1(0, r, r, 7);
ok(cr == 7, "ccn_add1 carry KAT");
cr = ccn_addn(n, r, s->units, n, s->units);
ok(cr == 1, "ccn_addn carry KAT");
free(s);
free(t);
}
const struct rshift_test_vector {
const char *r;
const char *x;
const char *k;
} rshift_test_vectors[] = {
#include "../test_vectors/shift_right.kat"
};
const size_t rshift_test_vectors_num = CC_ARRAY_LEN(rshift_test_vectors);
static int test_ccn_shift_right()
{
for (unsigned i = 0; i < rshift_test_vectors_num; i++) {
const struct rshift_test_vector *test = &rshift_test_vectors[i];
ccnBuffer r = hexStringToCcn(test->r);
ccnBuffer x = hexStringToCcn(test->x);
ccnBuffer k = hexStringToCcn(test->k);
cc_size n = x->len;
cc_unit r2[n];
ccn_shift_right_multi(n, r2, x->units, (size_t)k->units[0]);
ok_ccn_cmp(r->len, r->units, r2, "r = x >> %llu", k->units[0]);
if (k->units[0] < CCN_UNIT_BITS) {
ccn_cond_shift_right(n, 1, r2, x->units, (size_t)k->units[0]);
ok_ccn_cmp(r->len, r->units, r2, "r = x >> %llu", k->units[0]);
} else {
ok(true, "easier to calculate the test count that way");
}
free(r);
free(x);
free(k);
}
return 0;
}
const struct lshift_test_vector {
const char *r;
const char *x;
const char *k;
} lshift_test_vectors[] = {
#include "../test_vectors/shift_left.kat"
};
const size_t lshift_test_vectors_num = CC_ARRAY_LEN(lshift_test_vectors);
static int test_ccn_shift_left()
{
for (unsigned i = 0; i < lshift_test_vectors_num; i++) {
const struct lshift_test_vector *test = &lshift_test_vectors[i];
ccnBuffer r = hexStringToCcn(test->r);
ccnBuffer x = hexStringToCcn(test->x);
ccnBuffer k = hexStringToCcn(test->k);
cc_size n = r->len;
cc_unit r2[n], x2[n];
ccn_setn(n, x2, x->len, x->units);
ccn_shift_left_multi(n, r2, x2, (size_t)k->units[0]);
ok_ccn_cmp(n, r->units, r2, "r = x << %llu", k->units[0]);
free(r);
free(x);
free(k);
}
return 0;
}
static void test_ccn_sub1(void)
{
cc_size n = 1;
cc_unit r[n];
cc_unit s[n];
ccnBuffer t1 = hexStringToCcn("00000000000000000000000000000001");
ccnBuffer t2 = hexStringToCcn("ffffffffffffffffffffffffffffffff");
ccnBuffer t3 = hexStringToCcn("00000001000000000000000000000001");
cc_unit borrow = ccn_sub1(0, r, s, 7);
is(borrow, (cc_unit)7, "ccn_sub1 with zero length scalar failed");
borrow = ccn_sub1(t1->len, t1->units, t1->units, 1);
is(borrow, 0, "ccn_sub1 shouldn't borrow");
ok(ccn_is_zero(t1->len, t1->units), "t1 should be 0");
borrow = ccn_sub1(t1->len, t1->units, t1->units, 1);
is(borrow, 1, "ccn_sub1 should borrow");
ok_ccn_cmp(t1->len, t1->units, t2->units, "t1 should be -1");
borrow = ccn_sub1(t2->len, t2->units, t2->units, ~CC_UNIT_C(0));
is(borrow, 0, "ccn_sub1 shouldn't borrow");
borrow = ccn_sub1(t3->len, t3->units, t3->units, 1);
is(borrow, 0, "ccn_sub1 shouldn't borrow");
ok(!ccn_is_zero(t3->len, t3->units), "t3 shouldn't be 0");
borrow = ccn_subn(t3->len, t3->units, t3->units, t2->len, t2->units);
is(borrow, 1, "ccn_subn should borrow");
free(t1);
free(t2);
free(t3);
}
static int test_ccn_cmp_zerolen(void)
{
int cmp;
cc_size n = 0;
cc_unit r[1];
cc_unit s[1];
cmp = ccn_cmp(n, r, s);
is(cmp, 0, "ccn_cmp with size zero should return zero");
return 1;
}
static void test_ccn_bitlen(void)
{
cc_unit z[5] = {0, 0, 0, 0, 0};
is(ccn_bitlen(5, z), 0, "ccn_bitlen() returned wrong result");
is(ccn_bitlen(0, z), 0, "ccn_bitlen() returned wrong result");
cc_unit a[5] = {0, 0, 1, 0, 0};
is(ccn_bitlen(5, a), 2 * CCN_UNIT_BITS + 1, "ccn_bitlen() returned wrong result");
cc_unit b[5] = {1, 0, 1, 0, 0};
is(ccn_bitlen(5, b), 2 * CCN_UNIT_BITS + 1, "ccn_bitlen() returned wrong result");
cc_unit c[5] = {1, 0, 1, 0, 1};
is(ccn_bitlen(5, c), 4 * CCN_UNIT_BITS + 1, "ccn_bitlen() returned wrong result");
cc_unit d[5] = {1, 0, 0, 0, 0};
is(ccn_bitlen(5, d), 1, "ccn_bitlen() returned wrong result");
}
static int test_ccn_abs(void)
{
cc_unit a[1] = {5};
cc_unit b[1] = {4};
cc_unit r[1];
CC_DECL_WORKSPACE_OR_FAIL(ws, CCN_ABS_WORKSPACE_N(1));
is(ccn_abs_ws(ws, 1, r, a, b), 0, "ccn_abs() returned wrong result");
ok(ccn_is_one(1, r), "ccn_abs() computed wrong result");
is(ccn_abs_ws(ws, 1, r, a, a), 0, "ccn_abs() returned wrong result");
ok(ccn_is_zero(1, r), "ccn_abs() computed wrong result");
is(ccn_abs_ws(ws, 1, r, b, a), 1, "ccn_abs() returned wrong result");
ok(ccn_is_one(1, r), "ccn_abs() computed wrong result");
CC_FREE_WORKSPACE(ws);
return 0;
}
static void test_ccn_cmpn()
{
cc_unit a[4] = { 1, 2, 0, 0 };
cc_unit b[4] = { 1, 2, 0, 3 };
// ns == nt
is(ccn_cmpn(0, a, 0, b), 0, "{} == {}");
is(ccn_cmpn(1, a, 1, b), 0, "{1} == {1}");
is(ccn_cmpn(2, a, 2, b), 0, "{1,2} == {1,2}");
is(ccn_cmpn(3, a, 3, b), 0, "{1,2,0} == {1,2,0}");
is(ccn_cmpn(4, a, 4, b), -1, "{1,2,0,0} < {1,2,0,3}");
is(ccn_cmpn(4, b, 4, a), 1, "{1,2,0,3} > {1,2,0,0}");
// ns > nt
is(ccn_cmpn(4, a, 3, b), 0, "{1,2,0,0} == {1,2,0}");
is(ccn_cmpn(4, a, 2, b), 0, "{1,2,0,0} == {1,2}");
is(ccn_cmpn(3, a, 2, b), 0, "{1,2,0} == {1,2}");
is(ccn_cmpn(4, a, 1, b), 1, "{1,2,0,0} > {1}");
is(ccn_cmpn(3, a, 1, b), 1, "{1,2,0} > {1}");
is(ccn_cmpn(2, a, 1, b), 1, "{1,2} > {1}");
is(ccn_cmpn(1, a, 0, b), 1, "{1} > {}");
// ns < nt
is(ccn_cmpn(3, b, 4, a), 0, "{1,2,0} == {1,2,0,0}");
is(ccn_cmpn(2, b, 4, a), 0, "{1,2} == {1,2,0,0}");
is(ccn_cmpn(2, b, 3, a), 0, "{1,2} == {1,2,0}");
is(ccn_cmpn(1, b, 4, a), -1, "{1} < {1,2,0,0}");
is(ccn_cmpn(1, b, 3, a), -1, "{1} < {1,2,0}");
is(ccn_cmpn(1, b, 2, a), -1, "{1} < {1,2}");
is(ccn_cmpn(0, b, 1, a), -1, "{} < {1}");
}
const struct gcd_test_vector {
const char *gcd;
const char *a;
const char *b;
const char *lcm;
} gcd_test_vectors[] = {
#include "../test_vectors/gcd_lcm.kat"
};
const size_t gcd_test_vectors_num = CC_ARRAY_LEN(gcd_test_vectors);
static int test_ccn_gcd()
{
for (unsigned i = 0; i < gcd_test_vectors_num; i++) {
const struct gcd_test_vector *test = &gcd_test_vectors[i];
ccnBuffer gcd = hexStringToCcn(test->gcd);
ccnBuffer a = hexStringToCcn(test->a);
ccnBuffer b = hexStringToCcn(test->b);
ccnBuffer lcm = hexStringToCcn(test->lcm);
cc_size n = CC_MAX(a->len, b->len);
cc_unit r[2 * n], an[n], bn[n];
CC_DECL_WORKSPACE_OR_FAIL(ws,
CC_MAX(CCN_GCD_WORKSPACE_N(n), CCN_LCM_WORKSPACE_N(n)));
size_t k = ccn_gcd_ws(ws, n, r, a->len, a->units, b->len, b->units);
ccn_shift_left_multi(n, r, r, k);
ok_ccn_cmp(gcd->len, gcd->units, r, "r = gcd(a, b)");
if (ccn_is_zero(n, r)) {
ok(true, "hard to predict the test count otherwise");
} else {
ccn_setn(n, an, a->len, a->units);
ccn_setn(n, bn, b->len, b->units);
ccn_lcm_ws(ws, n, r, an, bn);
ok_ccn_cmp(lcm->len, lcm->units, r, "r = lcm(a, b)");
}
CC_FREE_WORKSPACE(ws);
free(gcd);
free(a);
free(b);
free(lcm);
}
return 0;
}
static int test_ccn_div_exact()
{
cc_size n = ccn_nof(256);
cc_unit a[n * 2], b[n * 2], c[n * 2], r1[n * 2], r2[n * 2];
ccn_clear(n * 2, a);
ccn_clear(n * 2, b);
CC_DECL_WORKSPACE_OR_FAIL(ws,
CCN_DIV_EUCLID_WORKSPACE_SIZE(2 * n, 2 * n) + CCN_DIV_EXACT_WORKSPACE_N(2 * n));
for (size_t i = 0; i < 2000; i++) {
ccn_random(n, a, global_test_rng);
ccn_random(n, b, global_test_rng);
ccn_mul(n, c, a, b);
ccn_div_exact_ws(ws, n * 2, r1, c, b);
is(ccn_div_ws(ws, n * 2, r2, n * 2, c, n * 2, b), CCERR_OK, "ccn_div_ws() succeeded");
ok_ccn_cmp(n * 2, r1, r2, "quotients match");
}
// x / x == 1
ccn_div_exact_ws(ws, n, a, a, a);
ok(ccn_is_one(n * 2, a), "x / x == 1");
// x / 1 == x
ccn_div_exact_ws(ws, n, a, b, a);
ok_ccn_cmp(n, a, b, "x / 1 == x");
CC_FREE_WORKSPACE(ws);
return 0;
}
static int test_ccn_div_2n()
{
cc_size n = 2;
cc_unit q[n], r[n], a[n], d[n];
ccn_seti(n, a, 0x51);
ccn_seti(n, d, 0x10);
int rv = ccn_div_euclid(n, q, n, r, n, a, n, d);
is(rv, CCERR_OK, "ccn_div_euclid() failed");
is(ccn_n(n, q), 1, "wrong quotient");
is(q[0], 0x05, "wrong quotient");
is(ccn_n(n, r), 1, "wrong remainder");
is(r[0], 0x01, "wrong remainder");
return 0;
}
const struct invmod_test_vector {
const char *inv;
const char *x;
const char *m;
int rv;
} invmod_test_vectors[] = {
#include "../test_vectors/invmod.kat"
};
const size_t invmod_test_vectors_num = CC_ARRAY_LEN(invmod_test_vectors);
static int test_ccn_invmod()
{
for (unsigned i = 0; i < invmod_test_vectors_num; i++) {
const struct invmod_test_vector *test = &invmod_test_vectors[i];
ccnBuffer inv = hexStringToCcn(test->inv);
ccnBuffer x = hexStringToCcn(test->x);
ccnBuffer m = hexStringToCcn(test->m);
cc_size n = m->len;
cc_unit r[n];
CC_DECL_WORKSPACE_OR_FAIL(ws, CCN_INVMOD_WORKSPACE_N(n) +
CCZP_INIT_WORKSPACE_N(n) + CCZP_INV_FAST_WORKSPACE_N(n));
int rv = ccn_invmod_ws(ws, n, r, x->len, x->units, m->units);
is(rv, test->rv, "unexpected ccn_invmod_ws() result");
ok_ccn_cmp(inv->len, inv->units, r, "r = ccn_invmod_ws(x, m)");
// Test cczp_inv() and cczp_inv_fast().
if ((m->units[0] & 1) && ccn_cmpn(m->len, m->units, x->len, x->units) > 0) {
cczp_decl_n(n, zp);
CCZP_N(zp) = n;
ccn_set(n, CCZP_PRIME(zp), m->units);
cczp_init_ws(ws, zp);
cc_unit xn[n];
ccn_setn(n, xn, x->len, x->units);
int rv = cczp_inv_ws(ws, zp, r, xn);
is(rv, test->rv, "unexpected cczp_inv() result");
ok_ccn_cmp(inv->len, inv->units, r, "r = cczp_inv(x, m)");
rv = cczp_inv_fast_ws(ws, zp, r, xn);
is(rv, test->rv, "unexpected cczp_inv_fast() result");
ok_ccn_cmp(inv->len, inv->units, r, "r = cczp_inv_fast(x, m)");
} else {
ok(true, "always increase test count");
ok(true, "always increase test count");
ok(true, "always increase test count");
ok(true, "always increase test count");
}
CC_FREE_WORKSPACE(ws);
free(inv);
free(x);
free(m);
}
return 0;
}
#define MODULUS_BITS 653
#define MODULUS_REAL_BITS 457
#define DIVISOR_BITS 1985
int ccn_tests(TM_UNUSED int argc, TM_UNUSED char *const *argv)
{
int rc = 0;
size_t modulus_bits = MODULUS_BITS;
size_t modulus_real_bits = MODULUS_REAL_BITS;
size_t divisor_bits = DIVISOR_BITS;
int num_tests = 100335 + num_of_tests_ccn_read_write;
num_tests += 20; // ccn_cmpn
num_tests += 4002; // ccn_div_exact
num_tests += 5; // ccn_div_2n
num_tests += gcd_test_vectors_num * 2; // ccn_gcd
num_tests += rshift_test_vectors_num * 2; // ccn_shift_right
num_tests += lshift_test_vectors_num; // ccn_shift_left
num_tests += invmod_test_vectors_num * 6; // ccn_invmod
plan_tests(num_tests);
// Functional tests
for (int i = 0; i < 25000; i++) {
modulus_bits = cc_rand_unit() % 753 + 30;
modulus_real_bits = modulus_bits / (cc_rand_unit() % 4 + 1) + cc_rand_unit() % 5;
divisor_bits = modulus_bits * (cc_rand_unit() % 4 + 1) + cc_rand_unit() % 7;
rc = test_ccn_div(modulus_bits, modulus_real_bits, divisor_bits);
is(rc, 0, "test_ccn_div() division results doesn't verify");
divisor_bits = modulus_bits / (cc_rand_unit() % 3 + 1) + cc_rand_unit() % 7;
rc = test_ccn_div(modulus_bits, modulus_real_bits, divisor_bits);
is(rc, 0, "test_ccn_div() division results doesn't verify");
}
// Negative tests
cc_unit d[2] = { 0, 0 };
cc_unit a[5] = { 5, 4, 3, 2, 1 };
cc_unit q[5], r[2];
rc = ccn_div_euclid(5, q, 2, r, 5, a, 2, d);
is(rc, -2, "ccn_div_euclid() division by zero");
for (int i = 50; i >= 1; i--) {
d[0] = (cc_unit)i;
rc = ccn_div_euclid(5, q, 2, r, 5, a, 2, d);
is(rc, 0, "ccn_div_euclid()");
rc = verify_ccn_div_euclid(5, q, 2, r, 5, a, 2, d);
is(rc, 0, "ccn_div_euclid() division by small divisor");
}
// Make sure arithmetic right shift is in place
for (int i = 0; i < 200; i++) {
cc_unit v = cc_rand_unit();
ok(ccop_msb(v) == (ccn_bit(&v, CCN_UNIT_BITS - 1) ? ~(cc_unit)0 : 0), "ccop_msb() produces incorrect result");
}
ccn_addn_kat();
test_ccn_sub1();
test_ccn_shift_right();
test_ccn_shift_left();
is(test_ccn_sqr(), 1, "test_ccn_sqr failed");
is(test_ccn_cmp_zerolen(), 1, "test_ccn_cmp_zerolen failed");
is(test_ccn_read_write(),1, "test_ccn_read_write failed");
test_ccn_bitlen();
test_ccn_abs();
test_ccn_cmpn();
test_ccn_gcd();
test_ccn_div_exact();
test_ccn_div_2n();
test_ccn_invmod();
return rc;
}