corecrypto/ccckg/crypto_test/ccckgtest.c

462 lines
16 KiB
C
Raw Permalink 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) (2019) 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 <corecrypto/ccckg.h>
#include "ccckg_priv.h"
#include "cc_priv.h"
#include "testmore.h"
#include <corecrypto/ccsha2.h>
static int test_full_run(ccec_const_cp_t cp, const struct ccdigest_info *di)
{
struct ccrng_state *rng = global_test_rng;
ccec_full_ctx_decl_cp(cp, P_owner);
ccec_pub_ctx_decl_cp(cp, P_contrib);
ccec_ctx_init(cp, P_owner);
ccec_ctx_init(cp, P_contrib);
int rv;
ccckg_ctx_decl(cp, di, ctx_a);
ccckg_ctx_decl(cp, di, ctx_b);
ccckg_init(ctx_a, cp, di, rng);
ccckg_init(ctx_b, cp, di, rng);
uint8_t commitment[ccckg_sizeof_commitment(cp, di)];
rv = ccckg_contributor_commit(ctx_a, sizeof(commitment), commitment);
is(rv, 0, "Generated commitment");
uint8_t share[ccckg_sizeof_share(cp, di)];
rv = ccckg_owner_generate_share(ctx_b, sizeof(commitment), commitment, sizeof(share), share);
is(rv, 0, "Generated share");
uint8_t sk_a[32];
uint8_t opening[ccckg_sizeof_opening(cp, di)];
rv = ccckg_contributor_finish(ctx_a, sizeof(share), share, sizeof(opening), opening, P_contrib, sizeof(sk_a), sk_a);
is(rv, 0, "Opened commitment");
uint8_t sk_b[32];
rv = ccckg_owner_finish(ctx_b, sizeof(opening), opening, P_owner, sizeof(sk_b), sk_b);
is(rv, 0, "Owner finished");
ok_ccn_cmp(ccec_cp_n(cp), ccec_ctx_x(P_contrib), ccec_ctx_x(P_owner), "Ps don't match");
ok_memcmp_or_fail(sk_a, sk_b, sizeof(sk_a), "SKs don't match");
ccckg_ctx_clear(cp, di, ctx_a);
ccckg_ctx_clear(cp, di, ctx_b);
return 0;
}
static int test_bogus_inputs()
{
struct ccrng_state *rng = global_test_rng;
const struct ccdigest_info *di = ccsha256_di();
ccec_const_cp_t cp = ccec_cp_256();
ccec_full_ctx_decl_cp(cp, P_owner);
ccec_pub_ctx_decl_cp(cp, P_contrib);
ccec_full_ctx_decl_cp(ccec_cp_384(), P_bogus_full);
ccec_pub_ctx_decl_cp(ccec_cp_384(), P_bogus);
ccec_ctx_init(cp, P_owner);
ccec_ctx_init(cp, P_contrib);
int rv;
ccckg_ctx_decl(cp, di, ctx_a);
ccckg_ctx_decl(cp, di, ctx_b);
ccckg_init(ctx_a, cp, di, rng);
ccckg_init(ctx_b, cp, di, rng);
uint8_t commitment[ccckg_sizeof_commitment(cp, di)];
// Passing the wrong commitment size must fail.
rv = ccckg_contributor_commit(ctx_a, sizeof(commitment) + 1, commitment);
is(rv, CCERR_PARAMETER, "Generated commitment");
rv = ccckg_contributor_commit(ctx_a, sizeof(commitment), commitment);
is(rv, 0, "Generated commitment");
uint8_t share[ccckg_sizeof_share(cp, di)];
// Passing the wrong commitment size must fail.
rv = ccckg_owner_generate_share(ctx_b, sizeof(commitment) + 1, commitment, sizeof(share), share);
is(rv, CCERR_PARAMETER, "ccckg_owner_generate_share should fail");
// Passing the wrong share size must fail.
rv = ccckg_owner_generate_share(ctx_b, sizeof(commitment), commitment, sizeof(share) + 1, share);
is(rv, CCERR_PARAMETER, "ccckg_owner_generate_share should fail");
rv = ccckg_owner_generate_share(ctx_b, sizeof(commitment), commitment, sizeof(share), share);
is(rv, 0, "Generated share");
uint8_t sk_a[32], sk_b[32];
uint8_t opening[ccckg_sizeof_opening(cp, di)];
// Passing the wrong share size must fail.
rv = ccckg_contributor_finish(ctx_a, sizeof(share) + 1, share, sizeof(opening), opening, P_contrib, sizeof(sk_a), sk_a);
is(rv, CCERR_PARAMETER, "ccckg_contributor_finish should fail");
// Passing the wrong opening size must fail.
rv = ccckg_contributor_finish(ctx_a, sizeof(share), share, sizeof(opening) + 1, opening, P_contrib, sizeof(sk_a), sk_a);
is(rv, CCERR_PARAMETER, "ccckg_contributor_finish should fail");
// Passing a point on the wrong curve must fail.
rv = ccckg_contributor_finish(ctx_a, sizeof(share), share, sizeof(opening), opening, P_bogus, sizeof(sk_a), sk_a);
isnt(rv, CCERR_OK, "ccckg_contributor_finish should fail");
// Passing a share with the wrong format must fail.
share[0] = 0x02;
rv = ccckg_contributor_finish(ctx_a, sizeof(share), share, sizeof(opening), opening, P_contrib, sizeof(sk_a), sk_a);
isnt(rv, CCERR_OK, "ccckg_contributor_finish should fail");
share[0] = 0x04;
rv = ccckg_contributor_finish(ctx_a, sizeof(share), share, sizeof(opening), opening, P_contrib, sizeof(sk_a), sk_a);
is(rv, 0, "Opened commitment");
// Passing the wrong opening size must fail.
rv = ccckg_owner_finish(ctx_b, sizeof(opening) + 1, opening, P_owner, sizeof(sk_b), sk_b);
is(rv, CCERR_PARAMETER, "ccckg_owner_finish should fail");
// Passing a point on the wrong curve must fail.
rv = ccckg_owner_finish(ctx_b, sizeof(opening), opening, P_bogus_full, sizeof(sk_b), sk_b);
is(rv, CCERR_PARAMETER, "ccckg_owner_finish should fail");
rv = ccckg_owner_finish(ctx_b, sizeof(opening), opening, P_owner, sizeof(sk_b), sk_b);
is(rv, 0, "Owner finished");
ok_ccn_cmp(ccec_cp_n(cp), ccec_ctx_x(P_contrib), ccec_ctx_x(P_owner), "Ps don't match");
ok_memcmp_or_fail(sk_a, sk_b, sizeof(sk_a), "SKs don't match");
ccckg_ctx_clear(cp, di, ctx_a);
ccckg_ctx_clear(cp, di, ctx_b);
return 0;
}
static int test_bogus_commitment()
{
ccec_const_cp_t cp = ccec_cp_256();
struct ccrng_state *rng = global_test_rng;
const struct ccdigest_info *di = ccsha256_di();
ccec_full_ctx_decl_cp(cp, P_owner);
ccec_pub_ctx_decl_cp(cp, P_contrib);
ccec_ctx_init(cp, P_owner);
ccec_ctx_init(cp, P_contrib);
int rv;
ccckg_ctx_decl(cp, di, ctx_a);
ccckg_ctx_decl(cp, di, ctx_b);
ccckg_init(ctx_a, cp, di, rng);
ccckg_init(ctx_b, cp, di, rng);
uint8_t commitment[ccckg_sizeof_commitment(cp, di)];
rv = ccckg_contributor_commit(ctx_a, sizeof(commitment), commitment);
is(rv, 0, "Generated commitment");
// Corrupt the commitment.
commitment[0] ^= 0x01;
uint8_t share[ccckg_sizeof_share(cp, di)];
rv = ccckg_owner_generate_share(ctx_b, sizeof(commitment), commitment, sizeof(share), share);
is(rv, 0, "Generated share");
uint8_t sk_a[32];
uint8_t opening[ccckg_sizeof_opening(cp, di)];
rv = ccckg_contributor_finish(ctx_a, sizeof(share), share, sizeof(opening), opening, P_contrib, sizeof(sk_a), sk_a);
is(rv, 0, "Opened commitment");
uint8_t sk_b[32];
rv = ccckg_owner_finish(ctx_b, sizeof(opening), opening, P_owner, sizeof(sk_b), sk_b);
is(rv, CCERR_INTEGRITY, "Invalid commitment");
ccckg_ctx_clear(cp, di, ctx_a);
ccckg_ctx_clear(cp, di, ctx_b);
return 0;
}
static int test_bogus_scalar()
{
ccec_const_cp_t cp = ccec_cp_256();
struct ccrng_state *rng = global_test_rng;
const struct ccdigest_info *di = ccsha256_di();
ccec_full_ctx_decl_cp(cp, P_owner);
ccec_ctx_init(cp, P_owner);
int rv;
ccckg_ctx_decl(cp, di, ctx_b);
ccckg_init(ctx_b, cp, di, rng);
// Assemble commitment data with an invalid scalar.
uint8_t commitment_data[ccckg_sizeof_opening(cp, di)];
ccn_write_uint_padded(ccec_cp_n(cp), cczp_prime(ccec_cp_zq(cp)), ccec_cp_order_size(cp), commitment_data);
// Build the commitment.
uint8_t commitment[ccckg_sizeof_commitment(cp, di)];
ccdigest(di, sizeof(commitment_data), commitment_data, commitment);
uint8_t share[ccckg_sizeof_share(cp, di)];
rv = ccckg_owner_generate_share(ctx_b, sizeof(commitment), commitment, sizeof(share), share);
is(rv, 0, "Generated share");
uint8_t sk_b[32];
rv = ccckg_owner_finish(ctx_b, sizeof(commitment_data), commitment_data, P_owner, sizeof(sk_b), sk_b);
is(rv, CCERR_PARAMETER, "Invalid scalar");
ccckg_ctx_clear(cp, di, ctx_b);
return 0;
}
static int test_bogus_share()
{
ccec_const_cp_t cp = ccec_cp_256();
struct ccrng_state *rng = global_test_rng;
const struct ccdigest_info *di = ccsha256_di();
ccec_pub_ctx_decl_cp(cp, P_contrib);
ccec_ctx_init(cp, P_contrib);
int rv;
ccckg_ctx_decl(cp, di, ctx_a);
ccckg_ctx_decl(cp, di, ctx_b);
ccckg_init(ctx_a, cp, di, rng);
ccckg_init(ctx_b, cp, di, rng);
uint8_t commitment[ccckg_sizeof_commitment(cp, di)];
rv = ccckg_contributor_commit(ctx_a, sizeof(commitment), commitment);
is(rv, 0, "Generated commitment");
uint8_t share[ccckg_sizeof_share(cp, di)];
rv = ccckg_owner_generate_share(ctx_b, sizeof(commitment), commitment, sizeof(share), share);
is(rv, 0, "Generated share");
// Corrupt the share.
share[ccec_export_pub_size(P_contrib) - 1] ^= 0x55;
uint8_t sk_a[32];
uint8_t opening[ccckg_sizeof_opening(cp, di)];
rv = ccckg_contributor_finish(ctx_a, sizeof(share), share, sizeof(opening), opening, P_contrib, sizeof(sk_a), sk_a);
isnt(rv, 0, "Invalid share");
ccckg_ctx_clear(cp, di, ctx_a);
ccckg_ctx_clear(cp, di, ctx_b);
return 0;
}
static int test_bogus_share_infinity()
{
ccec_const_cp_t cp = ccec_cp_256();
struct ccrng_state *rng = global_test_rng;
const struct ccdigest_info *di = ccsha256_di();
ccec_pub_ctx_decl_cp(cp, P_contrib);
ccec_ctx_init(cp, P_contrib);
int rv;
ccckg_ctx_decl(cp, di, ctx_a);
ccckg_ctx_decl(cp, di, ctx_b);
ccckg_init(ctx_a, cp, di, rng);
ccckg_init(ctx_b, cp, di, rng);
uint8_t commitment[ccckg_sizeof_commitment(cp, di)];
rv = ccckg_contributor_commit(ctx_a, sizeof(commitment), commitment);
is(rv, 0, "Generated commitment");
uint8_t share[ccckg_sizeof_share(cp, di)];
rv = ccckg_owner_generate_share(ctx_b, sizeof(commitment), commitment, sizeof(share), share);
is(rv, 0, "Generated share");
// Turn the share into the point at infinity.
cc_clear(ccec_export_pub_size(P_contrib) - 1, share + 1);
uint8_t sk_a[32];
uint8_t opening[ccckg_sizeof_opening(cp, di)];
rv = ccckg_contributor_finish(ctx_a, sizeof(share), share, sizeof(opening), opening, P_contrib, sizeof(sk_a), sk_a);
isnt(rv, 0, "Invalid share");
ccckg_ctx_clear(cp, di, ctx_a);
ccckg_ctx_clear(cp, di, ctx_b);
return 0;
}
static int test_bogus_opening()
{
ccec_const_cp_t cp = ccec_cp_256();
struct ccrng_state *rng = global_test_rng;
const struct ccdigest_info *di = ccsha256_di();
ccec_full_ctx_decl_cp(cp, P_owner);
ccec_pub_ctx_decl_cp(cp, P_contrib);
ccec_ctx_init(cp, P_owner);
ccec_ctx_init(cp, P_contrib);
int rv;
ccckg_ctx_decl(cp, di, ctx_a);
ccckg_ctx_decl(cp, di, ctx_b);
ccckg_init(ctx_a, cp, di, rng);
ccckg_init(ctx_b, cp, di, rng);
uint8_t commitment[ccckg_sizeof_commitment(cp, di)];
rv = ccckg_contributor_commit(ctx_a, sizeof(commitment), commitment);
is(rv, 0, "Generated commitment");
uint8_t share[ccckg_sizeof_share(cp, di)];
rv = ccckg_owner_generate_share(ctx_b, sizeof(commitment), commitment, sizeof(share), share);
is(rv, 0, "Generated share");
uint8_t sk_a[32];
uint8_t opening[ccckg_sizeof_opening(cp, di)];
rv = ccckg_contributor_finish(ctx_a, sizeof(share), share, sizeof(opening), opening, P_contrib, sizeof(sk_a), sk_a);
is(rv, 0, "Opened commitment");
// Corrupt the opening.
opening[0] ^= 0x01;
uint8_t sk_b[32];
rv = ccckg_owner_finish(ctx_b, sizeof(opening), opening, P_owner, sizeof(sk_b), sk_b);
is(rv, CCERR_INTEGRITY, "Invalid commitment");
ccckg_ctx_clear(cp, di, ctx_a);
ccckg_ctx_clear(cp, di, ctx_b);
return 0;
}
static int test_state_machine()
{
ccec_const_cp_t cp = ccec_cp_256();
struct ccrng_state *rng = global_test_rng;
const struct ccdigest_info *di = ccsha256_di();
ccec_full_ctx_decl_cp(cp, P_owner);
ccec_pub_ctx_decl_cp(cp, P_contrib);
ccec_ctx_init(cp, P_owner);
ccec_ctx_init(cp, P_contrib);
int rv;
ccckg_ctx_decl(cp, di, ctx_a);
ccckg_ctx_decl(cp, di, ctx_b);
ccckg_init(ctx_a, cp, di, rng);
ccckg_init(ctx_b, cp, di, rng);
uint8_t commitment[ccckg_sizeof_commitment(cp, di)];
uint8_t share[ccckg_sizeof_share(cp, di)];
uint8_t opening[ccckg_sizeof_opening(cp, di)];
// A=STATE_INIT, B=STATE_INIT
uint8_t sk_a[32], sk_b[32];
rv = ccckg_contributor_finish(ctx_a, sizeof(share), share, sizeof(opening), opening, P_contrib, sizeof(sk_a), sk_a);
is(rv, CCERR_CALL_SEQUENCE, "Shouldn't be able to finish yet");
rv = ccckg_owner_finish(ctx_b, sizeof(opening), opening, P_owner, sizeof(sk_b), sk_b);
is(rv, CCERR_CALL_SEQUENCE, "Shouldn't be able to finish yet");
rv = ccckg_contributor_commit(ctx_a, sizeof(commitment), commitment);
is(rv, 0, "Generated commitment");
rv = ccckg_owner_generate_share(ctx_b, sizeof(commitment), commitment, sizeof(share), share);
is(rv, 0, "Generated share");
// A=STATE_COMMIT, B=STATE_SHARE
rv = ccckg_contributor_commit(ctx_a, sizeof(commitment), commitment);
is(rv, CCERR_CALL_SEQUENCE, "Shouldn't be able to commit twice");
rv = ccckg_owner_generate_share(ctx_b, sizeof(commitment), commitment, sizeof(share), share);
is(rv, CCERR_CALL_SEQUENCE, "Shouldn't be able to share twice");
rv = ccckg_contributor_finish(ctx_a, sizeof(share), share, sizeof(opening), opening, P_contrib, sizeof(sk_a), sk_a);
is(rv, 0, "Opened commitment");
rv = ccckg_owner_finish(ctx_b, sizeof(opening), opening, P_owner, sizeof(sk_b), sk_b);
is(rv, 0, "Owner finished");
// A=STATE_FINISH, B=STATE_FINISH
rv = ccckg_contributor_commit(ctx_a, sizeof(commitment), commitment);
is(rv, CCERR_CALL_SEQUENCE, "Shouldn't be able to commit twice");
rv = ccckg_owner_generate_share(ctx_b, sizeof(commitment), commitment, sizeof(share), share);
is(rv, CCERR_CALL_SEQUENCE, "Shouldn't be able to share twice");
rv = ccckg_contributor_finish(ctx_a, sizeof(share), share, sizeof(opening), opening, P_contrib, sizeof(sk_a), sk_a);
is(rv, CCERR_CALL_SEQUENCE, "Shouldn't be able to finish twice");
rv = ccckg_owner_finish(ctx_b, sizeof(opening), opening, P_owner, sizeof(sk_b), sk_b);
is(rv, CCERR_CALL_SEQUENCE, "Shouldn't be able to finish twice");
ok_ccn_cmp(ccec_cp_n(cp), ccec_ctx_x(P_contrib), ccec_ctx_x(P_owner), "Ps don't match");
ok_memcmp_or_fail(sk_a, sk_b, sizeof(sk_a), "SKs don't match");
ccckg_ctx_clear(cp, di, ctx_a);
ccckg_ctx_clear(cp, di, ctx_b);
return 0;
}
int ccckg_tests(TM_UNUSED int argc, TM_UNUSED char *const *argv)
{
ccec_const_cp_t curves[] = { ccec_cp_192(), ccec_cp_224(), ccec_cp_256(), ccec_cp_384(), ccec_cp_521() };
const struct ccdigest_info *hashes[] = { ccsha256_di(), ccsha384_di(), ccsha512_di() };
int num_tests = 0;
num_tests += 7; // full run tests
num_tests *= CC_ARRAY_LEN(curves) * CC_ARRAY_LEN(hashes);
num_tests += 5; // bogus commitment
num_tests += 3; // bogus scalar
num_tests += 8; // bogus shares
num_tests += 5; // bogus opening
num_tests += 15; // state machine
plan_tests(num_tests);
for (size_t i = 0; i < CC_ARRAY_LEN(curves); i++) {
ccec_const_cp_t cp = curves[i];
for (size_t j = 0; j < CC_ARRAY_LEN(hashes); j++) {
const struct ccdigest_info *di = hashes[j];
is(test_full_run(cp, di), 0, "Full run test");
}
}
is(test_bogus_inputs(), 0, "Bogus input test");
is(test_bogus_commitment(), 0, "Bogus commitment test");
is(test_bogus_scalar(), 0, "Bogus scalar test");
is(test_bogus_share(), 0, "Bogus share test");
is(test_bogus_share_infinity(), 0, "Bogus share test");
is(test_bogus_opening(), 0, "Bogus opening test");
is(test_state_machine(), 0, "State machine test");
return 0;
}