2022-11-18 08:56:18 +00:00
|
|
|
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) {
|
2022-11-18 12:21:38 +00:00
|
|
|
return false;
|
2022-11-18 08:56:18 +00:00
|
|
|
}
|
2022-11-18 12:21:38 +00:00
|
|
|
return true;
|
2022-11-18 08:56:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
|
|
|
sc25519_invert(recip, s)
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
2022-11-18 12:21:38 +00:00
|
|
|
t_.set(L.subarray(0, crypto_core_ed25519_SCALARBYTES), crypto_core_ed25519_SCALARBYTES)
|
2022-11-18 08:56:18 +00:00
|
|
|
s_.set(s.subarray(0, crypto_core_ed25519_SCALARBYTES))
|
|
|
|
|
2022-11-18 12:21:38 +00:00
|
|
|
sodium_sub(t_, s_, crypto_core_ed25519_NONREDUCEDSCALARBYTES)
|
2022-11-18 08:56:18 +00:00
|
|
|
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]++;
|
|
|
|
|
2022-11-18 12:21:38 +00:00
|
|
|
t_.set(L.subarray(0, crypto_core_ed25519_SCALARBYTES), crypto_core_ed25519_SCALARBYTES)
|
2022-11-18 08:56:18 +00:00
|
|
|
s_.set(s.subarray(0, crypto_core_ed25519_SCALARBYTES))
|
|
|
|
|
2022-11-18 12:21:38 +00:00
|
|
|
sodium_sub(t_, s_, crypto_core_ed25519_NONREDUCEDSCALARBYTES)
|
2022-11-18 08:56:18 +00:00
|
|
|
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
|
|
|
|
}
|