use ark_ec::AffineRepr;
use ark_ff::{Field, PrimeField as ArkworksPrimeField, Zero};
use ark_serialize::{CanonicalSerialize, CanonicalSerializeWithFlags, EmptyFlags};
use elliptic_curve::bigint::ArrayEncoding;
use elliptic_curve::scalar::FromUintUnchecked;
use elliptic_curve::sec1::FromEncodedPoint;
use elliptic_curve::sec1::ToEncodedPoint;
use p256::{FieldBytes, U256};
pub(crate) fn fr_p256_to_arkworks(scalar: &p256::Scalar) -> ark_secp256r1::Fr {
ark_secp256r1::Fr::from_be_bytes_mod_order(&scalar.to_bytes())
}
pub(crate) fn fr_arkworks_to_p256(scalar: &ark_secp256r1::Fr) -> p256::Scalar {
let mut bytes = [0u8; 32];
scalar
.serialize_with_flags(&mut bytes[..], EmptyFlags)
.unwrap();
p256::Scalar::from_uint_unchecked(U256::from_le_byte_array(FieldBytes::from(bytes)))
}
pub(crate) fn fq_arkworks_to_p256(scalar: &ark_secp256r1::Fq) -> FieldBytes {
let mut bytes = [0u8; 32];
scalar.serialize_uncompressed(&mut bytes[..]).unwrap();
bytes.reverse();
p256::FieldBytes::from(bytes)
}
pub(crate) fn affine_pt_p256_to_projective_arkworks(
point: &p256::AffinePoint,
) -> ark_secp256r1::Projective {
if point.is_identity().into() {
return ark_secp256r1::Projective::zero();
}
let encoded_point = point.to_encoded_point(false);
ark_secp256r1::Projective::from(ark_secp256r1::Affine::new_unchecked(
ark_secp256r1::Fq::from_be_bytes_mod_order(encoded_point.x().unwrap()),
ark_secp256r1::Fq::from_be_bytes_mod_order(encoded_point.y().unwrap()),
))
}
pub(crate) fn reduce_bytes(bytes: &[u8; 32]) -> ark_secp256r1::Fr {
ark_secp256r1::Fr::from_be_bytes_mod_order(bytes)
}
pub(crate) fn arkworks_fq_to_fr(scalar: &ark_secp256r1::Fq) -> (ark_secp256r1::Fr, bool) {
let mut bytes = [0u8; 32];
scalar.serialize_uncompressed(&mut bytes[..]).unwrap();
let output = ark_secp256r1::Fr::from_le_bytes_mod_order(&bytes);
(output, output.into_bigint() != scalar.into_bigint())
}
pub(crate) fn affine_pt_arkworks_to_p256(point: &ark_secp256r1::Affine) -> p256::AffinePoint {
if point.is_zero() {
return p256::AffinePoint::IDENTITY;
}
let encoded_point = p256::EncodedPoint::from_affine_coordinates(
&fq_arkworks_to_p256(point.x().expect("The point should not be zero")),
&fq_arkworks_to_p256(point.y().expect("The point should not be zero")),
false,
);
p256::AffinePoint::from_encoded_point(&encoded_point).unwrap()
}
pub(crate) fn get_affine_x_coordinate(
point: &ark_secp256r1::Projective,
) -> Option<ark_secp256r1::Fq> {
if point.is_zero() {
return None;
}
let mut z_inv = point
.z
.inverse()
.expect("z is zero. This should never happen.");
z_inv.square_in_place();
Some(point.x * z_inv)
}
#[cfg(test)]
mod tests {
use super::*;
use ark_ec::{CurveGroup, Group};
use ark_ff::UniformRand;
use elliptic_curve::group::prime::PrimeCurveAffine;
use elliptic_curve::ops::Reduce;
use elliptic_curve::Field;
#[test]
fn test_fr_p256_to_arkworks() {
let arkworks_seven = ark_secp256r1::Fr::from(7u32);
let p256_seven = p256::Scalar::from(7u32);
let actual_arkworks_seven = fr_p256_to_arkworks(&p256_seven);
assert_eq!(actual_arkworks_seven, arkworks_seven);
let actual_p256_seven = fr_arkworks_to_p256(&arkworks_seven);
assert_eq!(actual_p256_seven, p256_seven);
}
#[test]
fn test_pt_arkworks_to_p256() {
assert_eq!(
p256::AffinePoint::IDENTITY,
affine_pt_arkworks_to_p256(&ark_secp256r1::Affine::zero())
);
assert_eq!(
p256::AffinePoint::generator(),
affine_pt_arkworks_to_p256(&ark_secp256r1::Affine::generator())
);
assert_eq!(
(p256::AffinePoint::generator() * p256::Scalar::from(7u32)).to_affine(),
affine_pt_arkworks_to_p256(
&(ark_secp256r1::Projective::generator() * ark_secp256r1::Fr::from(7u32))
.into_affine()
)
);
let random_s = p256::Scalar::random(&mut rand::thread_rng());
assert_eq!(
(p256::AffinePoint::generator() * random_s).to_affine(),
affine_pt_arkworks_to_p256(
&(ark_secp256r1::Projective::generator() * fr_p256_to_arkworks(&random_s))
.into_affine()
)
);
}
#[test]
fn test_pt_p256_to_arkworks() {
assert_eq!(
ark_secp256r1::Projective::zero(),
affine_pt_p256_to_projective_arkworks(&p256::AffinePoint::IDENTITY)
);
assert_eq!(
ark_secp256r1::Projective::generator() * ark_secp256r1::Fr::from(7u32),
affine_pt_p256_to_projective_arkworks(
&(p256::AffinePoint::generator() * p256::Scalar::from(7u32)).to_affine()
)
);
assert_eq!(
ark_secp256r1::Projective::generator(),
affine_pt_p256_to_projective_arkworks(&p256::AffinePoint::generator())
);
let random_s = p256::Scalar::random(&mut rand::thread_rng());
assert_eq!(
(ark_secp256r1::Projective::generator() * fr_p256_to_arkworks(&random_s)).into_affine(),
affine_pt_p256_to_projective_arkworks(
&(p256::AffinePoint::generator() * random_s).to_affine()
)
);
}
#[test]
fn test_arkworks_fq_to_fr() {
let s = ark_secp256r1::Fq::rand(&mut rand::thread_rng());
let s_fr = arkworks_fq_to_fr(&s).0;
let p256_s = fq_arkworks_to_p256(&s);
let reduced_s = p256::Scalar::reduce_bytes(&p256_s);
assert_eq!(fr_arkworks_to_p256(&s_fr), reduced_s);
assert_eq!(reduce_bytes(&p256_s.into()), s_fr);
}
#[test]
fn test_fq_arkworks_to_p256() {
let arkworks_seven = ark_secp256r1::Fq::from(7u32);
let p256_seven = p256::FieldBytes::from(p256::Scalar::from(7u32));
let actual_p256_seven = fq_arkworks_to_p256(&arkworks_seven);
assert_eq!(actual_p256_seven, p256_seven);
}
}