diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr index 3c1ac469c9af..38e063a62be9 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr @@ -49,19 +49,20 @@ impl AztecAddress { Self { inner: 0 } } - /// Returns an address's `AddressPoint`, which can be used to create shared secrets with the owner - /// of the address. If the address is invalid (i.e. it is not a properly derived Aztec address), then this - /// returns `Option::none()`, and no shared secrets can be created. - pub fn to_address_point(self) -> Option { - // We compute the address point by taking our address as x, and then solving for y in the - // equation which defines the grumpkin curve: - // y^2 = x^3 - 17; x = address - let x = self.inner; - let y_squared = x * x * x - 17; + /// Returns `true` if the address is valid. + /// + /// An invalid address is one that can be proven to not be correctly derived, meaning it contains no contract code, + /// public keys, etc., and can therefore not receive messages nor execute calls. + pub fn is_valid(self) -> bool { + self.get_y().is_some() + } - // An invalid AztecAddress is one for which no y coordinate satisfies the curve equation, which we'll - // identify by proving that the square root of y_squared does not exist. - sqrt(y_squared).map(|y| { + /// Returns an address's [`AddressPoint`]. + /// + /// This can be used to create shared secrets with the owner of the address. If the address is invalid (see + /// [`AztecAddress::is_valid`]) then this returns `Option::none()`, and no shared secrets can be created. + pub fn to_address_point(self) -> Option { + self.get_y().map(|y| { // If we get a negative y coordinate (y > (r - 1) / 2), we swap it to the // positive one (where y <= (r - 1) / 2) by negating it. let final_y = if Self::is_positive(y) { y } else { -y }; @@ -83,6 +84,24 @@ impl AztecAddress { y.lt(MID_PLUS_1) } + /// Returns one of the two possible y-coordinates. + /// + /// Not all `AztecAddresses` are valid, in which case there is no corresponding y-coordinate. This returns + /// `Option::none()` for invalid addresses. + /// + /// An `AztecAddress` is defined by an x-coordinate, for which two y-coordinates exist as solutions to the curve + /// equation. This function returns either of them. Note that an [`AddressPoint`] must **always** have a positive + /// y-coordinate - if trying to obtain the underlying point use [`AztecAddress::to_address_point`] instead. + fn get_y(self) -> Option { + // We compute the address point by taking our address as x, and then solving for y in the + // equation which defines the grumpkin curve: + // y^2 = x^3 - 17; x = address + let x = self.inner; + let y_squared = x * x * x - 17; + + sqrt(y_squared) + } + pub fn compute(public_keys: PublicKeys, partial_address: PartialAddress) -> AztecAddress { // // address = address_point.x @@ -265,6 +284,10 @@ fn serde() { fn to_address_point_valid() { // x = 8 where x^3 - 17 = 512 - 17 = 495, which is a residue in this field let address = AztecAddress { inner: 8 }; + + assert(address.get_y().is_some()); // We don't bother checking the result of get_y as it is only used internally + assert(address.is_valid()); + let maybe_point = address.to_address_point(); assert(maybe_point.is_some()); @@ -279,7 +302,10 @@ fn to_address_point_valid() { #[test] unconstrained fn to_address_point_invalid() { // x = 3 where x^3 - 17 = 27 - 17 = 10, which is a non-residue in this field - let address = AztecAddress { inner: 3 }; // - let maybe_point = address.to_address_point(); - assert(maybe_point.is_none()); + let address = AztecAddress { inner: 3 }; + + assert(address.get_y().is_none()); + assert(!address.is_valid()); + + assert(address.to_address_point().is_none()); }