forked from bluealloy/revm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathg1.rs
91 lines (84 loc) · 3.26 KB
/
g1.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use super::utils::{fp_from_bendian, fp_to_bytes, remove_padding};
use crate::bls12_381_const::{G1_INPUT_ITEM_LENGTH, G1_OUTPUT_LENGTH, PADDED_FP_LENGTH};
use crate::PrecompileError;
use blst::{blst_p1_affine, blst_p1_affine_in_g1, blst_p1_affine_on_curve};
use primitives::Bytes;
/// Encodes a G1 point in affine format into byte slice with padded elements.
pub(super) fn encode_g1_point(input: *const blst_p1_affine) -> Bytes {
let mut out = vec![0u8; G1_OUTPUT_LENGTH];
// SAFETY: Out comes from fixed length array, input is a blst value.
unsafe {
fp_to_bytes(&mut out[..PADDED_FP_LENGTH], &(*input).x);
fp_to_bytes(&mut out[PADDED_FP_LENGTH..], &(*input).y);
}
out.into()
}
/// Returns a `blst_p1_affine` from the provided byte slices, which represent the x and y
/// affine coordinates of the point.
///
/// If the x or y coordinate do not represent a canonical field element, an error is returned.
///
/// See [fp_from_bendian] for more information.
pub(super) fn decode_and_check_g1(
p0_x: &[u8; 48],
p0_y: &[u8; 48],
) -> Result<blst_p1_affine, PrecompileError> {
let out = blst_p1_affine {
x: fp_from_bendian(p0_x)?,
y: fp_from_bendian(p0_y)?,
};
Ok(out)
}
/// Extracts a G1 point in Affine format from a 128 byte slice representation.
///
/// **Note**: This function will perform a G1 subgroup check if `subgroup_check` is set to `true`.
pub(super) fn extract_g1_input(
input: &[u8],
subgroup_check: bool,
) -> Result<blst_p1_affine, PrecompileError> {
if input.len() != G1_INPUT_ITEM_LENGTH {
return Err(PrecompileError::Other(format!(
"Input should be {G1_INPUT_ITEM_LENGTH} bytes, was {}",
input.len()
)));
}
let input_p0_x = remove_padding(&input[..PADDED_FP_LENGTH])?;
let input_p0_y = remove_padding(&input[PADDED_FP_LENGTH..G1_INPUT_ITEM_LENGTH])?;
let out = decode_and_check_g1(input_p0_x, input_p0_y)?;
if subgroup_check {
// NB: Subgroup checks
//
// Scalar multiplications, MSMs and pairings MUST perform a subgroup check.
//
// Implementations SHOULD use the optimized subgroup check method:
//
// https://eips.ethereum.org/assets/eip-2537/fast_subgroup_checks
//
// On any input that fail the subgroup check, the precompile MUST return an error.
//
// 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()));
}
} else {
// From EIP-2537:
//
// Error cases:
//
// * An input is neither a point on the G1 elliptic curve nor the infinity point
//
// NB: There is no subgroup check for the G1 addition precompile.
//
// We use blst_p1_affine_on_curve instead of blst_p1_affine_in_g1 because the latter performs
// the subgroup check.
//
// 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(),
));
}
}
Ok(out)
}