Privacy preserving location sharing DID method to enable associating wallet address with POIs/locations without sharing actual location information, allowing others to establish if these registered POIs are in proximity of their locations with the use of Homomorphic Encryption.
Location sharing and applications requiring geofencing and handling events related to wallets proximity is very limited in distributed ledgers because of the nature of DLT and the fact that all data is available and public on chain. However, the demand is clear for such functionalities to enable users to associate locations and points of interest POIs to their wallets but without sacrificing their privacy and allowing the location information to be accessible to any one. To resolve this, the adopted approach by this method relies on the use of homomorphic encryptions. Homomorphic encryptions allow an entity to share sensitive information in encrypted format with another party that can perform certain operations on the encrypted and return it to the first party that upon decryption can see the exact result for the original information. In location-based applications, most of the use cases revolve around entities being able to share their locations with each other to perform calculations related to proximity and geofencing. The use of homomorphic encryption is applied for geofencing and proximity calculations, where few protocols exist that allow one entity to share its location with another entity that can perform some calculations and with data exchange with the first entity can both identify if they are in proximity of each other without exposing the actual location information. For this purpose, loc-did provides a decentralized method based on the concept of DID to enable users to associate their wallet addresses with different POIs/locations without sharing the actual location information, yet allowing other parties based on some agreement after exchange of messages to establish if these registered POIs are in proximity of their locations or their own POIs. The Location DID method allows any Ethereum key pair account to create an identity and associate with that identity different geo locations / points of interest, either physical or virtual, in a privacy preserving way. For handling all CRUD operations of the DID Document, the loc-did registry is represented by a smart contract that is deployed on polygon testnet and goerli. Through this approach users can define POIs and locations that either they are present at or of interest to allow others to discover them or their interests without letting others know the exact location. This can help in different use cases, for example allowing wallets to initiate a chat only if they are in proximity of each other, allow push notifications to be sent to users based on their POIs and their preferences of receiving notifications only within a certain radius of that POI. Based on confirming user's wallet proximity a payment can be either performed or neglected and also validating token gating can be tied to wallets proximity to ensure redemption is based on actual presence of the wallet owner.
The project is build as a DID method that has derived most of the smart contract registry part and also the did resolver from W3C specifications and the universal DID resolver in addition to the use of open source Polygon DID method to build the code base for this project (https://wiki.polygon.technology/docs/develop/did-implementation/getting-started/).
The project is aimed to complement many messaging and communication protocols that are allowing Web3 dapps to use methods such as push notification and wallet chat and those protocols such as XMTP has inspired this project in great way. The project is proposed as an approach to add a new feature to the XMTP protocol to allow users when creating context to specify a certain geofencing area in which they can receive chatting messages or receive notifications. Currently, XMTP has the feature of specifying certain option for listing conversations such as dates and pagination, with privacy preserving location sharing approach the XMTP protocol can utilize this to enable geofencing capability and allow users to limit receiving messages from others unless within the boundaries of certain POIs
The privacy preserving location DID (did-loc) method specification is complaint with the DID requirements (https://www.w3.org/TR/did-core/#ref-for-dfn-did-documents-3) specified by W3C Credentials Community Group.
The main component of the project includes The DID method specification The DID method registry smart contract built in solidity and deployed on both Mumbai and Goerli The DID method resolver which is an npm package to allow users to query DID documents and resolve them to obtain the required POI/Location encrypted parameters.
The method utilizes homomorphic encryption to allow users to share their locations coordinates in encrypted format while allowing others to perform calculations on these values and deduct if users are in proximity or not. There are few homomorphic encryption schemes, in this project we used only Paillier cryptosystem (https://link.springer.com/content/pdf/10.1007/3-540-48910-X_16.pdf). Though the DID method specification defined how to be able to specify the encryption scheme that can be used.
To go in details of how this works, the main motivation behind this method is to ensure capability of sharing wallet related location information but while still maintaining wallet holder privacy. To ensure that, Homomorphic Encryption techniques are used to encrypt the location information store it as POIs in public ledger and enable communication between two entities to verify locations and prove proximity or a POI being in a geofenced area. One of the suggested approach for the homomorphic encryption and operations is based on the Paillier cryptosystem. Any POI is represented as a 4-tuple made of the encrypted value of calculating the user location coordinates (x, y) as in { "xyFactor" : "Enc(x^2 + y^2)", "xFactor" : "Enc(-2x)", "yFactor" : "Enc(-2y)", "radius" : "r" } where the encryption is made by the DID controller Homomorphoic public key specified in the service section.
For any interested party in a wallet POIs and its location and proximity, an entity can first resolve the DID doc of the wallet address which will provide the DID doc with a list of services endpoints. By filtering for only service endpoints of type PointOfInterest, the inqurying entity can find a list of POIs and the endpoints to those POIs which each will resolve to a POI JSON object that includes the different homomorphic encrypted values of that POI coordinates. As the entity obtains the POI object, the following calculations will need to be performed
First the entity will compare the radius value r to its intention, if the radius value is too large or too small. For example, an entity that want to check certain wallet proximity in a conference won't be interested in POI that has r set to 100's of meters or more. Also, an entity that want to send a geofenced advertisement to a wallet won't be interested in a POI with a radius value of few meters. The inquiring the entity will calculate using the controller public key the following encrypted values: Enc(u^2 + v^2), where (u , v) is the center of the inquiring entity circle of geofenced area for example. The inquiring entity also need to calculate (Enc(-2x))^u and (Enc(-2y))^v. The inquiring entity finally, calculates the distance in encrypted format by utilizing Homomorphic encryption capability to perform addition and multiply operations
Enc(d) = ( Enc(x^2 + y^2) * Enc(u^2 + v^2) ) * ( (Enc(-2x))^u * (Enc(-2y))^v )
this will represent the distance d encrypted using the controller homomorphic scheme public key.
The inquiring entity communicates the last value to the wallet of the controller and then the controller wallet using the private key can decrypt and find the value d. If d is less than r, then the associated action is performed, e.g., send a location-based notification to the 2nd party wallet or start a wallet to wallet chat.
As a security and privacy concern, it is worth mentioning that even though the did-loc method was built around the concept of privacy preserving, yet it relies on the concepts of Public key cryptography, wallet address pseudonymous and homomorphic encryption to deliver this. Users should be aware that all DIDs documents created are available publicly on-chain and the distributed storage system IPFS. All records even of deleted/revoked DIDs can still be accessible. The privacy in the design is mainly for the location information, which is ensured based on the robustness of the homomorphic encryption scheme used. Also, it is worth notifying any entities using this method that publishing multiple location information with wrong selection of parameters, in specific the radius can give the adversary means to correlate information and be able to deduct some information even without breaking the encryption scheme.
As an example this code shows how two users in Decentraland can share POIs and then perform the calculations to establish if they are in proximity or not
const paillierBigint = require('paillier-bigint')
const { getResolver } = require('../did-loc-resolver/lib/index'); const { Resolver } = require('did-resolver')
// First entity has POI/Location in Decentrland at Decentral Park (-56,76) // const x = -56n // const y = 76n // const poi = { // xyFactor : "24842458863964170883616544200100307152366584071824570547518386773587875268761603764131522720853412199352860825746458179453593104118549053127677769629514755666968481186400829104015188130334753914955152055659754768151501939226996455093751224708390516318577324106523874534171680755493038298542553604201402123815958056694930899608870927966615893391363514460085437289465001318858370276732185119612761930056016696406072448504183847104364189810245666693821464302962980963856212474358866430041358116305938321716423580659926033270820695592713871330664385612523913217521192913682298030525046504515455582186572310194027194871188", // xFactor : "1815021957738640719005070963961211758605854259112706718715000171834473684502212052691252498547745201834476481200145819025581896891952954361197465656109883689881102599852884558601928400691420647771992950642281479983891625886272719952803309310224422319791436871814727026553692831551111705962601215212630457911720736015081250333756650536855910819610781212859637411241361050706229312693558895487683901991471072418237681367949887017789463608714795252012937554376167122978598846437343598369988221678557140121977392812960158653917990815995226143238300917960909942116415459367009932496455302965243453348800938059379407174743", // yFactor : "13144848402877802353591118416343541536029001079062149502453668050301861805069009637439257864268140453626965491504497583054724515530483347765350687718998988258837713166622231405744553136295114482447796581220124777346461325864080859484655266951254518863557093212016178934572530563842951820422536554846674458010034276164835893304483540748113294778255101707011867817298828077250773870764133709476982928308253520136341696531441776773793151015895082387407699088802885748162739039292817449528928242473643426648821980761623343857597944923879807087761743353386389395943733967801291459722385126859795946247610494106173172947962", // radius : "100" // }
async function didLocProximityTest () {
// Entity 2 is interested in connecting with entity 1 with DID Document identitfier 'did:loc:mumbai:0x754e49da4978bd9FF2e9Bfddd9399898FbB3dEc3'
// Second entity has a Location in Decentrland at EggHeadz HQ (14,88) const u = 14n const v = 88n // For example here we assume entity 2 is interested in establishing connection with any entity within a radius of 150 const acceptedDistance = 50;
// First retrieve the did doc const didResolver = new Resolver(getResolver({infuraProjectId: '4458cf4d1689497b9a38b1d6bbf05e78'})) const response = await didResolver.resolve('did:loc:mumbai:0x754e49da4978bd9FF2e9Bfddd9399898FbB3dEc3'); const poi = response.didDocument.service[0].serviceEndpoint;
console.log('Entity1 POI') console.log(poi)
// Entity 2 check the preference of entity 1 based on radius value if(poi.radius > acceptedDistance) { console.log('Entity is prefered distance does not match with local prefernece'); process.exit(); }
// Entity 2 extracts the public key of entity 1 from DID Document const n = 158654047794616470028275573187229388767694760694501892194878336468883820342741938813732465084914472764624630155203117463873950269835185172644598969819860796202415887047554163824426722407871918447977694719708904914441704743724349046433912676303810187283038671045821628273617609998106721239529080748942840641787n; const g = 24405139526609670466415836975899440191622555196370108181082375703175883755003832374662043241764834915745824859575867480583739307191715069717424110312798818501027348955909680676073769255220584393889326467675623301810148213001821482625987078305144379858429545420023932338475400045036693716705774054180582913631924050026454705214674092811482177512516598783301912130319548200720838041193692002906201646727052873455602716408067406065453916695576247132667047064093522694181268427762356911758969500915632128505171965226990726230412487526462864919525931965096294939363745991180494059857100777326337773126317183787433652068575n; const publicKey = new paillierBigint.PublicKey(n, g);
// Entity2 using entity 1 public key perform encryption of coordinates of second entity coordinates // then multiple the result with POI encrypted factors retrieved from the DID Document const uvFactor = publicKey.encrypt(u2n+v2n); const xyuvFactor = publicKey.addition(BigInt(poi.xFactor)**u, BigInt(poi.yFactor)**v);
// The result will be the distance squared const encDistance = publicKey.addition(BigInt(poi.xyFactor) , uvFactor , xyuvFactor); console.log('Encrypted Distance Squared: ',encDistance)
// Distance squared sent to Entity 1 that will perform decryption and find the distance between both entities and decide on accept or reject const lambda = 79327023897308235014137786593614694383847380347250946097439168234441910171370969406866232542457236382312315077601558731936975134917592586322299484909930385287432486547748727512846790161611413116411260052376021723385597411675564345787633079776985135051033641473909637567197438903209495047755250503941090316168n; const mu = 35637870372922708278901506676518969646190341327623990274959060810868272593670180920828298986016842640165165914037216983909644138893697226770910856670890468070037308450823582886034243226972009169934694784990505288116086676719975137821320756099051161474323953289796817717757727620235896164895555091227498059291n; const privateKey = new paillierBigint.PrivateKey(lambda, mu, publicKey) const dSquared = privateKey.decrypt(encDistance); const d = Math.sqrt(dSquared.toString(10)); console.log('Distance: ',d.toFixed(0))
}