use nettle_sys::{
__gmpz_clear, __gmpz_init, ecc_point, ecc_scalar, nettle_ecc_point_clear,
nettle_ecc_point_get, nettle_ecc_point_init, nettle_ecc_point_set,
nettle_ecc_scalar_clear, nettle_ecc_scalar_get, nettle_ecc_scalar_init,
nettle_ecc_scalar_set,
};
use std::mem::zeroed;
use crate::errors::Error;
use crate::{helper, Curve, Random, Result};
pub struct Scalar {
pub(crate) scalar: ecc_scalar,
}
impl Scalar {
pub fn new<C: Curve>(num: &[u8]) -> Result<Scalar> {
unsafe {
let mut scalar: ecc_scalar = zeroed();
nettle_ecc_scalar_init(&mut scalar as *mut _, C::get_curve());
let mut mpz = helper::convert_buffer_to_gmpz(num);
if nettle_ecc_scalar_set(&mut scalar as *mut _, &mut mpz) == 1 {
__gmpz_clear(&mut mpz as *mut _);
Ok(Scalar { scalar: scalar })
} else {
__gmpz_clear(&mut mpz as *mut _);
Err(Error::InvalidArgument { argument_name: "num" }.into())
}
}
}
pub fn new_random<C, R>(rng: &mut R) -> Self
where
C: Curve,
R: Random,
{
let bits = unsafe { C::bit_size() };
let bytes = if bits % 8 > 0 { 1 } else { 0 } + bits / 8;
let mut buf = vec![0u8; bytes as usize];
loop {
rng.random(&mut buf);
match Scalar::new::<C>(&buf) {
Ok(sc) => return sc,
Err(_) => {}
}
}
}
pub fn as_bytes(&self) -> Box<[u8]> {
unsafe {
let mut mpz = zeroed();
__gmpz_init(&mut mpz as *mut _);
nettle_ecc_scalar_get(&self.scalar as *const _, &mut mpz);
let ret = helper::convert_gmpz_to_buffer(mpz);
__gmpz_clear(&mut mpz);
ret
}
}
}
impl Clone for Scalar {
fn clone(&self) -> Self {
unsafe {
let buf = self.as_bytes();
let mut mpz = helper::convert_buffer_to_gmpz(&*buf);
let mut ret: ecc_scalar = zeroed();
nettle_ecc_scalar_init(&mut ret, self.scalar.ecc);
assert_eq!(nettle_ecc_scalar_set(&mut ret, &mut mpz), 1);
__gmpz_clear(&mut mpz);
Scalar { scalar: ret }
}
}
}
impl Drop for Scalar {
fn drop(&mut self) {
unsafe {
nettle_ecc_scalar_clear(&mut self.scalar as *mut _);
}
}
}
pub struct Point {
pub(crate) point: ecc_point,
}
impl Point {
pub fn new<C: Curve>(x: &[u8], y: &[u8]) -> Result<Point> {
unsafe {
let mut point: ecc_point = zeroed();
nettle_ecc_point_init(&mut point as *mut _, C::get_curve());
let mut x_mpz = helper::convert_buffer_to_gmpz(x);
let mut y_mpz = helper::convert_buffer_to_gmpz(y);
if nettle_ecc_point_set(
&mut point as *mut _,
&mut x_mpz,
&mut y_mpz,
) == 1
{
__gmpz_clear(&mut x_mpz as *mut _);
__gmpz_clear(&mut y_mpz as *mut _);
Ok(Point { point: point })
} else {
__gmpz_clear(&mut x_mpz as *mut _);
__gmpz_clear(&mut y_mpz as *mut _);
Err(Error::InvalidArgument { argument_name: "x or y" }.into())
}
}
}
pub fn as_bytes(&self) -> (Box<[u8]>, Box<[u8]>) {
unsafe {
let mut x_mpz = zeroed();
let mut y_mpz = zeroed();
__gmpz_init(&mut x_mpz as *mut _);
__gmpz_init(&mut y_mpz as *mut _);
nettle_ecc_point_get(
&self.point as *const _,
&mut x_mpz,
&mut y_mpz,
);
let x_ret = helper::convert_gmpz_to_buffer(x_mpz);
let y_ret = helper::convert_gmpz_to_buffer(y_mpz);
__gmpz_clear(&mut x_mpz as *mut _);
__gmpz_clear(&mut y_mpz as *mut _);
(x_ret, y_ret)
}
}
}
impl Clone for Point {
fn clone(&self) -> Self {
unsafe {
let (buf_x, buf_y) = self.as_bytes();
let mut mpz_x = helper::convert_buffer_to_gmpz(&*buf_x);
let mut mpz_y = helper::convert_buffer_to_gmpz(&*buf_y);
let mut ret: ecc_point = zeroed();
nettle_ecc_point_init(&mut ret, self.point.ecc);
assert_eq!(
nettle_ecc_point_set(&mut ret, &mut mpz_x, &mut mpz_y),
1
);
__gmpz_clear(&mut mpz_x);
__gmpz_clear(&mut mpz_y);
Point { point: ret }
}
}
}
impl Drop for Point {
fn drop(&mut self) {
unsafe {
nettle_ecc_point_clear(&mut self.point as *mut _);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Yarrow;
use crate::{Secp192r1, Secp224r1, Secp256r1, Secp384r1, Secp521r1};
#[test]
fn random_scalar() {
let mut rng = Yarrow::default();
let sc1 = Scalar::new_random::<Secp192r1, _>(&mut rng).as_bytes();
let sc2 = Scalar::new_random::<Secp192r1, _>(&mut rng).as_bytes();
assert!(sc1 != sc2);
let sc1 = Scalar::new_random::<Secp224r1, _>(&mut rng).as_bytes();
let sc2 = Scalar::new_random::<Secp224r1, _>(&mut rng).as_bytes();
assert!(sc1 != sc2);
let sc1 = Scalar::new_random::<Secp256r1, _>(&mut rng).as_bytes();
let sc2 = Scalar::new_random::<Secp256r1, _>(&mut rng).as_bytes();
assert!(sc1 != sc2);
let sc1 = Scalar::new_random::<Secp384r1, _>(&mut rng).as_bytes();
let sc2 = Scalar::new_random::<Secp384r1, _>(&mut rng).as_bytes();
assert!(sc1 != sc2);
let sc1 = Scalar::new_random::<Secp521r1, _>(&mut rng).as_bytes();
let sc2 = Scalar::new_random::<Secp521r1, _>(&mut rng).as_bytes();
assert!(sc1 != sc2);
}
}