use crate::bigint256::BigInt256;
use crate::serialization::sigma_byte_writer::SigmaByteWrite;
use crate::serialization::SigmaSerializeResult;
use crate::serialization::{
sigma_byte_reader::SigmaByteRead, SigmaParsingError, SigmaSerializable,
};
use elliptic_curve::group::ff::PrimeField;
use elliptic_curve::rand_core::RngCore;
use k256::Scalar;
use num_bigint::Sign;
use num_bigint::ToBigUint;
use num_bigint::{BigInt, BigUint};
use num_traits::ToPrimitive;
use sigma_ser::ScorexSerializable;
use std::convert::TryFrom;
pub fn random_scalar_in_group_range(rng: impl RngCore) -> Scalar {
Scalar::generate_vartime(rng)
}
pub fn scalar_to_bigint256(s: Scalar) -> Option<BigInt256> {
let bytes = s.to_bytes();
#[allow(clippy::unwrap_used)]
let bu: BigUint = bytes
.iter()
.enumerate()
.map(|(i, w)| w.to_biguint().unwrap() << ((31 - i) * 8))
.sum();
BigInt256::try_from(bu).ok()
}
fn biguint_to_bytes(x: &BigUint) -> [u8; 32] {
let mask = BigUint::from(u8::MAX);
let mut bytes = [0u8; 32];
#[allow(clippy::needless_range_loop)]
#[allow(clippy::unwrap_used)]
for i in 0..32 {
bytes[i] = ((x >> ((31 - i) * 8)) as BigUint & &mask).to_u8().unwrap();
}
bytes
}
pub fn bigint256_to_scalar(bi: BigInt256) -> Option<Scalar> {
if Sign::Minus == bi.sign() {
return None;
}
#[allow(clippy::unwrap_used)] let bu = bi.to_biguint().unwrap();
let bytes = biguint_to_bytes(&bu);
Scalar::from_repr(bytes.into()).into()
}
impl SigmaSerializable for ergo_chain_types::EcPoint {
fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult {
self.scorex_serialize(w)?;
Ok(())
}
fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError> {
let e = Self::scorex_parse(r)?;
Ok(e)
}
}
pub fn order() -> BigInt {
#[allow(clippy::unwrap_used)]
BigInt::parse_bytes(
b"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
16,
)
.unwrap()
}
#[allow(clippy::unwrap_used)]
#[cfg(test)]
#[allow(clippy::panic)]
mod tests {
use super::*;
use num_bigint::BigUint;
use num_bigint::ToBigUint;
use proptest::prelude::*;
fn bytes_to_biguint(bytes: &[u8; 32]) -> BigUint {
bytes
.iter()
.enumerate()
.map(|(i, w)| w.to_biguint().unwrap() << ((31 - i) * 8))
.sum()
}
fn scalar_to_biguint(scalar: &Scalar) -> Option<BigUint> {
Some(bytes_to_biguint(scalar.to_bytes().as_ref()))
}
fn biguint_to_scalar(x: &BigUint) -> Scalar {
debug_assert!(x < &modulus_as_biguint());
let bytes = biguint_to_bytes(x);
Scalar::from_repr(bytes.into()).unwrap()
}
fn modulus_as_biguint() -> BigUint {
scalar_to_biguint(&Scalar::ONE.negate()).unwrap() + 1.to_biguint().unwrap()
}
prop_compose! {
fn scalar()(bytes in any::<[u8; 32]>()) -> Scalar {
let mut res = bytes_to_biguint(&bytes);
let m = modulus_as_biguint();
if res >= m {
res -= m;
}
biguint_to_scalar(&res)
}
}
proptest! {
#[test]
fn scalar_biguint_roundtrip(scalar in scalar()) {
let bu = scalar_to_biguint(&scalar).unwrap();
let to_scalar = biguint_to_scalar(&bu);
prop_assert_eq!(scalar, to_scalar);
}
#[test]
fn scalar_bigint256_roundtrip(scalar in scalar()) {
let shifted_scalar = scalar >> 1;
let as_bigint256: BigInt256 = scalar_to_bigint256(shifted_scalar).unwrap();
let to_scalar = bigint256_to_scalar(as_bigint256).unwrap();
prop_assert_eq!(shifted_scalar, to_scalar);
}
}
}