#![allow(unsafe_code)]
use core::arch::global_asm;
use super::constants::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH};
use crate::platform::{self, caps::x86};
const AFFINE_POINT_LIMBS: usize = 8;
const FIELD_LIMBS: usize = 4;
global_asm!(
include_str!("asm/rscrypto_ed25519_scalarmulbase_x86_64_unknown_linux.s"),
options(att_syntax)
);
global_asm!(
include_str!("asm/rscrypto_ed25519_scalarmulbase_alt_x86_64_unknown_linux.s"),
options(att_syntax)
);
unsafe extern "C" {
fn rscrypto_edwards25519_scalarmulbase(out: *mut u64, scalar: *const u64);
fn rscrypto_edwards25519_scalarmulbase_alt(out: *mut u64, scalar: *const u64);
}
#[inline]
fn has_bmi2_adx() -> bool {
platform::caps().has(x86::BMI2.union(x86::ADX))
}
#[inline]
pub(super) fn basepoint_mul_encoded(s: &[u8; SECRET_KEY_LENGTH]) -> [u8; PUBLIC_KEY_LENGTH] {
let s_words = words_from_le_bytes(s);
let mut out = [0u64; AFFINE_POINT_LIMBS];
if has_bmi2_adx() {
unsafe { rscrypto_edwards25519_scalarmulbase(out.as_mut_ptr(), s_words.as_ptr()) };
} else {
unsafe { rscrypto_edwards25519_scalarmulbase_alt(out.as_mut_ptr(), s_words.as_ptr()) };
}
encode_affine_point(&out)
}
#[inline]
fn words_from_le_bytes(bytes: &[u8; SECRET_KEY_LENGTH]) -> [u64; FIELD_LIMBS] {
let mut words = [0u64; FIELD_LIMBS];
for (word, chunk) in words.iter_mut().zip(bytes.chunks_exact(8)) {
let mut limb = [0u8; 8];
limb.copy_from_slice(chunk);
*word = u64::from_le_bytes(limb);
}
words
}
#[inline]
fn encode_affine_point(point: &[u64; AFFINE_POINT_LIMBS]) -> [u8; PUBLIC_KEY_LENGTH] {
let mut encoded = [0u8; PUBLIC_KEY_LENGTH];
for (dst, word) in encoded
.chunks_exact_mut(8)
.zip(point[FIELD_LIMBS..AFFINE_POINT_LIMBS].iter().copied())
{
dst.copy_from_slice(&word.to_le_bytes());
}
encoded[PUBLIC_KEY_LENGTH - 1] &= 0x7f;
encoded[PUBLIC_KEY_LENGTH - 1] |= ((point[0] & 1) as u8) << 7;
encoded
}