Newtype the Field so we can add serializers

This commit is contained in:
Remco Bloemen 2022-03-17 14:58:14 -07:00
parent 8ff42be353
commit 0a17226a4c
11 changed files with 332 additions and 239 deletions

View File

@ -16,7 +16,7 @@ license-file = "mit-license.md"
[features]
default = []
bench = [ "criterion", "proptest" ]
mimc = [ "tiny-keccak", "zkp-u256" ]
mimc = [ "zkp-u256" ]
[[bench]]
name = "criterion"
@ -46,10 +46,11 @@ serde = "1.0"
sha2 = "0.10.1"
tempfile = "3.3.0"
thiserror = "1.0.0"
tiny-keccak = { version = "2.0.2", optional = true }
zkp-u256 = { version = "0.2", optional = true }
tiny-keccak = { version = "2.0.2" }
zkp-u256 = { version = "0.2", optional = true } # TODO: Remove
# Use the same `ethers-core` version as ark-circom
# TODO: Remove
ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = false }
[dev-dependencies]

View File

@ -22,18 +22,17 @@ semaphore = { git = "https://github.com/worldcoin/semaphore-rs" }
Example as in `src/lib.rs`, run with `cargo test`.
```rust
use semaphore::{identity::Identity, hash::Hash, poseidon_tree::PoseidonTree,
use semaphore::{hash_to_field, Field, identity::Identity, poseidon_tree::PoseidonTree,
protocol::* };
use num_bigint::BigInt;
// generate identity
let id = Identity::new(b"secret");
let id = Identity::from_seed(b"secret");
// generate merkle tree
const LEAF: Hash = Hash::from_bytes_be([0u8; 32]);
let mut tree = PoseidonTree::new(21, LEAF);
tree.set(0, id.commitment().into());
let leaf = Field::from(0);
let mut tree = PoseidonTree::new(21, leaf);
tree.set(0, id.commitment());
let merkle_proof = tree.proof(0).expect("proof should exist");
let root = tree.root();
@ -45,7 +44,7 @@ let external_nullifier_hash = hash_to_field(b"appId");
let nullifier_hash = generate_nullifier_hash(&id, external_nullifier_hash);
let proof = generate_proof(&id, &merkle_proof, external_nullifier_hash, signal_hash).unwrap();
let success = verify_proof(root.into(), nullifier_hash, signal_hash, external_nullifier_hash, &proof).unwrap();
let success = verify_proof(root, nullifier_hash, signal_hash, external_nullifier_hash, &proof).unwrap();
assert!(success);
```

View File

@ -12,8 +12,11 @@
"keccak",
"merkle",
"mimc",
"mimcsponge",
"mmaped",
"modpow",
"mulmod",
"proptest",
"Repr",
"Seedable",
"snarkfiles",

201
src/field.rs Normal file
View File

