694 lines
22 KiB
C
694 lines
22 KiB
C
/* 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;
|
||
}
|