Skip to content

Commit

Permalink
refactor: organize API in modules
Browse files Browse the repository at this point in the history
  • Loading branch information
iluxonchik committed Dec 10, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 0b381d9 commit 102e72b
Showing 6 changed files with 375 additions and 325 deletions.
74 changes: 74 additions & 0 deletions contracts/src/api/Adopters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@

/*
Represents interface that converts a type into a zkLocus value.
This is used to convert TypeScript types into zkLocus-supported types.
Any type that implements ZKLocusAdopter becomes a type that "adopts" to zkLocus's internal types. Its ultimate purpose is to be used
as a class decorator. Any class that gets decorated ZKLocusAdopter will be augmented with the additional properties and methods of the
ZKLocusAdopter interface. As such, any class that gets decorated with with a function that returns a class that implements ZKLocusAdopter
becomes an "adopter" of zkLocus, as it provides a way to convert the types into zkLocus types.
The values are converted in the following order:
1. rawValue: The value that the user provided. This value can be either an API type or a TypeScript native type. It gets converted into a normalized value.
2. normalizedValue: The normalized value of the type. This value is the normalized raw value. This value is an
API type, and should not be a TypeScript native type. It gets converted into a zkLocus value.
3. toZKValue: The zkLocus value of the type. This is the value that will be used in zkLocus. This value must be of type
Raw, normalized and ZK are the different states of the same value. The value begins as a raw value, and then it gets normalized, and then it gets converted into a zkLocus value.
*/

import { Int64 } from "o1js";
import { InputNumber } from "./Types";
import ZKGeoPointToGeoPointAdopter from "./internal/adopters/ZKGeoPointToGeoPointAdopter";

export { ZKGeoPointToGeoPointAdopter };

export interface ZKLocusAdopter<R, N, Z> {
/*
Returns the raw value of the type. This is the value that the user provided. This value can be either
an API type or a TypeScript native type.
*/
rawValue(): R;

/*
Returns the normalized value of the type. This value is the normalized raw value. This value is an
API type, and should not be a TypeScript native type.
A normalized value is easily convertible into a zkLocus value.
*/
normalizedValue(): N;

/*
Returns the zkLocus value of the type. This is the value that will be used in zkLocus. This value must be of type
the zkLocus implentation operats upon. For example, if the zkLocus implementation operates on Int64, then this
value must be of type Int64.
In practice, these value types are directly compatile the types used inside the recursive zkSNARKs circuits of zkLocus.
*/
toZKValue(): Z;
}

export function ZKNumberToInt64Adopter<T extends new (...args: any[]) => { raw: InputNumber; normalized: number; }>(Base: T) {
return class extends Base implements ZKLocusAdopter<InputNumber, number, Int64> {

/*
Returns the raw value of the number. This is the value that the user provided.
*/
rawValue(): InputNumber {
return this.raw;
}
/*
Returns the normalized value of the number. This is the value that will be used in the zkSNARK.
*/
normalizedValue(): number {
return this.normalized;
}

toZKValue(): Int64 {
// Assuming Int64 is a valid type or class in the provided zkLocus code
return Int64.from(this.normalizedValue());
}
};
}

184 changes: 184 additions & 0 deletions contracts/src/api/Models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import { Int64 } from "o1js";
import { ZKGeoPointToGeoPointAdopter, ZKLocusAdopter, ZKNumberToInt64Adopter } from "./Adopters";
import { RawCoordinates, InputNumber } from "./Types";
import { ZKLocusProof } from "./api";

import { GeoPoint, ThreePointPolygon } from "../model/Geography";
import ZKThreePointPolygonToThreePointPolygonAdopter from "./internal/adopters/ZKThreePointPolygonToThreePointPolygonAdopter";


/*
Represents a number that will be converted to the Fields of a zkSNARK in zkLocus.
*/

@ZKNumberToInt64Adopter
export class ZKNumber {
protected _raw_value: InputNumber;
protected _normalized_value: number;
protected _num_decimals: number;

constructor(value: InputNumber) {
this._raw_value = value;
this._normalized_value = Math.round(Number(value));
this._num_decimals = this._count_num_decimals();
}

get raw(): InputNumber {
return this._raw_value;
}

get normalized(): number {
return this._normalized_value;
}

/*
Returns the number of decimals in the number.
*/
get num_decimals(): number {
return this._num_decimals;
}

protected _count_num_decimals(): number {
const decimalPart = this._normalized_value.toString().split('.')[1];
return decimalPart ? decimalPart.length : 0;
}
}
// Declaration merging to augment the ZKNumber class with the additional properties and methods of the ZKInterface
export interface ZKNumber extends ZKLocusAdopter<InputNumber, number, Int64> { }

/*
Represents a coordinate that will be converted to the Fields of a zkSNARK in zkLocus.
It imposes the maximum and the minimum possible values for a coordinate, wether it's latitude or longitude, and
ensures that the precision limit is not exceeded.
*/

export class ZKCoordinate extends ZKNumber {
constructor(value: InputNumber) {
super(value);
const valueAsInteger = Math.abs(Number(value));
if (valueAsInteger > 180 || this.num_decimals > 7) {
throw new Error("Invalid coordinate value");
}
}

/*
Returns the factor of the coordinate. This is the factor that the coordinate will be multiplied by
to get the zkLocus value. The factor is a power of 10, and it's equal to 10 ^ num_decimals.
For numbers without decimals (i.e. integers), the factor is 1.
*/
get factor(): number {
return Math.max(1, 10 ** this.num_decimals);
}
}
/*
Represents a latitude that will be converted to the Fields of a zkSNARK in zkLocus.
*/

