Skip to content

Commit

Permalink
addressing more comments
Browse files Browse the repository at this point in the history
  • Loading branch information
sklppy88 committed Oct 24, 2024
1 parent 7c70f22 commit 9d81a35
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 98 deletions.
30 changes: 23 additions & 7 deletions noir-projects/aztec-nr/aztec/src/keys/getters/test.nr
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,32 @@ unconstrained fn test_get_public_keys_unknown() {

// Instead of querying for some unknown account, which would result in the oracle erroring out, we mock a bad oracle
// response to check that the circuit properly checks the address derivation.
let original_keys = get_public_keys(account.address).serialize();

// We fill in all the keys but we leave partial address = 0
let mut bad_response = [0; KEY_ORACLE_RESPONSE_LENGTH];
for i in 0..12 {
bad_response[i] = original_keys[i];
}
let mut random_keys_and_partial_address = [0; KEY_ORACLE_RESPONSE_LENGTH];
// We use randomly generated points on the curve, and a random partial address to ensure that
// this combination does not derive the address and we should see the assertion fail.

// npk_m
random_keys_and_partial_address[0] = 0x292364b852c6c6f01472951e76a39cbcf074591fd0e063a81965e7b51ad868a5;
random_keys_and_partial_address[1] = 0x0a687b46cdc9238f1c311f126aaaa4acbd7a737bff2efd7aeabdb8d805843a27;
random_keys_and_partial_address[2] = 0x0000000000000000000000000000000000000000000000000000000000000000;
// ivpk_m
random_keys_and_partial_address[3] = 0x173c5229a00c5425255680dd6edc27e278c48883991f348fe6985de43b4ec25f;
random_keys_and_partial_address[4] = 0x1698608e23b5f6c2f43c49a559108bb64e2247b8fc2da842296a416817f40b7f;
random_keys_and_partial_address[5] = 0x0000000000000000000000000000000000000000000000000000000000000000;
// ovpk_m
random_keys_and_partial_address[6] = 0x1bad2f7d1ad960a1bd0fe4d2c8d17f5ab4a86ef8b103e0a9e7f67ec0d3b4795e;
random_keys_and_partial_address[7] = 0x206db87110abbecc9fbaef2c865189d94ef2c106202f734ee4eba9257fd28bf1;
random_keys_and_partial_address[8] = 0x0000000000000000000000000000000000000000000000000000000000000000;
// tpk_m
random_keys_and_partial_address[9] = 0x05e3bd9cfe6b47daa139613619cf7d7fd8bb0112b6f2908caa6d9b536ed948ed;
random_keys_and_partial_address[10] = 0x051066f877c9df47552d02e7dc32127ff4edefc8498e813bca1cbd3f5d1be429;
random_keys_and_partial_address[11] = 0x0000000000000000000000000000000000000000000000000000000000000000;
// partial address
random_keys_and_partial_address[12] = 0x236703e2cb00a182e024e98e9f759231b556d25ff19f98896cebb69e9e678cc9;

let _ = OracleMock::mock("getPublicKeysAndPartialAddress")
.returns(bad_response.serialize())
.returns(random_keys_and_partial_address.serialize())
.times(1);
let _ = get_public_keys(account.address);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,13 @@ use crate::{
},
constants::{
AZTEC_ADDRESS_LENGTH, FUNCTION_TREE_HEIGHT, GENERATOR_INDEX__PUBLIC_KEYS_HASH,
GENERATOR_INDEX__CONTRACT_ADDRESS_V1,
GENERATOR_INDEX__CONTRACT_ADDRESS_V1, MAX_FIELD_VALUE,
}, contract_class_id::ContractClassId,
hash::{poseidon2_hash_with_separator, private_functions_root_from_siblings},
merkle_tree::membership::MembershipWitness,
traits::{Empty, FromField, ToField, Serialize, Deserialize}, utils,
};

global BN254_FR_MODULUS_DIV_2: Field =
10944121435919637611123202872628637544274182200208017171849102093287904247808;

// We do below because `use crate::point::Point;` does not work
use dep::std::embedded_curve_ops::EmbeddedCurvePoint as Point;