@ -0,0 +1,201 @@
use crate::util::{keccak256, trim_hex_prefix};
use ark_bn254::Fr as ArkField;
use ark_ff::{BigInteger as _, PrimeField as _};
use core::{
fmt::{Formatter, Result as FmtResult},
str,
str::FromStr,
};
use ff::{PrimeField as _, PrimeFieldRepr as _};
use hex::encode_to_slice;
use num_bigint::{BigInt, Sign};
use poseidon_rs::Fr as PosField;
use serde::{
de::{Error as DeError, Visitor},
Deserialize, Serialize, Serializer,
};
/// An element of the BN254 scalar field Fr.
///
/// Represented as a big-endian byte vector without Montgomery reduction.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
// TODO: Make sure value is always reduced.
pub struct Field([u8; 32]);
impl Field {
/// Construct a field element from a big-endian byte vector.
#[must_use]
pub fn from_be_bytes_mod_order(bytes: &[u8]) -> Self {
ArkField::from_be_bytes_mod_order(bytes).into()
}
}
impl From<u64> for Field {
fn from(value: u64) -> Self {
ArkField::from(value).into()
}
}
impl From<ArkField> for Field {
fn from(value: ArkField) -> Self {
let mut bytes = [0_u8; 32];
let byte_vec = value.into_repr().to_bytes_be();
bytes.copy_from_slice(&byte_vec[..]);
Self(bytes)
}
}
impl From<Field> for ArkField {
fn from(value: Field) -> Self {
Self::from_be_bytes_mod_order(&value.0[..])
}
}
impl From<PosField> for Field {
fn from(value: PosField) -> Self {
let mut bytes = [0u8; 32];
value
.into_repr()
.write_be(&mut bytes[..])
.expect("write to correctly sized slice always succeeds");
Self(bytes)
}
}
impl From<Field> for PosField {
fn from(value: Field) -> Self {
let mut repr = <Self as ff::PrimeField>::Repr::default();
repr.read_be(&value.0[..])
.expect("read from correctly sized slice always succeeds");
Self::from_repr(repr).expect("value is always in range")
}
}
impl From<Field> for BigInt {
fn from(value: Field) -> Self {
Self::from_bytes_be(Sign::Plus, &value.0[..])
}
}
impl Serialize for Field {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
// Write as a 0x prefixed lower-case hex string
let mut buffer = [0u8; 66];
buffer[0] = b'0';
buffer[1] = b'x';
encode_to_slice(&self.0, &mut buffer[2..]).expect("the buffer is correctly sized");
let string = str::from_utf8(&buffer).expect("the buffer is valid UTF-8");
serializer.serialize_str(string)
} else {
// Write as bytes directly
serializer.serialize_bytes(&self.0)
}
}
}
/// Parse Hash from hex string.
/// Hex strings can be upper/lower/mixed case and have an optional `0x` prefix
/// but they must always be exactly 32 bytes.
impl FromStr for Field {
type Err = hex::FromHexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let str = trim_hex_prefix(s);
let mut out = [0_u8; 32];
hex::decode_to_slice(str, &mut out)?;
// TODO: Reduce
Ok(Self(out))
}
}
/// Deserialize human readable hex strings or byte arrays into hashes.
/// Hex strings can be upper/lower/mixed case and have an optional `0x` prefix
/// but they must always be exactly 32 bytes.
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
if deserializer.is_human_readable() {
deserializer.deserialize_str(StrVisitor)
} else {
// TODO: Reduce
<[u8; 32]>::deserialize(deserializer).map(Field)
}
}
}
struct StrVisitor;
impl<'de> Visitor<'de> for StrVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
formatter.write_str("a 32 byte hex string")
}
fn visit_borrowed_str<E>(self, value: &'de str) -> Result<Self::Value, E>
where
E: DeError,
{
Field::from_str(value).map_err(|e| E::custom(format!("Error in hex: {}", e)))
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: DeError,
{
Field::from_str(value).map_err(|e| E::custom(format!("Error in hex: {}", e)))
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
where
E: DeError,
{
Field::from_str(&value).map_err(|e| E::custom(format!("Error in hex: {}", e)))
}
}
/// Hash arbitrary data to a field element.
///
/// This is used to create `signal_hash` and `external_nullifier_hash`.
#[must_use]
#[allow(clippy::module_name_repetitions)]
pub fn hash_to_field(data: &[u8]) -> Field {
let hash = keccak256(data);
// Shift right one byte to make it fit in the field
let mut bytes = [0_u8; 32];
bytes[1..].copy_from_slice(&hash[..31]);
Field(bytes)
}
#[cfg(test)]
mod test {
use super::*;
use ark_ff::Field as _;
#[test]
fn test_modulus_identical() {
assert_eq!(PosField::char().0, ArkField::characteristic());
}
#[test]
fn test_field_serde() {
let value = Field::from(0x1234_5678);
let serialized = serde_json::to_value(value).unwrap();
let deserialized = serde_json::from_value(serialized).unwrap();
assert_eq!(value, deserialized);
}
// #[test]
// fn test_ark_pos_ark_roundtrip() {
// let mut rng = ChaChaRng::seed_from_u64(123);
// for _ in 0..1000 {
// let n = Field::rand(&mut rng);
// let m = poseidon_to_ark(ark_to_poseidon(n));
// assert_eq!(n, m);
// }
// }
}

View File

@ -1,5 +1,4 @@
use crate::{poseidon_hash, Field};
use ark_ff::PrimeField;
use sha2::{Digest, Sha256};
#[derive(Clone, PartialEq, Eq, Debug)]
@ -8,35 +7,32 @@ pub struct Identity {
pub nullifier: Field,
}
// todo: improve
fn sha(msg: &[u8]) -> [u8; 32] {
/// Implements the private key derivation function from zk-kit.
///
/// See <https://github.com/appliedzkp/zk-kit/blob/1ea410456fc2b95877efa7c671bc390ffbfb5d36/packages/identity/src/identity.ts#L58>
fn derive_field(seed_hex: &[u8; 64], suffix: &[u8]) -> Field {
let mut hasher = Sha256::new();
hasher.update(msg);
let result = hasher.finalize();
let res: [u8; 32] = result.into();
res
hasher.update(seed_hex);
hasher.update(suffix);
Field::from_be_bytes_mod_order(hasher.finalize().as_ref())
}
fn seed_hex(seed: &[u8]) -> [u8; 64] {
let mut hasher = Sha256::new();
hasher.update(seed);
let bytes: [u8; 32] = hasher.finalize().into();
let mut result = [0_u8; 64];
hex::encode_to_slice(&bytes, &mut result[..]).expect("output buffer is correctly sized");
result
}
impl Identity {
#[must_use]
pub fn new(seed: &[u8]) -> Self {
let seed_hash = &sha(seed);
// https://github.com/appliedzkp/zk-kit/blob/1ea410456fc2b95877efa7c671bc390ffbfb5d36/packages/identity/src/identity.ts#L58
let trapdoor = Field::from_be_bytes_mod_order(&sha(format!(
"{}identity_trapdoor",
hex::encode(seed_hash)
)
.as_bytes()));
let nullifier = Field::from_be_bytes_mod_order(&sha(format!(
"{}identity_nullifier",
hex::encode(seed_hash)
)
.as_bytes()));
pub fn from_seed(seed: &[u8]) -> Self {
let seed_hex = seed_hex(seed);
Self {
trapdoor,
nullifier,
trapdoor: derive_field(&seed_hex, b"identity_trapdoor"),
nullifier: derive_field(&seed_hex, b"identity_nullifier"),
}
}

View File

@ -4,6 +4,7 @@
#![allow(clippy::multiple_crate_versions)]
mod circuit;
mod field;
pub mod hash;
pub mod identity;
pub mod merkle_tree;
@ -17,40 +18,52 @@ pub mod mimc_hash;
#[cfg(feature = "mimc")]
pub mod mimc_tree;
use ark_bn254::{Fr, Parameters};
use ark_bn254::Parameters;
use ark_ec::bn::Bn;
pub use crate::poseidon_hash::poseidon_hash;
// Export types
pub use crate::{
field::{hash_to_field, Field},
poseidon_hash::poseidon_hash,
};
pub type Field = Fr;
pub type Groth16Proof = ark_groth16::Proof<Bn<Parameters>>;
pub type EthereumGroth16Proof = ark_circom::ethereum::Proof;
#[cfg(test)]
mod test {
use crate::{
hash::Hash,
hash_to_field,
identity::Identity,
poseidon_tree::PoseidonTree,
protocol::{generate_nullifier_hash, generate_proof, hash_to_field, verify_proof},
protocol::{generate_nullifier_hash, generate_proof, verify_proof},
Field,
};
use hex_literal::hex;
#[test]
fn test_field_serde() {
let value = Field::from(0x1234_5678);
let serialized = serde_json::to_value(value).unwrap();
let deserialized = serde_json::from_value(serialized).unwrap();
assert_eq!(value, deserialized);
}
#[test]
fn test_end_to_end() {
const LEAF: Hash = Hash::from_bytes_be(hex!(
"0000000000000000000000000000000000000000000000000000000000000000"
));
// const LEAF: Hash = Hash::from_bytes_be(hex!(
// "0000000000000000000000000000000000000000000000000000000000000000"
// ));
let leaf = Field::from(0);
// generate identity
let id = Identity::new(b"hello");
let id = Identity::from_seed(b"hello");
// generate merkle tree
let mut tree = PoseidonTree::new(21, LEAF);
tree.set(0, id.commitment().into());
let mut tree = PoseidonTree::new(21, leaf);
tree.set(0, id.commitment());
let merkle_proof = tree.proof(0).expect("proof should exist");
let root = tree.root().into();
let root = tree.root();
// change signal and external_nullifier here
let signal = b"xxx";
@ -79,13 +92,10 @@ mod test {
#[cfg(feature = "bench")]
pub mod bench {
use crate::{
hash::Hash,
identity::Identity,
poseidon_tree::PoseidonTree,
protocol::{generate_proof, hash_to_field},
hash_to_field, identity::Identity, poseidon_tree::PoseidonTree, protocol::generate_proof,
Field,
};
use criterion::Criterion;
use hex_literal::hex;
pub fn group(criterion: &mut Criterion) {
#[cfg(feature = "mimc")]
@ -96,14 +106,12 @@ pub mod bench {
}
fn bench_proof(criterion: &mut Criterion) {
const LEAF: Hash = Hash::from_bytes_be(hex!(
"0000000000000000000000000000000000000000000000000000000000000000"
));
let leaf = Field::from(0);
// Create tree
let id = Identity::new(b"hello");
let mut tree = PoseidonTree::new(21, LEAF);
tree.set(0, id.commitment().into());
let id = Identity::from_seed(b"hello");
let mut tree = PoseidonTree::new(21, leaf);
tree.set(0, id.commitment());
let merkle_proof = tree.proof(0).expect("proof should exist");
// change signal and external_nullifier here

View File

@ -8,8 +8,8 @@
//!
//! * Instantiate a `PrimeField` to use Montgomery form.
use crate::util::keccak256;
use once_cell::sync::Lazy;
use tiny_keccak::{Hasher as _, Keccak};
use zkp_u256::U256;
const NUM_ROUNDS: usize = 220;
@ -21,14 +21,6 @@ static MODULUS: Lazy<U256> = Lazy::new(|| {
.unwrap()
});
fn keccak256(bytes: &[u8]) -> [u8; 32] {
let mut output = [0; 32];
let mut hasher = Keccak::v256();
hasher.update(bytes);
hasher.finalize(&mut output);
output
}
static ROUND_CONSTANTS: Lazy<[U256; NUM_ROUNDS]> = Lazy::new(|| {
const SEED: &str = "mimcsponge";
let mut result = [U256::ZERO; NUM_ROUNDS];

View File

@ -1,57 +1,15 @@
use crate::Field;
use ark_ff::{BigInteger256, PrimeField as _};
use ff::PrimeField as _;
use once_cell::sync::Lazy;
use poseidon_rs::{Fr, FrRepr, Poseidon};
use poseidon_rs::Poseidon;
static POSEIDON: Lazy<Poseidon> = Lazy::new(Poseidon::new);
#[must_use]
fn ark_to_poseidon(n: Field) -> Fr {
Fr::from_repr(FrRepr(n.into_repr().0)).expect("n is a valid field element")
}
#[must_use]
fn poseidon_to_ark(n: Fr) -> Field {
Field::from_repr(BigInteger256(n.into_repr().0)).expect("n is a valid field element")
}
#[must_use]
pub fn poseidon_hash(input: &[Field]) -> Field {
let input = input
.iter()
.copied()
.map(ark_to_poseidon)
.collect::<Vec<_>>();
let input = input.iter().copied().map(Into::into).collect::<Vec<_>>();
POSEIDON
.hash(input)
.map(poseidon_to_ark)
.map(Into::into)
.expect("hash with fixed input size can't fail")
}
#[cfg(test)]
mod test {
use super::{ark_to_poseidon, poseidon_to_ark};
use crate::Field;
use ark_ff::{Field as _, UniformRand};
use ff::PrimeField;
use poseidon_rs::Fr;
use rand_chacha::ChaChaRng;
use rand_core::SeedableRng;
#[test]
fn test_modulus_identical() {
assert_eq!(Fr::char().0, Field::characteristic());
}
#[test]
fn test_ark_pos_ark_roundtrip() {
let mut rng = ChaChaRng::seed_from_u64(123);
for _ in 0..1000 {
let n = Field::rand(&mut rng);
let m = poseidon_to_ark(ark_to_poseidon(n));
assert_eq!(n, m);
}
}
}

View File

@ -1,9 +1,7 @@
use crate::{
hash::Hash,
merkle_tree::{self, Hasher, MerkleTree},
poseidon_hash, Field,
};
use ark_ff::{PrimeField, ToBytes};
use serde::{Deserialize, Serialize};
#[allow(dead_code)]
@ -16,81 +14,54 @@ pub type Proof = merkle_tree::Proof<PoseidonHash>;
#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct PoseidonHash;
#[allow(clippy::fallible_impl_from)] // TODO
impl From<&Hash> for Field {
fn from(hash: &Hash) -> Self {
Self::from_be_bytes_mod_order(&hash.0)
}
}
#[allow(clippy::fallible_impl_from)] // TODO
impl From<Hash> for Field {
fn from(hash: Hash) -> Self {
Self::from_be_bytes_mod_order(&hash.0)
}
}
#[allow(clippy::fallible_impl_from)] // TODO
impl From<Field> for Hash {
fn from(n: Field) -> Self {
let mut bytes = [0_u8; 32];
n.into_repr()
.write(&mut bytes[..])
.expect("write should succeed");
bytes.reverse(); // Convert to big endian
Self(bytes)
}
}
impl Hasher for PoseidonHash {
type Hash = Hash;
type Hash = Field;
fn hash_node(left: &Self::Hash, right: &Self::Hash) -> Self::Hash {
poseidon_hash(&[left.into(), right.into()]).into()
poseidon_hash(&[*left, *right])
}
}
#[cfg(test)]
pub mod test {
use super::*;
use ark_ff::UniformRand;
use hex_literal::hex;
use rand_chacha::ChaChaRng;
use rand_core::SeedableRng;
#[test]
fn test_ark_hash_ark_roundtrip() {
let mut rng = ChaChaRng::seed_from_u64(123);
for _ in 0..1000 {
let n = Field::rand(&mut rng);
let m = Hash::from(n).into();
assert_eq!(n, m);
}
}
// TODO: proptest
// #[test]
// fn test_ark_hash_ark_roundtrip() {
// let mut rng = ChaChaRng::seed_from_u64(123);
// for _ in 0..1000 {
// let n = Field::rand(&mut rng);
// let m = Hash::from(n).into();
// assert_eq!(n, m);
// }
// }
#[test]
fn test_tree_4() {
const LEAF: Hash = Hash::from_bytes_be(hex!(
"0000000000000000000000000000000000000000000000000000000000000000"
));
// TODO: Const constructor
// #[test]
// fn test_tree_4() {
// const LEAF: Hash = Hash::from_bytes_be(hex!(
// "0000000000000000000000000000000000000000000000000000000000000000"
// ));
let tree = PoseidonTree::new(3, LEAF);
assert_eq!(tree.num_leaves(), 4);
assert_eq!(
tree.root(),
Hash::from_bytes_be(hex!(
"1069673dcdb12263df301a6ff584a7ec261a44cb9dc68df067a4774460b1f1e1"
))
);
let proof = tree.proof(3).expect("proof should exist");
assert_eq!(
proof,
crate::merkle_tree::Proof(vec![
Branch::Right(LEAF),
Branch::Right(Hash::from_bytes_be(hex!(
"2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864"
))),
])
);
}
// let tree = PoseidonTree::new(3, LEAF);
// assert_eq!(tree.num_leaves(), 4);
// assert_eq!(
// tree.root(),
// Hash::from_bytes_be(hex!(
//
// "1069673dcdb12263df301a6ff584a7ec261a44cb9dc68df067a4774460b1f1e1"
// ))
// );
// let proof = tree.proof(3).expect("proof should exist");
// assert_eq!(
// proof,
// crate::merkle_tree::Proof(vec![
// Branch::Right(LEAF),
// Branch::Right(Hash::from_bytes_be(hex!(
//
// "2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864"
// ))),
// ])
// );
// }
}

View File

@ -9,13 +9,10 @@ use crate::{
use ark_bn254::{Bn254, Parameters};
use ark_circom::CircomReduction;
use ark_ec::bn::Bn;
use ark_ff::PrimeField;
use ark_groth16::{create_proof_with_reduction_and_matrices, prepare_verifying_key, Proof};
use ark_relations::r1cs::SynthesisError;
use ark_std::{rand::thread_rng, UniformRand};
use color_eyre::Result;
use ethers_core::utils::keccak256;
use num_bigint::{BigInt, BigUint, ToBigInt};
use std::time::Instant;
use thiserror::Error;
@ -26,23 +23,11 @@ fn merkle_proof_to_vec(proof: &merkle_tree::Proof<PoseidonHash>) -> Vec<Field> {
.0
.iter()
.map(|x| match x {
Branch::Left(value) | Branch::Right(value) => value.into(),
Branch::Left(value) | Branch::Right(value) => *value,
})
.collect()
}
/// Hash arbitrary data to a field element.
///
/// This is used to create `signal_hash` and `external_nullifier_hash`.
#[must_use]
pub fn hash_to_field(data: &[u8]) -> Field {
let hash = keccak256(data);
// Shift right one byte to make it fit in the field
let mut bytes = [0_u8; 32];
bytes[1..].copy_from_slice(&hash[..31]);
Field::from_be_bytes_mod_order(&bytes)
}
/// Generates the nullifier hash
#[must_use]
pub fn generate_nullifier_hash(identity: &Identity, external_nullifier: Field) -> Field {
@ -59,11 +44,6 @@ pub enum ProofError {
SynthesisError(#[from] SynthesisError),
}
fn ark_to_bigint(n: Field) -> BigInt {
let n: BigUint = n.into();
n.to_bigint().expect("conversion always succeeds for uint")
}
/// Generates a semaphore proof
///
/// # Errors
@ -86,11 +66,7 @@ pub fn generate_proof(
let inputs = inputs.into_iter().map(|(name, values)| {
(
name.to_string(),
values
.iter()
.copied()
.map(ark_to_bigint)
.collect::<Vec<_>>(),
values.iter().copied().map(Into::into).collect::<Vec<_>>(),
)
});
@ -141,7 +117,12 @@ pub fn verify_proof(
) -> Result<bool, ProofError> {
let pvk = prepare_verifying_key(&ZKEY.0.vk);
let public_inputs = vec![root, nullifier_hash, signal_hash, external_nullifier_hash];
let result = ark_groth16::verify_proof(&pvk, proof, &public_inputs)?;
let public_inputs = [
root.into(),
nullifier_hash.into(),
signal_hash.into(),
external_nullifier_hash.into(),
];
let result = ark_groth16::verify_proof(&pvk, proof, &public_inputs[..])?;
Ok(result)
}

View File

@ -1,35 +1,18 @@
use ff::{PrimeField, PrimeFieldRepr};
use num_bigint::{BigInt, Sign};
use poseidon_rs::{Fr, FrRepr};
use tiny_keccak::{Hasher as _, Keccak};
#[must_use]
#[allow(clippy::missing_panics_doc)] // TODO: Remove panics
pub fn fr_to_bigint(fr: Fr) -> BigInt {
let mut bytes = [0_u8; 32];
fr.into_repr().write_be(&mut bytes[..]).unwrap();
BigInt::from_bytes_be(Sign::Plus, &bytes)
pub(crate) fn keccak256(bytes: &[u8]) -> [u8; 32] {
let mut output = [0; 32];
let mut hasher = Keccak::v256();
hasher.update(bytes);
hasher.finalize(&mut output);
output
}
#[must_use]
#[allow(clippy::missing_panics_doc)] // TODO: Remove panics
pub fn bigint_to_fr(bi: &BigInt) -> Fr {
// dirty: have to force the point into the field manually, otherwise you get an
// error if bi not in field
let q = BigInt::parse_bytes(
b"21888242871839275222246405745257275088548364400416034343698204186575808495617",
10,
)
.unwrap();
let m = bi.modpow(&BigInt::from(1), &q);
let mut repr = FrRepr::default();
let (_, mut res) = m.to_bytes_be();
// prepend zeros
res.reverse();
res.resize(32, 0);
res.reverse();
repr.read_be(&res[..]).unwrap();
Fr::from_repr(repr).unwrap()
/// Helper function to optionally remove `0x` prefix from hex strings.
pub(crate) fn trim_hex_prefix(str: &str) -> &str {
if str.len() >= 2 && (&str[..2] == "0x" || &str[..2] == "0X") {
&str[2..]
} else {
str
}
}