export class ZKLatitude extends ZKCoordinate {
constructor(value: InputNumber) {
super(value);
const valueAsInteger = Math.abs(Number(value));
if (valueAsInteger > 90) {
throw new Error("Invalid latitude value");
}
}
}
/*
Represents a longitude that will be converted to the Fields of a zkSNARK in zkLocus.
*/

export class ZKLongitude extends ZKCoordinate {

constructor(value: InputNumber) {
super(value);
const valueAsInteger: number = Math.abs(Number(value));
if (valueAsInteger > 180) {
throw new Error("Invalid longitude value");
}
}
}
/*
Represents a geographical point in TypeScript that will be converted into a zkLocus geographical point.
A zkLocus geographical point is one that can be used in a zero-knowledge circuit. zkLocus uses O1JS to
implement zero-knowledge circuits, so a zkLocus geographical point is one that is represented in a
valid set of O1JS structures.
All of the zero-knowledge functionality is also avaialbe on this class, namely:
1. Proving wether a point is in polygon
2. Proving the exact location.
*/

@ZKGeoPointToGeoPointAdopter
export class ZKGeoPoint {
protected _latitude: ZKLatitude;
protected _longitude: ZKLongitude;
protected _rawValue: { latitude: InputNumber | ZKLatitude; longitude: InputNumber | ZKLongitude; };

constructor(latitude: InputNumber | ZKLatitude, longitude: InputNumber | ZKLongitude) {
this._rawValue = {
latitude: latitude,
longitude: longitude,
};

this._latitude = latitude instanceof ZKLatitude ? latitude : new ZKLatitude(latitude);
this._longitude = longitude instanceof ZKLongitude ? longitude : new ZKLongitude(longitude);
}

get latitude(): ZKLatitude {
return this._latitude;
}

get longitude(): ZKLongitude {
return this._longitude;
}

get asRawValue(): { latitude: InputNumber | ZKLatitude; longitude: InputNumber | ZKLongitude; } {
return this._rawValue;
}

async proveInPolygon(polygon: ZKThreePointPolygon): Promise<ZKLocusProof> {
// TODO: Implement
return new ZKLocusProof( /* parameters */);
}
}
// Declaration merging to augment the ZKGeoPoint class with the additional properties and methods of the ZKInterface

export interface ZKGeoPoint extends ZKLocusAdopter<{ latitude: InputNumber | ZKLatitude; longitude: InputNumber | ZKLongitude; }, { latitude: ZKLatitude; longitude: ZKLongitude; factor: ZKNumber; }, GeoPoint> { }
/*
Interface for the ThreePointPolygon zkLocus class. It represents a three point polygon, also refered to as a "geogrpahical area".
*/



@ZKThreePointPolygonToThreePointPolygonAdopter
export class ZKThreePointPolygon {
private _vertices: [ZKGeoPoint, ZKGeoPoint, ZKGeoPoint];

get vertices(): [ZKGeoPoint, ZKGeoPoint, ZKGeoPoint] {
return this._vertices;
}

constructor(vertex1: ZKGeoPoint | RawCoordinates, vertex2: ZKGeoPoint | RawCoordinates, vertex3: ZKGeoPoint | RawCoordinates) {
this._vertices = [
vertex1 instanceof ZKGeoPoint ? vertex1 : new ZKGeoPoint(new ZKLatitude(vertex1.latitude), new ZKLongitude(vertex1.longitude)),
vertex2 instanceof ZKGeoPoint ? vertex2 : new ZKGeoPoint(new ZKLatitude(vertex2.latitude), new ZKLongitude(vertex2.longitude)),
vertex3 instanceof ZKGeoPoint ? vertex3 : new ZKGeoPoint(new ZKLatitude(vertex3.latitude), new ZKLongitude(vertex3.longitude))
];
this._ensure_same_factor_in_vertices();
}

protected _ensure_same_factor_in_vertices(): void {
const first_factor: number = this._vertices[0].latitude.num_decimals;
for (let i = 1; i < this._vertices.length; i++) {
if (this._vertices[i].latitude.num_decimals !== first_factor) {
throw new Error("Invalid polygon vertices");
}
}
}

}

export interface ZKThreePointPolygon extends ZKLocusAdopter<[ZKGeoPoint, ZKGeoPoint, ZKGeoPoint], [GeoPoint, GeoPoint, GeoPoint], ThreePointPolygon> { }
24 changes: 24 additions & 0 deletions contracts/src/api/Types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

/*
This contains the API for zkLocus. The API is designed to abstract away the underlying zero-knowledge circutiry logic, and focus
on providing a clear, concise and intuitive API for the end user. The API is designed adehering to the vision of zkLocus of allowing
for the sharing of optionally private geolocation data, that is extendable, customizable, and interoperable across the varioius
computational environments, such as blockchain (on-chain), off-chain, mobile, web and IoT.
The API's design levarages the recursive zkSNARKs architecture o zkLocus to its fullest extent. As such, the proofs are
naturally recursive and combinable with one another, just like in the low-level zkLocus API.
This API is designed specifically for TypeScript, and it's inspired by APIs in the Python ecosystem such as BeautifulSoup, where powerful
and complex functionality is abstracted away from the user, while exposing a clear and concise interface to the end user.
*/


// Utility Types
export type InputNumber = number | string; // Represents the number type

// Named Tuple Equivalent in TypeScript
export interface RawCoordinates {
latitude: InputNumber;
longitude: InputNumber;
}

Loading

0 comments on commit 102e72b

Please sign in to comment.