Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: ec addition for non-zero points #5858

Merged
merged 21 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from 17 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
Original file line number Diff line number Diff line change
Expand Up @@ -1471,6 +1471,7 @@ impl<F: AcirField> AcirContext<F> {
| BlackBoxFunc::AND
| BlackBoxFunc::XOR
| BlackBoxFunc::AES128Encrypt
| BlackBoxFunc::EmbeddedCurveAdd
);
// Convert `AcirVar` to `FunctionInput`
let inputs = self.prepare_inputs_for_black_box_func_call(inputs, allow_constant_inputs)?;
Expand Down
62 changes: 53 additions & 9 deletions noir_stdlib/src/embedded_curve_ops.nr
Original file line number Diff line number Diff line change
Expand Up @@ -125,20 +125,64 @@ pub fn fixed_base_scalar_mul(scalar: EmbeddedCurveScalar) -> EmbeddedCurvePoint
multi_scalar_mul([g1], [scalar])
}

// This is a hack as returning an `EmbeddedCurvePoint` from a foreign function in brillig returns a [BrilligVariable::SingleAddr; 2] rather than BrilligVariable::BrilligArray
/// This function only assumes that the points are on the curve
/// It handles corner cases around the infinity point causing some overhead compared to embedded_curve_add_not_nul and embedded_curve_add_unsafe
// This is a hack because returning an `EmbeddedCurvePoint` from a foreign function in brillig returns a [BrilligVariable::SingleAddr; 2] rather than BrilligVariable::BrilligArray
// as is defined in the brillig bytecode format. This is a workaround which allows us to fix this without modifying the serialization format.
// docs:start:embedded_curve_add
fn embedded_curve_add(
pub fn embedded_curve_add(point1: EmbeddedCurvePoint, point2: EmbeddedCurvePoint) -> EmbeddedCurvePoint {
// docs:end:embedded_curve_add
let x_coordinates_match = point1.x == point2.x;
let y_coordinates_match = point1.y == point2.y;
let double_predicate = (x_coordinates_match & y_coordinates_match);
let infinity_predicate = (x_coordinates_match & !y_coordinates_match);
let point1_1 = EmbeddedCurvePoint { x: point1.x + (x_coordinates_match as Field), y: point1.y, is_infinite: x_coordinates_match };
// point1_1 is guaranteed to have a different abscissa than point2
let mut result = embedded_curve_add_unsafe(point1_1, point2);
result.is_infinite = x_coordinates_match;

// dbl if x_match, y_match
let double = embedded_curve_add_unsafe(point1, point1);
result = if double_predicate { double } else { result };

// infinity if x_match, !y_match
if point1.is_infinite {
result= point2;
}
if point2.is_infinite {
result = point1;
}
let mut result_is_infinity = infinity_predicate & (!point1.is_infinite & !point2.is_infinite);
result.is_infinite = result_is_infinity | (point1.is_infinite & point2.is_infinite);
result
}

#[foreign(embedded_curve_add)]
fn embedded_curve_add_array_return(_point1: EmbeddedCurvePoint, _point2: EmbeddedCurvePoint) -> [Field; 3] {}

/// This function assumes that:
/// The points are on the curve, and
/// The points have not the same abscissa, and
guipublic marked this conversation as resolved.
Show resolved Hide resolved
/// Neither point is the infinity point.
/// If it is used with correct input, the function ensures the correct non-zero result is returned.
/// Except for points on the curve, the other assumptions are checked by the function. It will cause assertion failure if they are not respected.
pub fn embedded_curve_add_not_nul(point1: EmbeddedCurvePoint, point2: EmbeddedCurvePoint) -> EmbeddedCurvePoint {
assert(point1.x - point2.x != 0);
assert(point1.is_infinite == false);
assert(point2.is_infinite == false);
guipublic marked this conversation as resolved.
Show resolved Hide resolved
embedded_curve_add_unsafe(point1, point2)
}

/// Unsafe ec addition
/// It assumes (but does not check) that the points have not the same absissa, or that they are the same variable
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved
/// It also assumes neither point is the infinity point.
pub fn embedded_curve_add_unsafe(
point1: EmbeddedCurvePoint,
point2: EmbeddedCurvePoint
) -> EmbeddedCurvePoint
// docs:end:embedded_curve_add
{
) -> EmbeddedCurvePoint {
let point_array = embedded_curve_add_array_return(point1, point2);
let x = point_array[0];
let y = point_array[1];
EmbeddedCurvePoint { x, y, is_infinite: point_array[2] == 1 }
}

#[foreign(embedded_curve_add)]
fn embedded_curve_add_array_return(_point1: EmbeddedCurvePoint, _point2: EmbeddedCurvePoint) -> [Field; 3] {}
EmbeddedCurvePoint { x, y, is_infinite: false }
}
Loading