use super::arith::Field;
use super::gentable::HasGeneratorTable;
use super::point::{AffinePoint, Curve, Point};
use ic_core::{ensure, Result};
fn load_scalar<C: Curve>(bytes: &[u8]) -> Result<C::Scalar> {
ensure!(
bytes.len() == C::SCALAR_BYTES,
InvalidLength,
"ecdh private key"
);
let d = C::scalar_from_slice(bytes).ok_or(ic_core::err!(
InvalidParameter,
"ecdh private key is not less than n"
))?;
ensure!(
!bool::from(d.is_zero()),
InvalidParameter,
"ecdh private key must not be zero"
);
Ok(d)
}
pub fn public_key<C: HasGeneratorTable>(private_key: &[u8], out: &mut [u8]) -> Result<()> {
ensure!(
out.len() == 1 + 2 * C::FIELD_BYTES,
InvalidLength,
"ecdh public key buffer"
);
let d = load_scalar::<C>(private_key)?;
let q = Point::<C>::mul_generator(&d)
.to_affine()
.ok_or(ic_core::err!(Internal, "public key is the identity"))?;
ensure!(
q.write_uncompressed(out),
Internal,
"public key buffer length disagrees with the encoder"
);
Ok(())
}
pub fn public_key_compressed<C: HasGeneratorTable>(
private_key: &[u8],
out: &mut [u8],
) -> Result<()> {
ensure!(
out.len() == 1 + C::FIELD_BYTES,
InvalidLength,
"ecdh compressed key buffer"
);
let d = load_scalar::<C>(private_key)?;
let q = Point::<C>::mul_generator(&d)
.to_affine()
.ok_or(ic_core::err!(Internal, "public key is the identity"))?;
ensure!(
q.write_compressed(out),
Internal,
"compressed key buffer length disagrees with the encoder"
);
Ok(())
}
pub fn agree<C: Curve>(private_key: &[u8], peer_public_key: &[u8], out: &mut [u8]) -> Result<()> {
ensure!(
out.len() == C::FIELD_BYTES,
InvalidLength,
"ecdh shared secret buffer"
);
let d = load_scalar::<C>(private_key)?;
let q = AffinePoint::<C>::from_sec1(peer_public_key).ok_or(ic_core::err!(
InvalidParameter,
"ecdh peer public key is not a valid curve point"
))?;
let shared = Point::<C>::from_affine(&q).mul_scalar(&d);
let affine = shared.to_affine().ok_or(ic_core::err!(
InvalidParameter,
"ecdh key agreement produced the identity"
))?;
out.copy_from_slice(affine.x.to_bytes().as_ref());
Ok(())
}