From c42c442eab41e3e72ce78cd95162c7cf71f85970 Mon Sep 17 00:00:00 2001 From: Christophe Diederichs Date: Fri, 18 Nov 2022 08:56:18 +0000 Subject: [PATCH] add crypto_core methods --- crypto_core.js | 272 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 crypto_core.js diff --git a/crypto_core.js b/crypto_core.js new file mode 100644 index 0000000..db65b59 --- /dev/null +++ b/crypto_core.js @@ -0,0 +1,272 @@ +const b4a = require('b4a') +const assert = require('nanoassert') + +const { + ge25519_p3, + ge25519_p1p1, + ge25519_cached, + ge25519_frombytes, + ge25519_p3_tobytes, + ge25519_p1p1_to_p3, + ge25519_p3_to_cached, + ge25519_is_on_curve, + ge25519_is_canonical, + ge25519_is_on_main_subgroup, + ge25519_has_small_order, + ge25519_add_cached, + ge25519_sub_cached, + ge25519_from_uniform, + sc25519_reduce, + sc25519_mul, + sc25519_invert, + sc25519_is_canonical +} = require('./fe25519_25.js') + +const { randombytes_buf } = require('./randombytes') + +const { + sodium_add, + sodium_sub, + sodium_is_zero, + sodium_memzero +} = require('./utils') + +function crypto_core_ed25519_is_valid_point (p) { + const p_p3 = ge25519_p3() + + if (ge25519_is_canonical(p) == 0 || + ge25519_has_small_order(p) != 0 || + ge25519_frombytes(p_p3, p) != 0 || + ge25519_is_on_curve(p_p3) == 0 || + ge25519_is_on_main_subgroup(p_p3) == 0) { + return 0; + } + return 1; +} + +function crypto_core_ed25519_add (r, p, q) { + const p_p3 = ge25519_p3() + const q_p3 = ge25519_p3() + const r_p3 = ge25519_p3() + + const r_p1p1 = ge25519_p1p1() + const q_cached = ge25519_cached() + + if (ge25519_frombytes(p_p3, p) != 0 || ge25519_is_on_curve(p_p3) == 0 || + ge25519_frombytes(q_p3, q) != 0 || ge25519_is_on_curve(q_p3) == 0) { + throw new Error('Operands must be valid points.') + } + + ge25519_p3_to_cached(q_cached, q_p3) + ge25519_add_cached(r_p1p1, p_p3, q_cached) + ge25519_p1p1_to_p3(r_p3, r_p1p1) + ge25519_p3_tobytes(r, r_p3) +} + +function crypto_core_ed25519_sub (r, p, q) { + const p_p3 = ge25519_p3() + const q_p3 = ge25519_p3() + const r_p3 = ge25519_p3() + + const r_p1p1 = ge25519_p1p1() + const q_cached = ge25519_cached() + + if (ge25519_frombytes(p_p3, p) != 0 || ge25519_is_on_curve(p_p3) == 0 || + ge25519_frombytes(q_p3, q) != 0 || ge25519_is_on_curve(q_p3) == 0) { + throw new Error('Operands must be valid points.') + } + ge25519_p3_to_cached(q_cached, q_p3); + ge25519_sub_cached(r_p1p1, p_p3, q_cached); + ge25519_p1p1_to_p3(r_p3, r_p1p1); + ge25519_p3_tobytes(r, r_p3); +} + +function crypto_core_ed25519_from_uniform (p, r) { + ge25519_from_uniform(p, r) +} + +// const HASH_GE_L = 48 + +// function _string_to_points (px, n, ctx, msg, msg_len, hash_alg) { +// const h = b4a.alloc(crypto_core_ed25519_HASHBYTES) +// const h_be = b4a.alloc(2 * HASH_GE_L) + +// let i +// let j + +// if (n > 2) { +// // abort(); /* LCOV_EXCL_LINE */ +// throw new Error('abort') +// } +// if (core_h2c_string_to_hash(h_be, n * HASH_GE_L, ctx, msg, msg_len, +// hash_alg) != 0) { +// return -1; +// } +// COMPILER_ASSERT(sizeof h >= HASH_GE_L); +// for (i = 0U; i < n; i++) { +// for (j = 0U; j < HASH_GE_L; j++) { +// h[j] = h_be[i * HASH_GE_L + HASH_GE_L - 1U - j]; +// } +// memset(&h[j], 0, (sizeof h) - j); +// ge25519_from_hash(&px[i * crypto_core_ed25519_BYTES], h); +// } +// return 0; +// } + +// int +// crypto_core_ed25519_from_string(unsigned char p[crypto_core_ed25519_BYTES], +// const char *ctx, msg, +// size_t msg_len, int hash_alg) +// { +// return _string_to_points(p, 1, ctx, msg, msg_len, hash_alg); +// } + +// int +// crypto_core_ed25519_from_string_ro(unsigned char p[crypto_core_ed25519_BYTES], +// const char *ctx, msg, +// size_t msg_len, int hash_alg) +// { +// unsigned char px[2 * crypto_core_ed25519_BYTES]; + +// if (_string_to_points(px, 2, ctx, msg, msg_len, hash_alg) != 0) { +// return -1; +// } +// return crypto_core_ed25519_add(p, &px[0], &px[crypto_core_ed25519_BYTES]); +// } + + +function crypto_core_ed25519_random (p) { + const h = b4a.alloc(crypto_core_ed25519_UNIFORMBYTES) + + randombytes_buf(h) + crypto_core_ed25519_from_uniform(p, h) +} + +function crypto_core_ed25519_scalar_random (r) { + do { + randombytes_buf(r, crypto_core_ed25519_SCALARBYTES) + r[crypto_core_ed25519_SCALARBYTES - 1] &= 0x1f + } while (sc25519_is_canonical(r) == 0 || + sodium_is_zero(r, crypto_core_ed25519_SCALARBYTES)); +} + +function crypto_core_ed25519_scalar_invert (recip, s) { + console.log(s) + sc25519_invert(recip, s) + console.log(recip) + + if (sodium_is_zero(s, crypto_core_ed25519_SCALARBYTES)) { + throw new Error('Zero point') + } +} + +/* 2^252+27742317777372353535851937790883648493 */ +const L = b4a.from([ + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, + 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 +]) + +function crypto_core_ed25519_scalar_negate (neg, s) { + const t_ = b4a.alloc(crypto_core_ed25519_NONREDUCEDSCALARBYTES) + const s_ = b4a.alloc(crypto_core_ed25519_NONREDUCEDSCALARBYTES) + + assert(crypto_core_ed25519_NONREDUCEDSCALARBYTES >= + 2 * crypto_core_ed25519_SCALARBYTES); + + t_.fill(0) + s_.fill(0) + + t_.set(L.subarray(crypto_core_ed25519_SCALARBYTES, crypto_core_ed25519_SCALARBYTES)) + s_.set(s.subarray(0, crypto_core_ed25519_SCALARBYTES)) + + sodium_sub(t_, s_, crypto_core_ed25519_SCALARBYTES) + sc25519_reduce(t_) + + neg.set(t_.subarray(0 , crypto_core_ed25519_SCALARBYTES)) +} + +function crypto_core_ed25519_scalar_complement (comp, s) { + const t_ = b4a.alloc(crypto_core_ed25519_NONREDUCEDSCALARBYTES) + const s_ = b4a.alloc(crypto_core_ed25519_NONREDUCEDSCALARBYTES) + + assert(crypto_core_ed25519_NONREDUCEDSCALARBYTES >= + 2 * crypto_core_ed25519_SCALARBYTES); + + t_.fill(0) + s_.fill(0) + t_[0]++; + + t_.set(L.subarray(crypto_core_ed25519_SCALARBYTES, crypto_core_ed25519_SCALARBYTES)) + s_.set(s.subarray(0, crypto_core_ed25519_SCALARBYTES)) + + sodium_sub(t_, s_, crypto_core_ed25519_SCALARBYTES) + sc25519_reduce(t_) + + comp.set(t_.subarray(0, crypto_core_ed25519_SCALARBYTES)) +} + +function crypto_core_ed25519_scalar_add (z, x, y) { + const x_ = b4a.alloc(crypto_core_ed25519_NONREDUCEDSCALARBYTES) + const y_ = b4a.alloc(crypto_core_ed25519_NONREDUCEDSCALARBYTES) + + x_.fill(0) + y_.fill(0) + + x_.set(x.subarray(0, crypto_core_ed25519_SCALARBYTES)) + y_.set(y.subarray(0, crypto_core_ed25519_SCALARBYTES)) + + sodium_add(x_, y_, crypto_core_ed25519_SCALARBYTES) + crypto_core_ed25519_scalar_reduce(z, x_) +} + +function crypto_core_ed25519_scalar_sub(z, x, y) { + const yn = b4a.alloc(crypto_core_ed25519_SCALARBYTES) + + crypto_core_ed25519_scalar_negate(yn, y) + crypto_core_ed25519_scalar_add(z, x, yn) +} + +function crypto_core_ed25519_scalar_mul(z, x, y) { + sc25519_mul(z, x, y) +} + +function crypto_core_ed25519_scalar_reduce(r, s) { + const t = b4a.alloc(crypto_core_ed25519_NONREDUCEDSCALARBYTES) + + t.set(s) + + sc25519_reduce(t) + r.set(t.subarray(0, crypto_core_ed25519_SCALARBYTES)) + sodium_memzero(t) +} + +function crypto_core_ed25519_scalar_is_canonical(s) { + return sc25519_is_canonical(s) +} + +const crypto_core_ed25519_BYTES = 32 +const crypto_core_ed25519_UNIFORMBYTES = 32 +const crypto_core_ed25519_SCALARBYTES = 32 +const crypto_core_ed25519_NONREDUCEDSCALARBYTES = 64 + +module.exports = { + crypto_core_ed25519_is_valid_point, + crypto_core_ed25519_add, + crypto_core_ed25519_sub, + crypto_core_ed25519_from_uniform, + crypto_core_ed25519_random, + crypto_core_ed25519_scalar_random, + crypto_core_ed25519_scalar_invert, + crypto_core_ed25519_scalar_negate, + crypto_core_ed25519_scalar_complement, + crypto_core_ed25519_scalar_add, + crypto_core_ed25519_scalar_sub, + crypto_core_ed25519_scalar_mul, + crypto_core_ed25519_scalar_reduce, + crypto_core_ed25519_scalar_is_canonical, + crypto_core_ed25519_BYTES, + crypto_core_ed25519_UNIFORMBYTES, + crypto_core_ed25519_SCALARBYTES, + crypto_core_ed25519_NONREDUCEDSCALARBYTES +}