Expand Down Expand Up @@ -68,20 +65,20 @@ impl Deserialize<AZTEC_ADDRESS_LENGTH> for AztecAddress {

impl ToPoint for AztecAddress {
fn to_point(self) -> Point {
// Calculate y^2 = x^3 - 17
let y_squared = pow(self.inner, 3) - 17;

// TODO (#8970): Failure validation
// We can see if y is square first, or we can soft fail with just sqrt(y_squared);
// If y is not square, the x-coordinate is not on the curve
// Do we throw here or can we soft continue and this is fine ? Test this with points not on curve to see what happens.
// let y_is_square = is_square(y_squared);
// assert(y_is_square);
// We compute the address point by taking our address, setting it to x, and then solving for y in the
// equation which defines our bn curve:
// y^2 = x^3 - 17; x = address
let x = self.inner;
let y_squared = pow(x, 3) - 17;

// TODO (#8970): Handle cases where we cannot recover a point from an address
let mut y = sqrt(y_squared);

// If we get a negative y coordinate, we pin it to the positive one by subtracting it from the Field modulus
if (!(y.lt(BN254_FR_MODULUS_DIV_2) | y.eq(BN254_FR_MODULUS_DIV_2))) {
y = (BN254_FR_MODULUS_DIV_2 + BN254_FR_MODULUS_DIV_2 + 1) - y;
// If we get a negative y coordinate (any y where y > MAX_FIELD_VALUE / 2), we pin it to the
// positive one (any value where y <= MAX_FIELD_VALUE / 2) by subtracting it from the Field modulus
// note: The field modulus is MAX_FIELD_VALUE + 1
if (!(y.lt(MAX_FIELD_VALUE / 2) | y.eq(MAX_FIELD_VALUE / 2))) {
y = (MAX_FIELD_VALUE + 1) - y;
}

Point { x: self.inner, y, is_infinite: false }
Expand All @@ -93,16 +90,6 @@ impl AztecAddress {
Self { inner: 0 }
}

pub fn compute_preaddress(
pub_keys_hash: PublicKeysHash,
partial_address: PartialAddress,
) -> Field {
poseidon2_hash_with_separator(
[pub_keys_hash.to_field(), partial_address.to_field()],
GENERATOR_INDEX__CONTRACT_ADDRESS_V1,
)
}

pub fn compute(public_keys: PublicKeys, partial_address: PartialAddress) -> AztecAddress {
let public_keys_hash = public_keys.hash();

Expand Down Expand Up @@ -200,20 +187,12 @@ fn compute_address_from_partial_and_pub_keys() {
);

let address = AztecAddress::compute(public_keys, partial_address);
let expected_computed_address_from_partial_and_pubkey =
0x24e4646f58b9fbe7d38e317db8d5636c423fbbdfbe119fc190fe9c64747e0c62;
assert(address.to_field() == expected_computed_address_from_partial_and_pubkey);
}

#[test]
fn compute_preaddress_from_partial_and_pub_keys_hash() {
let pub_keys_hash = PublicKeysHash::from_field(1);
let partial_address = PartialAddress::from_field(2);

let preaddress = AztecAddress::compute_preaddress(pub_keys_hash, partial_address);
let expected_computed_preaddress_from_partial_and_pubkey =
0x23ce9be3fa3c846b0f9245cc796902e731d04f086e8a42473bb29e405fc98075;
assert(preaddress == expected_computed_preaddress_from_partial_and_pubkey);
// The following value was generated by `derivation.test.ts`.
// --> Run the test with AZTEC_GENERATE_TEST_DATA=1 flag to update test data.
let expected_computed_address_from_partial_and_pubkeys =
0x24e4646f58b9fbe7d38e317db8d5636c423fbbdfbe119fc190fe9c64747e0c62;
assert(address.to_field() == expected_computed_address_from_partial_and_pubkeys);
}

#[test]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type PXE } from '@aztec/circuit-types';
import { type Fr } from '@aztec/circuits.js';
import { type Fr, computeAddressSecret, deriveMasterIncomingViewingSecretKey } from '@aztec/circuits.js';

import { type Salt } from '../account/index.js';
import { type AccountInterface } from '../account/interface.js';
Expand All @@ -25,4 +25,14 @@ export class AccountWalletWithSecretKey extends AccountWallet {
public getSecretKey() {
return this.secretKey;
}

/** Returns the address secret, the secret of the address point—the point that others use to encrypt messages to this account
* note - this ensures that the address secret always corresponds to an address point with y being positive
*/
public getAddressSecret() {
return computeAddressSecret(
this.getCompleteAddress().getPreaddress(),
deriveMasterIncomingViewingSecretKey(this.getSecretKey()),
);
}
}
2 changes: 1 addition & 1 deletion yarn-project/circuits.js/src/contract/contract_address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { type ContractInstance } from './interfaces/contract_instance.js';
* ```
* salted_initialization_hash = pedersen([salt, initialization_hash, deployer], GENERATOR__SALTED_INITIALIZATION_HASH)
* partial_address = pedersen([contract_class_id, salted_initialization_hash], GENERATOR__CONTRACT_PARTIAL_ADDRESS_V1)
* address = (poseidon2Hash([public_keys_hash, partial_address, GENERATOR__CONTRACT_ADDRESS_V1]) * G) + ivpk_m
* address = ((poseidon2Hash([public_keys_hash, partial_address, GENERATOR__CONTRACT_ADDRESS_V1]) * G) + ivpk_m).x <- the x-coordinate of the address point
* ```
* @param instance - A contract instance for which to calculate the deployment address.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`🔑 Pre address from partial matches Noir 1`] = `"0x23ce9be3fa3c846b0f9245cc796902e731d04f086e8a42473bb29e405fc98075"`;
exports[`🔑 Address matches Noir 1`] = `"0x24e4646f58b9fbe7d38e317db8d5636c423fbbdfbe119fc190fe9c64747e0c62"`;

exports[`🔑 Pre address from partial matches Noir 1`] = `"0x23ce9be3fa3c846b0f9245cc796902e731d04f086e8a42473bb29e405fc98075"`;
34 changes: 12 additions & 22 deletions yarn-project/circuits.js/src/keys/derivation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { type AztecAddress } from '@aztec/foundation/aztec-address';
import { poseidon2HashWithSeparator, sha512ToGrumpkinScalar } from '@aztec/foundation/crypto';
import { Fq, Fr, GrumpkinScalar, Point } from '@aztec/foundation/fields';

Expand Down Expand Up @@ -46,37 +46,27 @@ export function computePreaddress(publicKeysHash: Fr, partialAddress: Fr) {
}

export function computeAddress(publicKeys: PublicKeys, partialAddress: Fr) {
// Given public keys and a partial address, we can compute our address in the following steps.
// 1. preaddress = poseidon2([publicKeysHash, partialAddress], GeneratorIndex.CONTRACT_ADDRESS_V1);
// 2. addressPoint = (preaddress * G) + ivpk_m
// 3. address = addressPoint.x
const preaddress = computePreaddress(publicKeys.hash(), partialAddress);
const address = computeAddressFromPreaddressAndIvpkM(preaddress, publicKeys.masterIncomingViewingPublicKey);

return address;
}

export function computeAddressFromPreaddressAndIvpkM(preaddress: Fr, ivpkM: Point) {
const addressPoint = computeAddressPointFromPreaddressAndIvpkM(preaddress, ivpkM);

return AztecAddress.fromField(addressPoint.x);
}

export function computeAddressPointFromPreaddressAndIvpkM(preaddress: Fr, ivpkM: Point) {
// Given h, our preaddress, and our ivpk_m, we can derive our address point.
// All we need to do is:
// First, take our preaddress, and multiply it by the generator G
const preaddressPoint = derivePublicKeyFromSecretKey(new Fq(preaddress.toBigInt()));
// Then we add our ivpk_m to it. Tada !
const addressPoint = new Grumpkin().add(preaddressPoint, ivpkM);
const address = new Grumpkin().add(
derivePublicKeyFromSecretKey(new Fq(preaddress.toBigInt())),
publicKeys.masterIncomingViewingPublicKey,
);

return addressPoint;
return address.x;
}

export function computeAddressSecret(preaddress: Fr, ivsk: Fq) {
// TLDR; (h + ivsk) * G = P1
// TLDR; P1 = (h + ivsk) * G
// if P1.y is pos
// S = (h + ivsk)
// else
// S = Fq.MODULUS - (h + ivsk)
//
// Given h, our preaddress, and our ivsk, we have two different addressSecret candidates. One encodes to a point with a positive y-coordinate
// Given h (our preaddress) and our ivsk, we have two different addressSecret candidates. One encodes to a point with a positive y-coordinate
// and the other encodes to a point with a negative y-coordinate. We take the addressSecret candidate that is a simple addition of the two Scalars.
const addressSecretCandidate = ivsk.add(new Fq(preaddress.toBigInt()));
// We then multiply this secretCandidate by the generator G to create an addressPoint candidate.
Expand Down
10 changes: 1 addition & 9 deletions yarn-project/end-to-end/src/e2e_block_building.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import {
} from '@aztec/aztec.js';
import {
AZTEC_EPOCH_PROOF_CLAIM_WINDOW_IN_L2_SLOTS,
computeAddressSecret,
deriveMasterIncomingViewingSecretKey,
} from '@aztec/circuits.js';
import { times } from '@aztec/foundation/collection';
import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto';
Expand Down Expand Up @@ -303,13 +301,7 @@ describe('e2e_block_building', () => {
// compare logs
expect(rct.status).toEqual('success');
const noteValues = tx.noteEncryptedLogs.unrollLogs().map(l => {
const notePayload = L1NotePayload.decryptAsIncoming(
l,
computeAddressSecret(
thisWallet.getCompleteAddress().getPreaddress(),
deriveMasterIncomingViewingSecretKey(thisWallet.getSecretKey()),
),
);
const notePayload = L1NotePayload.decryptAsIncoming(l, thisWallet.getAddressSecret());
return notePayload?.note.items[0];
});
expect(noteValues[0]).toEqual(new Fr(10));
Expand Down
17 changes: 2 additions & 15 deletions yarn-project/end-to-end/src/e2e_event_logs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
L1EventPayload,
type PXE,
} from '@aztec/aztec.js';
import { computeAddressSecret, deriveMasterIncomingViewingSecretKey } from '@aztec/circuits.js';
import { EventSelector } from '@aztec/foundation/abi';
import { makeTuple } from '@aztec/foundation/array';
import { type Tuple } from '@aztec/foundation/serialize';
Expand Down Expand Up @@ -55,13 +54,7 @@ describe('Logs', () => {
const encryptedLogs = txEffect!.encryptedLogs.unrollLogs();
expect(encryptedLogs.length).toBe(3);

const decryptedEvent0 = L1EventPayload.decryptAsIncoming(
encryptedLogs[0],
computeAddressSecret(
wallets[0].getCompleteAddress().getPreaddress(),
deriveMasterIncomingViewingSecretKey(wallets[0].getSecretKey()),
),
)!;
const decryptedEvent0 = L1EventPayload.decryptAsIncoming(encryptedLogs[0], wallets[0].getAddressSecret())!;

expect(decryptedEvent0.contractAddress).toStrictEqual(testLogContract.address);
expect(decryptedEvent0.randomness).toStrictEqual(randomness[0]);
Expand All @@ -78,13 +71,7 @@ describe('Logs', () => {
const badEvent0 = TestLogContract.events.ExampleEvent1.decode(decryptedEvent0);
expect(badEvent0).toBe(undefined);

const decryptedEvent1 = L1EventPayload.decryptAsIncoming(
encryptedLogs[2],
computeAddressSecret(
wallets[0].getCompleteAddress().getPreaddress(),
deriveMasterIncomingViewingSecretKey(wallets[0].getSecretKey()),
),
)!;
const decryptedEvent1 = L1EventPayload.decryptAsIncoming(encryptedLogs[2], wallets[0].getAddressSecret())!;

expect(decryptedEvent1.contractAddress).toStrictEqual(testLogContract.address);
expect(decryptedEvent1.randomness).toStrictEqual(randomness[1]);
Expand Down
4 changes: 1 addition & 3 deletions yarn-project/ethereum/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
"rootDir": "src",
"tsBuildInfoFile": ".tsbuildinfo"
},
"include": [
"src"
],
"include": ["src"],
"references": [
{
"path": "../foundation"
Expand Down

0 comments on commit 9d81a35

Please sign in to comment.