Skip to content

Commit

Permalink
feat: implement inside outside polygon commitment circuit
Browse files Browse the repository at this point in the history
  • Loading branch information
iluxonchik committed Jan 7, 2024
1 parent 8284d94 commit f448042
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 65 deletions.
30 changes: 15 additions & 15 deletions contracts/src/Polygon.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,17 @@ describe('CoordinatesInPolygon', () => {

const notInRomaniaCoordinatesSourced: GeoPointProviderCircuitProof = await GeoPointProviderCircuit.fromLiteralGeoPoint(notInRomaniaCoordinates);

proofBrasovCenterCoordinatesInBrasovCenterPolygon = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofBrasovCenterCoordinatesInBrasovCenterPolygon = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
brasovCenterCoordinatesSourced,
brasovCenterPolygon
);

proofNotBrasovCenterCoordinatesInBrasovCenterPolygon = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofNotBrasovCenterCoordinatesInBrasovCenterPolygon = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
notBrasovCenterCoordinatesSourced,
brasovCenterPolygon
);

proofNotInRomaniaCoordinatesNotInBrasovCenterPolygon = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofNotInRomaniaCoordinatesNotInBrasovCenterPolygon = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
notInRomaniaCoordinatesSourced,
brasovCenterPolygon,
);
Expand Down Expand Up @@ -216,62 +216,62 @@ describe('CoordinatesInPolygon', () => {
});


proofInsideCoordinate1InInsidePolygon1 = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofInsideCoordinate1InInsidePolygon1 = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
insideCoordinate1Sourced,
insidePolygon1,
);

proofInsideCoordinate2InInsidePolygon1 = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofInsideCoordinate2InInsidePolygon1 = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
insideCoordinate2Sourced,
insidePolygon1,
);

proofInsideCoordinate3InInsidePolygon1 = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofInsideCoordinate3InInsidePolygon1 = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
insideCoordinate3Sourced,
insidePolygon1,
);

proofInsideCoordinate1InInsidePolygon2 = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofInsideCoordinate1InInsidePolygon2 = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
insideCoordinate1Sourced,
insidePolygon2,
);

proofInsideCoordinate2InInsidePolygon2 = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofInsideCoordinate2InInsidePolygon2 = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
insideCoordinate2Sourced,
insidePolygon2,
);

proofInsideCoordinate3InInsidePolygon2 = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofInsideCoordinate3InInsidePolygon2 = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
insideCoordinate3Sourced,
insidePolygon2,
);

proofInsideCoordinate1NotInOutsidePolygon1 = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofInsideCoordinate1NotInOutsidePolygon1 = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
insideCoordinate1Sourced,
outsidePolygon1,
);

proofInsideCoordinate2NotInOutsidePolygon1 = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofInsideCoordinate2NotInOutsidePolygon1 = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
insideCoordinate2Sourced,
outsidePolygon1,
);

proofInsideCoordinate3NotInOutsidePolygon1 = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofInsideCoordinate3NotInOutsidePolygon1 = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
insideCoordinate3Sourced,
outsidePolygon1,
);

proofInsideCoordinate1NotInOutsidePolygon2 = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofInsideCoordinate1NotInOutsidePolygon2 = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
insideCoordinate1Sourced,
outsidePolygon2,
);

proofInsideCoordinate2NotInOutsidePolygon2 = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofInsideCoordinate2NotInOutsidePolygon2 = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
insideCoordinate2Sourced,
outsidePolygon2,
);

