Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update ODIS SDK to accept any type of identifier #9985

Merged
merged 36 commits into from
Dec 8, 2022
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7d0a5b9
wip
isabellewei Oct 27, 2022
63ee2ae
general identifier odis sdk
isabellewei Oct 28, 2022
1a35832
update tests
isabellewei Oct 28, 2022
e9f1eb8
Merge branch 'master' of github.com:celo-org/celo-monorepo into isabe…
isabellewei Oct 28, 2022
a4fde40
add fn back in for backwards compatability
isabellewei Oct 29, 2022
0e9e119
no salt only pepper
isabellewei Oct 29, 2022
a9e2663
fix tests
isabellewei Oct 31, 2022
f13bc68
rename identifiers
isabellewei Oct 31, 2022
f07c4cd
fix tests
isabellewei Nov 1, 2022
d8cd6cd
PR comments
isabellewei Nov 18, 2022
4a7fc80
Merge branch 'master' of github.com:celo-org/celo-monorepo into isabe…
isabellewei Nov 18, 2022
710f3d8
update test
isabellewei Nov 18, 2022
8d3fe71
get rid of erroneously committed file
isabellewei Nov 18, 2022
3a92ce8
add prefix when blinding
isabellewei Nov 18, 2022
0b4a25a
add backwards compatibility test and fix existing tests
isabellewei Nov 22, 2022
0477fa6
Merge branch 'master' of github.com:celo-org/celo-monorepo into isabe…
isabellewei Nov 22, 2022
57795a5
update dependency graph
isabellewei Nov 22, 2022
f60b7cc
add comment
isabellewei Nov 22, 2022
baa9e1c
PR comments
isabellewei Nov 23, 2022
103bb75
PR comments
isabellewei Nov 23, 2022
00f9c35
ensure backwards compatibility
isabellewei Nov 29, 2022
c8a013f
update dep graph
isabellewei Nov 29, 2022
e33a385
hardcode expected values in backwards compatibility test
isabellewei Nov 30, 2022
f611c17
nit: remove newline
isabellewei Dec 6, 2022
388f81d
make comments TSDoc compatible
isabellewei Dec 6, 2022
944f661
PR comments
isabellewei Dec 6, 2022
8be47b0
Merge branch 'isabellewei/allIdentifiers' of github.com:celo-org/celo…
isabellewei Dec 6, 2022
67915e5
update docstrings and enforce prefix type
isabellewei Dec 6, 2022
387cda4
Merge branch 'master' of github.com:celo-org/celo-monorepo into isabe…
isabellewei Dec 6, 2022
3036bc1
add yarn.lock
isabellewei Dec 6, 2022
fff573c
revert identity pkg version in attestation-service
isabellewei Dec 6, 2022
e2e3674
use latest identity pkg version pre identifier change in attestation-…
isabellewei Dec 6, 2022
d1fef17
yarn.lock
isabellewei Dec 6, 2022
242eab0
update test value for nested hashing
isabellewei Dec 6, 2022
b9115b4
Merge branch 'master' into isabellewei/allIdentifiers
alecps Dec 7, 2022
67ec36c
Merge branch 'master' into isabellewei/allIdentifiers
alecps Dec 8, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/attestation-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
},
"dependencies": {
"@celo/contractkit": "3.0.1-dev",
"@celo/identity": "3.0.1-dev",
"@celo/identity": "3.0.0",
"@celo/keystores": "3.0.1-dev",
"@celo/phone-utils": "3.0.1-dev",
"bignumber.js": "^9.0.0",
Expand Down
5 changes: 3 additions & 2 deletions packages/sdk/identity/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"docs": "typedoc",
"test:reset": "yarn --cwd ../../protocol devchain generate-tar .tmp/devchain.tar.gz --migration_override ../../dev-utils/src/migration-override.json --upto 28",
"test:livechain": "yarn --cwd ../../protocol devchain run-tar .tmp/devchain.tar.gz",
"test": "jest --runInBand",
"test": "jest --runInBand --testPathIgnorePatterns src/odis/identifier-backwards-compatibility.test.ts",
"lint": "tslint -c tslint.json --project .",
"prepublishOnly": "yarn build"
},
Expand All @@ -44,7 +44,8 @@
"fetch-mock": "9.10.4",
"@types/elliptic": "^6.4.12",
"@celo/flake-tracker": "0.0.1-dev",
"@celo/ganache-cli": "git+https://github.com/celo-org/ganache-cli.git#21652da"
"@celo/ganache-cli": "git+https://github.com/celo-org/ganache-cli.git#21652da",
"old-identity-sdk": "npm:@celo/identity@1.5.2"
},
"engines": {
"node": ">=12.9.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { getPhoneHash } from '@celo/base'
isabellewei marked this conversation as resolved.
Show resolved Hide resolved
import { soliditySha3 } from '@celo/utils/lib/solidity'
import { OdisUtils } from 'old-identity-sdk'
import { WasmBlsBlindingClient } from './bls-blinding-client'
import {
getBlindedIdentifier,
getIdentifierHash,
getObfuscatedIdentifier,
IdentifierPrefix,
} from './identifier'
import { AuthenticationMethod, AuthSigner, getServiceContext } from './query'

const mockE164Number = '+14155550000'
const mockAccount = '0x755dB5fF7B82e9a96e0dDDD143293dc2ADeC0050'
// const mockPrivateKey = '0x2cacaf965ae80da49d5b1fc4b4c9b08ffc35971a584aedcc1cb8322b9d5fd9c9'
alecps marked this conversation as resolved.
Show resolved Hide resolved

// this DEK has been registered to the above account on alfajores
const dekPrivateKey = '0xc2bbdabb440141efed205497a41d5fb6114e0435fd541e368dc628a8e086bfee'
// const dekPublicKey = '0xc2bbdabb440141efed205497a41d5fb6114e0435fd541e368dc628a8e086bfee'
alecps marked this conversation as resolved.
Show resolved Hide resolved

const authSigner: AuthSigner = {
authenticationMethod: AuthenticationMethod.ENCRYPTION_KEY,
rawKey: dekPrivateKey,
}
const oldServiceContext = OdisUtils.Query.getServiceContext('alfajores')
const currentServiceContext = getServiceContext('alfajores')

const expectedObfuscatedIdentifier =
'0xf82c6272fd57d3e5d4e291be16b3ebac5c616084a5e6f3730c73f62efd39c6ae'
const expectedPepper = 'Pi4Z1NQnfsdvJ'

describe('backwards compatibility of phone number identifiers', () => {
beforeAll(() => {
fetchMock.reset()
// disables the mock, lets all calls fall through to the actual network
fetchMock.spy()
})

it('should match when using EncryptionSigner', async () => {
const oldRes = await OdisUtils.PhoneNumberIdentifier.getPhoneNumberIdentifier(
mockE164Number,
mockAccount,
authSigner,
oldServiceContext
)

const currRes = await getObfuscatedIdentifier(
mockE164Number,
IdentifierPrefix.PHONE_NUMBER,
mockAccount,
authSigner,
currentServiceContext
)

expect(oldRes.e164Number).toEqual(currRes.plaintextIdentifier)
expect(oldRes.phoneHash).toEqual(expectedObfuscatedIdentifier)
expect(currRes.obfuscatedIdentifier).toEqual(expectedObfuscatedIdentifier)
expect(oldRes.pepper).toEqual(expectedPepper)
expect(currRes.pepper).toEqual(expectedPepper)
}, 20000)

isabellewei marked this conversation as resolved.
Show resolved Hide resolved
it('blinded identifier should match', async () => {
const blsBlindingClient = new WasmBlsBlindingClient('')
const seed = Buffer.from(
'44714c0a2b2bacec757a67822a4fbbdfe043cca8c6ae936545ef992f246df1a9',
'hex'
)
const oldRes = await OdisUtils.PhoneNumberIdentifier.getBlindedPhoneNumber(
mockE164Number,
blsBlindingClient,
seed
)
const currentRes = await getBlindedIdentifier(
mockE164Number,
IdentifierPrefix.PHONE_NUMBER,
blsBlindingClient,
seed
)

const expectedBlindedIdentifier =
'fuN6SmbxkYBqVbKZu4SizdyDjavNLK/XguIlwsWUhsWA0hQDoZtsZjQCbXqTnUiA'

expect(oldRes).toEqual(expectedBlindedIdentifier)
expect(currentRes).toEqual(expectedBlindedIdentifier)
})

it('obfuscated identifier should match', async () => {
const sha3 = (v: string) => soliditySha3({ type: 'string', value: v })
const oldRes = getPhoneHash(sha3, mockE164Number, expectedPepper)

const currRes = getIdentifierHash(mockE164Number, IdentifierPrefix.PHONE_NUMBER, expectedPepper)

expect(oldRes).toEqual(expectedObfuscatedIdentifier)
expect(currRes).toEqual(expectedObfuscatedIdentifier)
})

it('should not match when different prefix used', async () => {
const oldRes = await OdisUtils.PhoneNumberIdentifier.getPhoneNumberIdentifier(
mockE164Number,
mockAccount,
authSigner,
oldServiceContext
)

const currRes = await getObfuscatedIdentifier(
mockE164Number,
'badPrefix',
alecps marked this conversation as resolved.
Show resolved Hide resolved
mockAccount,
authSigner,
currentServiceContext
)

expect(oldRes.e164Number).toEqual(currRes.plaintextIdentifier)
expect(oldRes.phoneHash).not.toEqual(currRes.obfuscatedIdentifier)
expect(oldRes.pepper).not.toEqual(currRes.pepper)
})
})
156 changes: 156 additions & 0 deletions packages/sdk/identity/src/odis/identifier.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import { CombinerEndpoint } from '@celo/phone-number-privacy-common'
import { WasmBlsBlindingClient } from './bls-blinding-client'
import {
getBlindedIdentifier,
getBlindedIdentifierSignature,
getObfuscatedIdentifier,
getObfuscatedIdentifierFromSignature,
getPepperFromThresholdSignature,
IdentifierPrefix,
} from './identifier'
import { AuthenticationMethod, EncryptionKeySigner, ErrorMessages, ServiceContext } from './query'

jest.mock('./bls-blinding-client', () => {
// tslint:disable-next-line:no-shadowed-variable
class WasmBlsBlindingClient {
blindMessage = (m: string) => m
unblindAndVerifyMessage = (m: string) => m
}
return {
WasmBlsBlindingClient,
}
})

const mockOffchainIdentifier = 'twitterHandle'
const mockAccount = '0x0000000000000000000000000000000000007E57'
const expectedIdentifierHash = '0x8d1f580d4e49568883df9092285c0f8336e50d592b944607a613aff804e0b48f'
const expectedPepper = 'nHIvMC9B4j2+H'

const serviceContext: ServiceContext = {
odisUrl: 'https://mockodis.com',
odisPubKey:
'7FsWGsFnmVvRfMDpzz95Np76wf/1sPaK0Og9yiB+P8QbjiC8FV67NBans9hzZEkBaQMhiapzgMR6CkZIZPvgwQboAxl65JWRZecGe5V3XO4sdKeNemdAZ2TzQuWkuZoA',
}
const endpoint = serviceContext.odisUrl + CombinerEndpoint.PNP_SIGN
const rawKey = '41e8e8593108eeedcbded883b8af34d2f028710355c57f4c10a056b72486aa04'

const authSigner: EncryptionKeySigner = {
authenticationMethod: AuthenticationMethod.ENCRYPTION_KEY,
rawKey,
}

describe(getObfuscatedIdentifier, () => {
afterEach(() => {
fetchMock.reset()
})

describe('Retrieves a pepper correctly', () => {
it('Using EncryptionKeySigner', async () => {
fetchMock.mock(endpoint, {
success: true,
signature: '0Uj+qoAu7ASMVvm6hvcUGx2eO/cmNdyEgGn0mSoZH8/dujrC1++SZ1N6IP6v2I8A',
performedQueryCount: 5,
totalQuota: 10,
version: '',
})

const blsBlindingClient = new WasmBlsBlindingClient(serviceContext.odisPubKey)
const base64BlindedMessage = await getBlindedIdentifier(
mockOffchainIdentifier,
IdentifierPrefix.TWITTER,
blsBlindingClient
)
const base64BlindSig = await getBlindedIdentifierSignature(
mockAccount,
authSigner,
serviceContext,
base64BlindedMessage
)
const base64UnblindedSig = await blsBlindingClient.unblindAndVerifyMessage(base64BlindSig)

await expect(
getObfuscatedIdentifier(
mockOffchainIdentifier,
IdentifierPrefix.TWITTER,
mockAccount,
authSigner,
serviceContext
)
).resolves.toMatchObject({
plaintextIdentifier: mockOffchainIdentifier,
pepper: expectedPepper,
obfuscatedIdentifier: expectedIdentifierHash,
unblindedSignature: base64UnblindedSig,
})
})

it('Preblinding the off-chain identifier', async () => {
fetchMock.mock(endpoint, {
success: true,
signature: '0Uj+qoAu7ASMVvm6hvcUGx2eO/cmNdyEgGn0mSoZH8/dujrC1++SZ1N6IP6v2I8A',
performedQueryCount: 5,
totalQuota: 10,
version: '',
})

const blsBlindingClient = new WasmBlsBlindingClient(serviceContext.odisPubKey)
const base64BlindedMessage = await getBlindedIdentifier(
mockOffchainIdentifier,
IdentifierPrefix.TWITTER,
blsBlindingClient
)

const base64BlindSig = await getBlindedIdentifierSignature(
mockAccount,
authSigner,
serviceContext,
base64BlindedMessage
)

const obfuscatedIdentifierDetails = await getObfuscatedIdentifierFromSignature(
mockOffchainIdentifier,
IdentifierPrefix.TWITTER,
base64BlindSig,
blsBlindingClient
)

expect(obfuscatedIdentifierDetails.obfuscatedIdentifier).toEqual(expectedIdentifierHash)
expect(obfuscatedIdentifierDetails.pepper).toEqual(expectedPepper)
})
})

it('Throws quota error', async () => {
fetchMock.mock(endpoint, 403)

await expect(
getObfuscatedIdentifier(
mockOffchainIdentifier,
IdentifierPrefix.PHONE_NUMBER,
mockAccount,
authSigner,
serviceContext
)
).rejects.toThrow(ErrorMessages.ODIS_QUOTA_ERROR)
})

it('Throws auth error', async () => {
fetchMock.mock(endpoint, 401)
await expect(
getObfuscatedIdentifier(
mockOffchainIdentifier,
IdentifierPrefix.PHONE_NUMBER,
mockAccount,
authSigner,
serviceContext
)
).rejects.toThrow(ErrorMessages.ODIS_AUTH_ERROR)
})
})

describe(getPepperFromThresholdSignature, () => {
it('Hashes sigs correctly', () => {
const base64Sig = 'vJeFZJ3MY5KlpI9+kIIozKkZSR4cMymLPh2GHZUatWIiiLILyOcTiw2uqK/LBReA'
const signature = Buffer.from(base64Sig, 'base64')
expect(getPepperFromThresholdSignature(signature)).toBe('piWqRHHYWtfg9')
})
})
Loading