Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 7 additions & 19 deletions crates/precompile/src/bls12_381/arkworks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use ark_ec::{
use ark_ff::{One, PrimeField, Zero};

use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use std::{string::ToString, vec::Vec};
use std::vec::Vec;

/// Reads a single `Fp` field element from the input slice.
///
Expand All @@ -34,8 +34,7 @@ fn read_fp(input_be: &[u8]) -> Result<Fq, PrecompileError> {
// Reverse in-place to convert from big-endian to little-endian.
input_le.reverse();

Fq::deserialize_uncompressed(&input_le[..])
.map_err(|_| PrecompileError::Other("non-canonical fp value".to_string()))
Fq::deserialize_uncompressed(&input_le[..]).map_err(|_| PrecompileError::NonCanonicalFp)
}

/// Encodes an `Fp` field element into a big-endian byte array.
Expand Down Expand Up @@ -80,9 +79,7 @@ fn new_g1_point_no_subgroup_check(px: Fq, py: Fq) -> Result<G1Affine, Precompile
// We cannot use `G1Affine::new` because that triggers an assert if the point is not on the curve.
let point = G1Affine::new_unchecked(px, py);
if !point.is_on_curve() {
return Err(PrecompileError::Other(
"Element not on G1 curve".to_string(),
));
return Err(PrecompileError::Bls12381G1NotOnCurve);
}
Ok(point)
}
Expand All @@ -104,9 +101,7 @@ fn new_g2_point_no_subgroup_check(x: Fq2, y: Fq2) -> Result<G2Affine, Precompile
// We cannot use `G2Affine::new` because that triggers an assert if the point is not on the curve.
let point = G2Affine::new_unchecked(x, y);
if !point.is_on_curve() {
return Err(PrecompileError::Other(
"Element not on G2 curve".to_string(),
));
return Err(PrecompileError::Bls12381G2NotOnCurve);
}
point
};
Expand All @@ -127,9 +122,7 @@ fn new_g2_point_no_subgroup_check(x: Fq2, y: Fq2) -> Result<G2Affine, Precompile
fn read_g1(x: &[u8; FP_LENGTH], y: &[u8; FP_LENGTH]) -> Result<G1Affine, PrecompileError> {
let point = read_g1_no_subgroup_check(x, y)?;
if !point.is_in_correct_subgroup_assuming_on_curve() {
return Err(PrecompileError::Other(
"Element not in the correct subgroup".to_string(),
));
return Err(PrecompileError::Bls12381G1NotInSubgroup);
}
Ok(point)
}
Expand Down Expand Up @@ -186,9 +179,7 @@ fn read_g2(
) -> Result<G2Affine, PrecompileError> {
let point = read_g2_no_subgroup_check(a_x_0, a_x_1, a_y_0, a_y_1)?;
if !point.is_in_correct_subgroup_assuming_on_curve() {
return Err(PrecompileError::Other(
"Element not in the correct subgroup".to_string(),
));
return Err(PrecompileError::Bls12381G1NotInSubgroup);
}
Ok(point)
}
Expand Down Expand Up @@ -244,10 +235,7 @@ fn encode_g2_point(input: &G2Affine) -> [u8; G2_LENGTH] {
#[inline]
fn read_scalar(input: &[u8]) -> Result<Fr, PrecompileError> {
if input.len() != SCALAR_LENGTH {
return Err(PrecompileError::Other(format!(
"Input should be {SCALAR_LENGTH} bytes, was {}",
input.len()
)));
return Err(PrecompileError::Bls12381ScalarInputLength);
}

Ok(Fr::from_be_bytes_mod_order(input))
Expand Down
20 changes: 6 additions & 14 deletions crates/precompile/src/bls12_381/blst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use blst::{
blst_p2_affine, blst_p2_affine_in_g2, blst_p2_affine_on_curve, blst_p2_from_affine,
blst_p2_mult, blst_p2_to_affine, blst_scalar, blst_scalar_from_bendian, MultiPoint,
};
use std::string::ToString;
use std::vec::Vec;

// Big-endian non-Montgomery form.
Expand Down Expand Up @@ -382,9 +381,7 @@ fn decode_g1_on_curve(
//
// SAFETY: Out is a blst value.
if unsafe { !blst_p1_affine_on_curve(&out) } {
return Err(PrecompileError::Other(
"Element not on G1 curve".to_string(),
));
return Err(PrecompileError::Bls12381G1NotOnCurve);
}

Ok(out)
Expand Down Expand Up @@ -436,7 +433,7 @@ fn _extract_g1_input(
// As endomorphism acceleration requires input on the correct subgroup, implementers MAY
// use endomorphism acceleration.
if unsafe { !blst_p1_affine_in_g1(&out) } {
return Err(PrecompileError::Other("Element not in G1".to_string()));
return Err(PrecompileError::Bls12381G1NotInSubgroup);
}
}
Ok(out)
Expand Down Expand Up @@ -481,9 +478,7 @@ fn decode_g2_on_curve(
//
// SAFETY: Out is a blst value.
if unsafe { !blst_p2_affine_on_curve(&out) } {
return Err(PrecompileError::Other(
"Element not on G2 curve".to_string(),
));
return Err(PrecompileError::Bls12381G2NotOnCurve);
}

Ok(out)
Expand Down Expand Up @@ -559,7 +554,7 @@ fn _extract_g2_input(
// As endomorphism acceleration requires input on the correct subgroup, implementers MAY
// use endomorphism acceleration.
if unsafe { !blst_p2_affine_in_g2(&out) } {
return Err(PrecompileError::Other("Element not in G2".to_string()));
return Err(PrecompileError::Bls12381G2NotInSubgroup);
}
}
Ok(out)
Expand All @@ -571,7 +566,7 @@ fn _extract_g2_input(
/// Note: The field element is expected to be in big endian format.
fn read_fp(input: &[u8; FP_LENGTH]) -> Result<blst_fp, PrecompileError> {
if !is_valid_be(input) {
return Err(PrecompileError::Other("non-canonical fp value".to_string()));
return Err(PrecompileError::NonCanonicalFp);
}
let mut fp = blst_fp::default();
// SAFETY: `input` has fixed length, and `fp` is a blst value.
Expand All @@ -595,10 +590,7 @@ fn read_fp(input: &[u8; FP_LENGTH]) -> Result<blst_fp, PrecompileError> {
/// `q`.
fn read_scalar(input: &[u8]) -> Result<blst_scalar, PrecompileError> {
if input.len() != SCALAR_LENGTH {
return Err(PrecompileError::Other(format!(
"Input should be {SCALAR_LENGTH} bytes, was {}",
input.len()
)));
return Err(PrecompileError::Bls12381ScalarInputLength);
}

let mut out = blst_scalar::default();
Expand Down
5 changes: 1 addition & 4 deletions crates/precompile/src/bls12_381/g1_add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@ pub fn g1_add(input: &[u8], gas_limit: u64) -> PrecompileResult {
}

if input.len() != G1_ADD_INPUT_LENGTH {
return Err(PrecompileError::Other(format!(
"G1ADD input should be {G1_ADD_INPUT_LENGTH} bytes, was {}",
input.len()
)));
return Err(PrecompileError::Bls12381G1AddInputLength);
}

// Extract coordinates from padded input
Expand Down
11 changes: 2 additions & 9 deletions crates/precompile/src/bls12_381/g1_msm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ pub const PRECOMPILE: Precompile =
pub fn g1_msm(input: &[u8], gas_limit: u64) -> PrecompileResult {
let input_len = input.len();
if input_len == 0 || !input_len.is_multiple_of(G1_MSM_INPUT_LENGTH) {
return Err(PrecompileError::Other(format!(
"G1MSM input length should be multiple of {G1_MSM_INPUT_LENGTH}, was {input_len}",
)));
return Err(PrecompileError::Bls12381G1MsmInputLength);
}

let k = input_len / G1_MSM_INPUT_LENGTH;
Expand Down Expand Up @@ -66,11 +64,6 @@ mod test {
fn bls_g1multiexp_g1_not_on_curve_but_in_subgroup() {
let input = Bytes::from(hex!("000000000000000000000000000000000a2833e497b38ee3ca5c62828bf4887a9f940c9e426c7890a759c20f248c23a7210d2432f4c98a514e524b5184a0ddac00000000000000000000000000000000150772d56bf9509469f9ebcd6e47570429fd31b0e262b66d512e245c38ec37255529f2271fd70066473e393a8bead0c30000000000000000000000000000000000000000000000000000000000000000"));
let fail = g1_msm(&input, G1_MSM_BASE_GAS_FEE);
assert_eq!(
fail,
Err(PrecompileError::Other(
"Element not on G1 curve".to_string()
))
);
assert_eq!(fail, Err(PrecompileError::Bls12381G1NotOnCurve));
}
}
5 changes: 1 addition & 4 deletions crates/precompile/src/bls12_381/g2_add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ pub fn g2_add(input: &[u8], gas_limit: u64) -> PrecompileResult {
}

if input.len() != G2_ADD_INPUT_LENGTH {
return Err(PrecompileError::Other(format!(
"G2ADD input should be {G2_ADD_INPUT_LENGTH} bytes, was {}",
input.len()
)));
return Err(PrecompileError::Bls12381G2AddInputLength);
}

// Extract coordinates from padded input
Expand Down
4 changes: 1 addition & 3 deletions crates/precompile/src/bls12_381/g2_msm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ pub const PRECOMPILE: Precompile =
pub fn g2_msm(input: &[u8], gas_limit: u64) -> PrecompileResult {
let input_len = input.len();
if input_len == 0 || !input_len.is_multiple_of(G2_MSM_INPUT_LENGTH) {
return Err(PrecompileError::Other(format!(
"G2MSM input length should be multiple of {G2_MSM_INPUT_LENGTH}, was {input_len}",
)));
return Err(PrecompileError::Bls12381G2MsmInputLength);
}

let k = input_len / G2_MSM_INPUT_LENGTH;
Expand Down
5 changes: 1 addition & 4 deletions crates/precompile/src/bls12_381/map_fp2_to_g2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,7 @@ pub fn map_fp2_to_g2(input: &[u8], gas_limit: u64) -> PrecompileResult {
}

if input.len() != PADDED_FP2_LENGTH {
return Err(PrecompileError::Other(format!(
"MAP_FP2_TO_G2 input should be {PADDED_FP2_LENGTH} bytes, was {}",
input.len()
)));
return Err(PrecompileError::Bls12381MapFp2ToG2InputLength);
}

let input_p0_x = remove_fp_padding(&input[..PADDED_FP_LENGTH])?;
Expand Down
10 changes: 2 additions & 8 deletions crates/precompile/src/bls12_381/map_fp_to_g1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ pub fn map_fp_to_g1(input: &[u8], gas_limit: u64) -> PrecompileResult {
}

if input.len() != PADDED_FP_LENGTH {
return Err(PrecompileError::Other(format!(
"MAP_FP_TO_G1 input should be {PADDED_FP_LENGTH} bytes, was {}",
input.len()
)));
return Err(PrecompileError::Bls12381MapFpToG1InputLength);
}

let input_p0 = remove_fp_padding(input)?;
Expand All @@ -49,9 +46,6 @@ mod test {
fn sanity_test() {
let input = Bytes::from(hex!("000000000000000000000000000000006900000000000000636f6e7472616374595a603f343061cd305a03f40239f5ffff31818185c136bc2595f2aa18e08f17"));
let fail = map_fp_to_g1(&input, MAP_FP_TO_G1_BASE_GAS_FEE);
assert_eq!(
fail,
Err(PrecompileError::Other("non-canonical fp value".to_string()))
);
assert_eq!(fail, Err(PrecompileError::NonCanonicalFp));
}
}
4 changes: 1 addition & 3 deletions crates/precompile/src/bls12_381/pairing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ pub const PRECOMPILE: Precompile =
pub fn pairing(input: &[u8], gas_limit: u64) -> PrecompileResult {
let input_len = input.len();
if input_len == 0 || !input_len.is_multiple_of(PAIRING_INPUT_LENGTH) {
return Err(PrecompileError::Other(format!(
"Pairing input length should be multiple of {PAIRING_INPUT_LENGTH}, was {input_len}"
)));
return Err(PrecompileError::Bls12381PairingInputLength);
}

let k = input_len / PAIRING_INPUT_LENGTH;
Expand Down
19 changes: 4 additions & 15 deletions crates/precompile/src/bls12_381/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,19 @@ use crate::PrecompileError;
/// Removes zeros with which the precompile inputs are left padded to 64 bytes.
pub(super) fn remove_fp_padding(input: &[u8]) -> Result<&[u8; FP_LENGTH], PrecompileError> {
if input.len() != PADDED_FP_LENGTH {
return Err(PrecompileError::Other(format!(
"Padded input should be {PADDED_FP_LENGTH} bytes, was {}",
input.len()
)));
return Err(PrecompileError::Bls12381FpPaddingLength);
}
let (padding, unpadded) = input.split_at(FP_PAD_BY);
if !padding.iter().all(|&x| x == 0) {
return Err(PrecompileError::Other(format!(
"{FP_PAD_BY} top bytes of input are not zero",
)));
return Err(PrecompileError::Bls12381FpPaddingInvalid);
}
Ok(unpadded.try_into().unwrap())
}
/// remove_g1_padding removes the padding applied to the Fp elements that constitute the
/// encoded G1 element.
pub(super) fn remove_g1_padding(input: &[u8]) -> Result<[&[u8; FP_LENGTH]; 2], PrecompileError> {
if input.len() != PADDED_G1_LENGTH {
return Err(PrecompileError::Other(format!(
"Input should be {PADDED_G1_LENGTH} bytes, was {}",
input.len()
)));
return Err(PrecompileError::Bls12381G1PaddingLength);
}

let x = remove_fp_padding(&input[..PADDED_FP_LENGTH])?;
Expand All @@ -39,10 +31,7 @@ pub(super) fn remove_g1_padding(input: &[u8]) -> Result<[&[u8; FP_LENGTH]; 2], P
/// encoded G2 element.
pub(super) fn remove_g2_padding(input: &[u8]) -> Result<[&[u8; FP_LENGTH]; 4], PrecompileError> {
if input.len() != PADDED_G2_LENGTH {
return Err(PrecompileError::Other(format!(
"Input should be {PADDED_G2_LENGTH} bytes, was {}",
input.len()
)));
return Err(PrecompileError::Bls12381G2PaddingLength);
}

let mut input_fps = [&[0; FP_LENGTH]; 4];
Expand Down
68 changes: 67 additions & 1 deletion crates/precompile/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ pub trait Crypto: Send + Sync + Debug {
msg: &[u8; 32],
) -> Result<[u8; 32], PrecompileError> {
crate::secp256k1::ecrecover_bytes(*sig, recid, *msg)
.ok_or_else(|| PrecompileError::other("ecrecover failed"))
.ok_or(PrecompileError::Secp256k1RecoverFailed)
}

/// Modular exponentiation.
Expand Down Expand Up @@ -230,6 +230,50 @@ pub enum PrecompileError {
BlobMismatchedVersion,
/// The proof verification failed
BlobVerifyKzgProofFailed,
/// Non-canonical field element
NonCanonicalFp,
/// BLS12-381 G1 point not on curve
Bls12381G1NotOnCurve,
/// BLS12-381 G1 point not in correct subgroup
Bls12381G1NotInSubgroup,
/// BLS12-381 G2 point not on curve
Bls12381G2NotOnCurve,
/// BLS12-381 G2 point not in correct subgroup
Bls12381G2NotInSubgroup,
/// BLS12-381 scalar input length error
Bls12381ScalarInputLength,
/// BLS12-381 G1 add input length error
Bls12381G1AddInputLength,
/// BLS12-381 G1 msm input length error
Bls12381G1MsmInputLength,
/// BLS12-381 G2 add input length error
Bls12381G2AddInputLength,
/// BLS12-381 G2 msm input length error
Bls12381G2MsmInputLength,
/// BLS12-381 pairing input length error
Bls12381PairingInputLength,
/// BLS12-381 map fp to g1 input length error
Bls12381MapFpToG1InputLength,
/// BLS12-381 map fp2 to g2 input length error
Bls12381MapFp2ToG2InputLength,
/// BLS12-381 padding error
Bls12381FpPaddingInvalid,
/// BLS12-381 fp padding length error
Bls12381FpPaddingLength,
/// BLS12-381 g1 padding length error
Bls12381G1PaddingLength,
/// BLS12-381 g2 padding length error
Bls12381G2PaddingLength,
/// KZG invalid G1 point
KzgInvalidG1Point,
/// KZG G1 point not on curve
KzgG1PointNotOnCurve,
/// KZG G1 point not in correct subgroup
KzgG1PointNotInSubgroup,
/// KZG input length error
KzgInvalidInputLength,
/// secp256k1 ecrecover failed
Secp256k1RecoverFailed,
/// Fatal error with a custom error message
Fatal(String),
/// Catch-all variant for other errors
Expand Down Expand Up @@ -266,6 +310,28 @@ impl fmt::Display for PrecompileError {
Self::BlobInvalidInputLength => "invalid blob input length",
Self::BlobMismatchedVersion => "mismatched blob version",
Self::BlobVerifyKzgProofFailed => "verifying blob kzg proof failed",
Self::NonCanonicalFp => "non-canonical field element",
Self::Bls12381G1NotOnCurve => "bls12-381 g1 point not on curve",
Self::Bls12381G1NotInSubgroup => "bls12-381 g1 point not in correct subgroup",
Self::Bls12381G2NotOnCurve => "bls12-381 g2 point not on curve",
Self::Bls12381G2NotInSubgroup => "bls12-381 g2 point not in correct subgroup",
Self::Bls12381ScalarInputLength => "bls12-381 scalar input length error",
Self::Bls12381G1AddInputLength => "bls12-381 g1 add input length error",
Self::Bls12381G1MsmInputLength => "bls12-381 g1 msm input length error",
Self::Bls12381G2AddInputLength => "bls12-381 g2 add input length error",
Self::Bls12381G2MsmInputLength => "bls12-381 g2 msm input length error",
Self::Bls12381PairingInputLength => "bls12-381 pairing input length error",
Self::Bls12381MapFpToG1InputLength => "bls12-381 map fp to g1 input length error",
Self::Bls12381MapFp2ToG2InputLength => "bls12-381 map fp2 to g2 input length error",
Self::Bls12381FpPaddingInvalid => "bls12-381 fp 64 top bytes of input are not zero",
Self::Bls12381FpPaddingLength => "bls12-381 fp padding length error",
Self::Bls12381G1PaddingLength => "bls12-381 g1 padding length error",
Self::Bls12381G2PaddingLength => "bls12-381 g2 padding length error",
Self::KzgInvalidG1Point => "kzg invalid g1 point",
Self::KzgG1PointNotOnCurve => "kzg g1 point not on curve",
Self::KzgG1PointNotInSubgroup => "kzg g1 point not in correct subgroup",
Self::KzgInvalidInputLength => "kzg invalid input length",
Self::Secp256k1RecoverFailed => "secp256k1 signature recovery failed",
Self::Fatal(s) => s,
Self::Other(s) => s,
};
Expand Down
Loading
Loading