proofInsideCoordinate3NotInOutsidePolygon2 = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(
proofInsideCoordinate3NotInOutsidePolygon2 = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(
insideCoordinate3Sourced,
outsidePolygon2,
);
Expand Down
6 changes: 2 additions & 4 deletions contracts/src/api/proofs/ZKLocusProof.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { Field, JsonProof, ZkProgram} from "o1js";
import { Bool } from "o1js/dist/node/lib/bool";
import { Bool, Field, JsonProof, ZkProgram, Cache} from "o1js";
import type { ZKPublicKey } from "../models/ZKPublicKey";
import type { ZKThreePointPolygon } from "../models/ZKThreePointPolygon";
import type { ZKGeoPoint } from "../models/ZKGeoPoint";
import { GeoPointInPolygonCommitment } from "../../model/private/Commitment";
import { GeoPoint, ThreePointPolygon } from "../../model/Geography";
import { ZKProgramCompileResult} from "./Types";
import { OracleAuthenticatedGeoPointCommitment } from "../../model/private/Oracle";
import { Cache } from "o1js/dist/node/lib/proof-system/cache";
import { ZKProgramCircuit } from "./Types";
import { ICompilableZKLocusProof } from "./ICompilableZKLocusProof";
import { ICompilableZKLocusProof } from "./Interfaces";



Expand Down
3 changes: 1 addition & 2 deletions contracts/src/api/provers/ZKGeoPointProver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type { ZKThreePointPolygon } from "../models/ZKThreePointPolygon";
import type { ZKGeoPoint } from "../models/ZKGeoPoint";
import { IZKProver } from "./Interfaces";
import { GeoPointInPolygonCircuit, GeoPointInPolygonCircuitProof, GeoPointProviderCircuit, GeoPointProviderCircuitProof } from "../../zkprogram/private/Geography";
import { ZKLocusProof } from "../proofs/ZKLocusProof";
import { ZKGeoPointInPolygonProof } from "../proofs/ZKGeoPointInPolygonProof";
import { PublicKey, Signature } from "o1js";
import { OracleGeoPointProviderCircuitProof, OracleGeoPointProviderCircuit } from "../../zkprogram/private/Oracle";
Expand Down Expand Up @@ -63,7 +62,7 @@ export default function <T extends ZKGeoPointConstructor>(Base: T) {
*/
inPolygon: async (polygon: ZKThreePointPolygon): Promise<ZKGeoPointInPolygonProof> => {
const geoPointProof: GeoPointProviderCircuitProof = await GeoPointProviderCircuit.fromLiteralGeoPoint(this.toZKValue());
const geoPointInPolygonProof: GeoPointInPolygonCircuitProof = await GeoPointInPolygonCircuit.proveProvidedGeoPointIn3PointPolygon(geoPointProof, polygon.toZKValue());
const geoPointInPolygonProof: GeoPointInPolygonCircuitProof = await GeoPointInPolygonCircuit.proveGeoPointIn3PointPolygon(geoPointProof, polygon.toZKValue());
return new ZKGeoPointInPolygonProof(this, polygon, geoPointInPolygonProof);
},
/**
Expand Down
28 changes: 15 additions & 13 deletions contracts/src/logic/Methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { isPointOnEdgeProvable } from './Geography';

import { GeoPoint, ThreePointPolygon } from '../model/Geography';
import { Int64Prover } from "../math/Provers.js";
import { GeoPointPolygonInclusionExclusionProof, GeoPointInPolygonCommitment, GeoPointWithTimeStampIntervalInPolygonCommitment } from "../model/private/Commitment";
import { GeoPointInOutPolygonCommitment, GeoPointInPolygonCommitment, GeoPointWithTimeStampIntervalInPolygonCommitment } from "../model/private/Commitment";
import { TimeStampInterval } from "../model/Time";
import { GeoPointInPolygonCircuitProof, GeoPointProviderCircuitProof, TimeStampIntervalProviderCircuitProof } from "../zkprogram/private/Geography";
import { OracleGeoPointProviderCircuitProof } from "../zkprogram/private/Oracle";
Expand Down Expand Up @@ -195,11 +195,13 @@ export function AND(
proof1: SelfProof<Empty, GeoPointInPolygonCommitment>,
proof2: SelfProof<Empty, GeoPointInPolygonCommitment>
): GeoPointInPolygonCommitment {
// IMPORTANT: this has an issue. If I give proof1, which asserts that the user is in Spain, and proof2 that
// IMPORTANT: A caveat of this AND. If you give proof1, which asserts that the user is in Spain, and proof2 that
// asserts that the user is not in Romania, then the resulting proof from .AND will say that the user is
// neither in Spain, nor Romania. This is because the AND operation is applied to the `isInPolygon` field
// of the two proofs. This is not the desired behaviour. The desired behaviour is to have a proof that
// asserts that the user is in Spain AND is not in Romania.
// not in Spain AND Romania. This is because the AND operation is applied to the `isInPolygon` field
// of the two proofs. This is coherent with the "isPointInPolygon" logic, as the resulting proof attests
// whether the point IS IN polygon. As such, the AND logic is applied to whether the point IS IN polygon 1 AND IN polygon 2.

// A separate piece of functionality is is to have a proof that asserts that the user is in Spain AND is not in Romania.
// For correctness, this method/proof should opearate ensuring that the values of `isInPolygon` is the same
// in both proofs: either both are true, or both are false. If they are different, then the proof should
// fail. This way the proof will attest to either the user being inside a set of polygons, or outside of that set.
Expand Down Expand Up @@ -288,14 +290,14 @@ export function OR(


} export function combine(
proof1: SelfProof<Empty, GeoPointPolygonInclusionExclusionProof>,
proof2: SelfProof<Empty, GeoPointPolygonInclusionExclusionProof>
): GeoPointPolygonInclusionExclusionProof {
proof1: SelfProof<Empty, GeoPointInOutPolygonCommitment>,
proof2: SelfProof<Empty, GeoPointInOutPolygonCommitment>
): GeoPointInOutPolygonCommitment {
proof1.verify();
proof2.verify();

const proof1PublicOutput: GeoPointPolygonInclusionExclusionProof = proof1.publicOutput;
const proof2PublicOutput: GeoPointPolygonInclusionExclusionProof = proof2.publicOutput;
const proof1PublicOutput: GeoPointInOutPolygonCommitment = proof1.publicOutput;
const proof2PublicOutput: GeoPointInOutPolygonCommitment = proof2.publicOutput;

// ensure that the proof is for the same coordinates
proof1.publicOutput.coordinatesCommitment.assertEquals(
Expand Down Expand Up @@ -411,15 +413,15 @@ export function OR(
newOutsideCommitment
);

return new GeoPointPolygonInclusionExclusionProof({
return new GeoPointInOutPolygonCommitment({
insidePolygonCommitment: newInsideCommitment,
outsidePolygonCommitment: newOutsideCommitment,
coordinatesCommitment: proof1PublicOutput.coordinatesCommitment,
});
}
export function fromCoordinatesInPolygonProof(
proof: SelfProof<Empty, GeoPointInPolygonCommitment>
): GeoPointPolygonInclusionExclusionProof {
): GeoPointInOutPolygonCommitment {
proof.verify();

const coodinatesInPolygonProof: GeoPointInPolygonCommitment = proof.publicOutput;
Expand All @@ -434,7 +436,7 @@ export function fromCoordinatesInPolygonProof(
coodinatesInPolygonProof.polygonCommitment
);

return new GeoPointPolygonInclusionExclusionProof({
return new GeoPointInOutPolygonCommitment({
insidePolygonCommitment: insideCommitment,
outsidePolygonCommitment: outsideCommitment,
coordinatesCommitment: coodinatesInPolygonProof.geoPointCommitment,
Expand Down
84 changes: 84 additions & 0 deletions contracts/src/logic/private/GeoPointInOrOutOfPolygon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { Empty, Field, Poseidon, Provable, SelfProof } from "o1js";
import { GeoPointInOutPolygonCommitment, GeoPointInPolygonCommitment } from "../../model/private/Commitment";
import { GeoPointInPolygonCircuitProof } from "../../zkprogram/private/Geography";


/**
* Creates a GeoPointInOutPolygonCommitment object based on the provided inside and outside proofs.
*
* @param insideProof - The proof of the GeoPoint being inside a polygon.
* @param outsideProof - The proof of the GeoPoint being outside a polygon.
* @returns A GeoPointInOutPolygonCommitment object.
*/
export function fromPointInPolygonProofs(
insideProof: GeoPointInPolygonCircuitProof,
outsideProof: GeoPointInPolygonCircuitProof,
): GeoPointInOutPolygonCommitment {
insideProof.verify();
const insideProofCommitment: GeoPointInPolygonCommitment = insideProof.publicOutput;
insideProofCommitment.isInPolygon.assertTrue("`insideProof` is not a proof of a GeoPoint being inside a polygon, but rather outside.");

outsideProof.verify();
const outsideProofCommitment: GeoPointInPolygonCommitment = outsideProof.publicOutput;
outsideProofCommitment.isInPolygon.assertFalse("`outsideProof` is not a proof of a GeoPoint being outside a polygon, but rather inside.");

const insideGeoPointCommitment: Field = insideProofCommitment.geoPointCommitment;
const outsideGeoPointCommitment: Field = outsideProofCommitment.geoPointCommitment;
insideGeoPointCommitment.assertEquals(outsideGeoPointCommitment, "`insideProof` and `outsideProof` are not proofs of the same GeoPoint being inside and outside a polygon, respectively.")

const insidePolygonCommitment: Field = insideProofCommitment.polygonCommitment;
const outsidePolygonCommitment: Field = outsideProofCommitment.polygonCommitment;


return new GeoPointInOutPolygonCommitment({
insidePolygonCommitment: insidePolygonCommitment,
outsidePolygonCommitment: outsidePolygonCommitment,
coordinatesCommitment: insideGeoPointCommitment,
});
}


/**
* Extends a self-proof and a point-in-polygon proof to create a commitment to a GeoPoint inside or outside a polygon.
* If the `pointInPolygonProof` is a proof of the GeoPoint being inside the polygon, then the `selfProof`'s public output
* `insidePolygonCommitment` will be extended with the `pointInPolygonProof`'s public output `polygonCommitment`.
* If the `pointInPolygonProof` is a proof of the GeoPoint being outside the polygon, then the `selfProof`'s public output
* `outsidePolygonCommitment` will be extended with the `pointInPolygonProof`'s public output `polygonCommitment`.
*
* @param selfProof The self-proof of the geo point being inside or outside the polygon.
* @param pointInPolygonProof The point-in-polygon proof of the geo point being inside the polygon.
* @returns The commitment to the geo point inside or outside the polygon.
*/
export function extendWithPointInPolygonProof(
selfProof: SelfProof<Empty, GeoPointInOutPolygonCommitment>,
pointInPolygonProof: GeoPointInPolygonCircuitProof,
): GeoPointInOutPolygonCommitment {
selfProof.verify();
pointInPolygonProof.verify();

const selfProofCommitment: GeoPointInOutPolygonCommitment = selfProof.publicOutput;
const pointInPolygonProofCommitment: GeoPointInPolygonCommitment = pointInPolygonProof.publicOutput;

selfProofCommitment.coordinatesCommitment.assertEquals(pointInPolygonProofCommitment.geoPointCommitment, "`selfProof` and `pointInPolygonProof` are not proofs of the same GeoPoint.");

const extendedCommitmentInside: GeoPointInOutPolygonCommitment = new GeoPointInOutPolygonCommitment({
insidePolygonCommitment: Poseidon.hash([pointInPolygonProofCommitment.polygonCommitment, pointInPolygonProofCommitment.polygonCommitment]),
outsidePolygonCommitment: selfProofCommitment.outsidePolygonCommitment,
coordinatesCommitment: pointInPolygonProofCommitment.geoPointCommitment,
});

const extendedCommitmentOutside: GeoPointInOutPolygonCommitment = new GeoPointInOutPolygonCommitment({
insidePolygonCommitment: selfProofCommitment.insidePolygonCommitment,
outsidePolygonCommitment: Poseidon.hash([pointInPolygonProofCommitment.polygonCommitment, pointInPolygonProofCommitment.polygonCommitment]),
coordinatesCommitment: pointInPolygonProofCommitment.geoPointCommitment,
});

const extendedCommitment: GeoPointInOutPolygonCommitment = Provable.if(
pointInPolygonProofCommitment.isInPolygon,
GeoPointInOutPolygonCommitment,
extendedCommitmentInside,
extendedCommitmentOutside,
);

return extendedCommitment;
}
13 changes: 8 additions & 5 deletions contracts/src/model/private/Commitment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@ import { TimeStampInterval } from "../Time.js";

export class GeoPointInPolygonCommitment extends Struct({
polygonCommitment: Field,
// TODO: consider including outSidePolygonCommitment proofs, in order to inlcude the "inner" and "outer" polygon definitions of GeoJSON
//outsidePolygonCommitment: Field,
geoPointCommitment: Field,
isInPolygon: Bool,
}) {
toString(): string {
return `Polygon Commitment: ${this.polygonCommitment.toString()}\nCoordinates Commitment: ${this.geoPointCommitment.toString()}\nIs In Polygon: ${this.isInPolygon.toString()}`;
}
}
};


;
export class GeoPointPolygonInclusionExclusionProof extends Struct({
/**
* Two-dimensional private geolocation commitment. It repreesents a commitment to a GeoPoint being outside a list of polygons and inside a list of polygons.
*
* IMPORTANT: This commitment expression should only be utilized in the case of
*/
export class GeoPointInOutPolygonCommitment extends Struct({
insidePolygonCommitment: Field,
outsidePolygonCommitment: Field,
coordinatesCommitment: Field,
Expand Down
Loading

0 comments on commit f448042

Please sign in to comment.