Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions app/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,19 @@ GEM
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.4.0)
aws-partitions (1.1140.0)
aws-sdk-core (3.228.0)
aws-partitions (1.1141.0)
aws-sdk-core (3.229.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
base64
bigdecimal
jmespath (~> 1, >= 1.6.1)
logger
aws-sdk-kms (1.109.0)
aws-sdk-kms (1.110.0)
aws-sdk-core (~> 3, >= 3.228.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.195.0)
aws-sdk-s3 (1.196.0)
aws-sdk-core (~> 3, >= 3.228.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
Expand Down
27 changes: 0 additions & 27 deletions app/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1448,29 +1448,6 @@ PODS:
- React-Core
- react-native-nfc-manager (3.16.1):
- React-Core
- react-native-quick-crypto (0.7.14):
- DoubleConversion
- glog
- hermes-engine
- OpenSSL-Universal
- RCT-Folly (= 2024.01.01.00)
- RCTRequired
- RCTTypeSafety
- React
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-NativeModulesApple
- React-RCTFabric
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-safe-area-context (5.5.1):
- React-Core
- react-native-sqlite-storage (6.0.1):
Expand Down Expand Up @@ -1930,7 +1907,6 @@ DEPENDENCIES:
- react-native-get-random-values (from `../../node_modules/react-native-get-random-values`)
- "react-native-netinfo (from `../../node_modules/@react-native-community/netinfo`)"
- react-native-nfc-manager (from `../../node_modules/react-native-nfc-manager`)
- react-native-quick-crypto (from `../../node_modules/react-native-quick-crypto`)
- react-native-safe-area-context (from `../../node_modules/react-native-safe-area-context`)
- react-native-sqlite-storage (from `../../node_modules/react-native-sqlite-storage`)
- React-nativeconfig (from `../../node_modules/react-native/ReactCommon`)
Expand Down Expand Up @@ -2094,8 +2070,6 @@ EXTERNAL SOURCES:
:path: "../../node_modules/@react-native-community/netinfo"
react-native-nfc-manager:
:path: "../../node_modules/react-native-nfc-manager"
react-native-quick-crypto:
:path: "../../node_modules/react-native-quick-crypto"
react-native-safe-area-context:
:path: "../../node_modules/react-native-safe-area-context"
react-native-sqlite-storage:
Expand Down Expand Up @@ -2261,7 +2235,6 @@ SPEC CHECKSUMS:
react-native-get-random-values: d16467cf726c618e9c7a8c3c39c31faa2244bbba
react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187
react-native-nfc-manager: a280ef94cd4871a471b052f0dc70381cf1223049
react-native-quick-crypto: 8c04031798c1902ec3c6f4def538911a8f744d03
react-native-safe-area-context: 827032edf27079702cbd006f11dc79451a2d744b
react-native-sqlite-storage: 0c84826214baaa498796c7e46a5ccc9a82e114ed
React-nativeconfig: 31072ab0146e643594f6959c7f970a04b6c9ddd0
Expand Down
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"dependencies": {
"@babel/runtime": "^7.27.4",
"@ethersproject/shims": "^5.7.0",
"@noble/hashes": "^1.5.0",
"@openpassport/zk-kit-lean-imt": "^0.0.6",
"@openpassport/zk-kit-smt": "^0.0.1",
"@peculiar/x509": "^1.12.3",
Expand Down Expand Up @@ -124,7 +125,6 @@
"react-native-localize": "^3.4.1",
"react-native-nfc-manager": "^3.15.1",
"react-native-passport-reader": "^1.0.3",
"react-native-quick-crypto": "^0.7.12",
"react-native-safe-area-context": "^5.5.1",
"react-native-screens": "4.9.0",
"react-native-sqlite-storage": "^6.0.1",
Expand Down
64 changes: 46 additions & 18 deletions app/src/utils/ethers.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,55 @@
// SPDX-License-Identifier: BUSL-1.1; Copyright (c) 2025 Social Connect Labs, Inc.; Licensed under BUSL-1.1 (see LICENSE); Apache-2.0 from 2029-06-11

// https://docs.ethers.org/v6/cookbook/react-native/
import { hmac } from '@noble/hashes/hmac';
import { pbkdf2 as noblePbkdf2 } from '@noble/hashes/pbkdf2';
import { sha256 as nobleSha256 } from '@noble/hashes/sha256';
import { sha512 as nobleSha512 } from '@noble/hashes/sha512';
import { ethers } from 'ethers';
import crypto from 'react-native-quick-crypto';

ethers.randomBytes.register(length => {
return new Uint8Array(crypto.randomBytes(length));
});
function randomBytes(length: number): Uint8Array {
if (typeof globalThis.crypto?.getRandomValues !== 'function') {
throw new Error('globalThis.crypto.getRandomValues is not available');
}
return globalThis.crypto.getRandomValues(new Uint8Array(length));
}

ethers.computeHmac.register((algo, key, data) => {
return crypto.createHmac(algo, key).update(data).digest();
});
function computeHmac(
algo: 'sha256' | 'sha512',
key: Uint8Array,
data: Uint8Array,
): Uint8Array {
const hash = algo === 'sha256' ? nobleSha256 : nobleSha512;
return hmac(hash, key, data);
}

ethers.pbkdf2.register((passwd, salt, iter, keylen, algo) => {
return crypto.pbkdf2Sync(passwd, salt, iter, keylen, algo);
});
function pbkdf2(
password: Uint8Array,
salt: Uint8Array,
iterations: number,
keylen: number,
algo: 'sha256' | 'sha512',
): Uint8Array {
const hash = algo === 'sha256' ? nobleSha256 : nobleSha512;
return noblePbkdf2(hash, password, salt, { c: iterations, dkLen: keylen });
}

ethers.sha256.register(data => {
// @ts-expect-error
return crypto.createHash('sha256').update(data).digest();
});
function sha256(data: Uint8Array): Uint8Array {
return nobleSha256.create().update(data).digest();
}

ethers.sha512.register(data => {
// @ts-expect-error
return crypto.createHash('sha512').update(data).digest();
});
function sha512(data: Uint8Array): Uint8Array {
return nobleSha512.create().update(data).digest();
}

ethers.randomBytes.register(randomBytes);

ethers.computeHmac.register(computeHmac);

ethers.pbkdf2.register(pbkdf2);

ethers.sha256.register(sha256);

ethers.sha512.register(sha512);

export { computeHmac, pbkdf2, randomBytes, sha256, sha512 };
55 changes: 55 additions & 0 deletions app/tests/utils/ethers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: BUSL-1.1; Copyright (c) 2025 Social Connect Labs, Inc.; Licensed under BUSL-1.1 (see LICENSE); Apache-2.0 from 2029-06-11

// Register crypto polyfills
import '../../src/utils/ethers';

import { ethers } from 'ethers';

describe('ethers crypto polyfills', () => {
it('randomBytes returns requested length and unique values', () => {
const a = ethers.randomBytes(16);
const b = ethers.randomBytes(16);

expect(a).toHaveLength(16);
expect(b).toHaveLength(16);
expect(ethers.hexlify(a)).not.toBe(ethers.hexlify(b));
});

it('computeHmac matches known vector', () => {
const result = ethers.computeHmac(
'sha256',
ethers.toUtf8Bytes('key'),
ethers.toUtf8Bytes('data'),
);
expect(ethers.hexlify(result)).toBe(
'0x5031fe3d989c6d1537a013fa6e739da23463fdaec3b70137d828e36ace221bd0',
);
});

it('pbkdf2 derives expected key', () => {
const derived = ethers.pbkdf2(
ethers.toUtf8Bytes('password'),
ethers.toUtf8Bytes('salt'),
1000,
32,
'sha256',
);
expect(ethers.hexlify(derived)).toBe(
'0x632c2812e46d4604102ba7618e9d6d7d2f8128f6266b4a03264d2a0460b7dcb3',
);
});

it('sha256 hashes data correctly', () => {
const digest = ethers.sha256(ethers.toUtf8Bytes('hello'));
expect(ethers.hexlify(digest)).toBe(
'0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824',
);
});

it('sha512 hashes data correctly', () => {
const digest = ethers.sha512(ethers.toUtf8Bytes('hello'));
expect(ethers.hexlify(digest)).toBe(
'0x9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043',
);
});
});
56 changes: 5 additions & 51 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1099,16 +1099,6 @@ __metadata:
languageName: node
linkType: hard

"@craftzdog/react-native-buffer@npm:^6.0.5":
version: 6.1.0
resolution: "@craftzdog/react-native-buffer@npm:6.1.0"
dependencies:
ieee754: "npm:^1.2.1"
react-native-quick-base64: "npm:^2.0.5"
checksum: 10c0/ec6115d5ae1924a329b5ce7bebe147b7e2464e8529088dc1be75d8de67837976f0ecc555b486684a81b7a4e9d779335cf9c9a68afd03849f971e47456b55eafc
languageName: node
linkType: hard

"@cspotcode/source-map-support@npm:^0.8.0":
version: 0.8.1
resolution: "@cspotcode/source-map-support@npm:0.8.1"
Expand Down Expand Up @@ -2570,7 +2560,7 @@ __metadata:
languageName: node
linkType: hard

"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.4.0":
"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.4.0, @noble/hashes@npm:^1.5.0":
version: 1.8.0
resolution: "@noble/hashes@npm:1.8.0"
checksum: 10c0/06a0b52c81a6fa7f04d67762e08b2c476a00285858150caeaaff4037356dd5e119f45b2a530f638b77a5eeca013168ec1b655db41bae3236cb2e9d511484fc77
Expand Down Expand Up @@ -4623,6 +4613,7 @@ __metadata:
"@babel/plugin-transform-private-methods": "npm:^7.23.3"
"@babel/runtime": "npm:^7.27.4"
"@ethersproject/shims": "npm:^5.7.0"
"@noble/hashes": "npm:^1.5.0"
"@openpassport/zk-kit-lean-imt": "npm:^0.0.6"
"@openpassport/zk-kit-smt": "npm:^0.0.1"
"@peculiar/x509": "npm:^1.12.3"
Expand Down Expand Up @@ -4716,7 +4707,6 @@ __metadata:
react-native-localize: "npm:^3.4.1"
react-native-nfc-manager: "npm:^3.15.1"
react-native-passport-reader: "npm:^1.0.3"
react-native-quick-crypto: "npm:^0.7.12"
react-native-safe-area-context: "npm:^5.5.1"
react-native-screens: "npm:4.9.0"
react-native-sqlite-storage: "npm:^6.0.1"
Expand Down Expand Up @@ -14605,7 +14595,7 @@ __metadata:
languageName: node
linkType: hard

"events@npm:^3.2.0, events@npm:^3.3.0":
"events@npm:^3.2.0":
version: 3.3.0
resolution: "events@npm:3.3.0"
checksum: 10c0/d6b6f2adbccbcda74ddbab52ed07db727ef52e31a61ed26db9feb7dc62af7fc8e060defa65e5f8af9449b86b52cc1a1f6a79f2eafcf4e62add2b7a1fa4a432f6
Expand Down Expand Up @@ -20586,7 +20576,7 @@ __metadata:
languageName: node
linkType: hard

"process@npm:^0.11.1, process@npm:^0.11.10":
"process@npm:^0.11.1":
version: 0.11.10
resolution: "process@npm:0.11.10"
checksum: 10c0/40c3ce4b7e6d4b8c3355479df77aeed46f81b279818ccdc500124e6a5ab882c0cc81ff7ea16384873a95a74c4570b01b120f287abbdd4c877931460eca6084b3
Expand Down Expand Up @@ -21140,29 +21130,6 @@ __metadata:
languageName: node
linkType: hard

"react-native-quick-base64@npm:^2.0.5":
version: 2.2.0
resolution: "react-native-quick-base64@npm:2.2.0"
peerDependencies:
react: "*"
react-native: "*"
checksum: 10c0/f4c800aa3b4932228c406de86d70c8b4183e2522e941736d7edb4fbe7d9b6158e375cd197869a344f551fff8c5e609b4d6eb4d2ce6e8ef61dfb2aef42aadebff
languageName: node
linkType: hard

"react-native-quick-crypto@npm:^0.7.12":
version: 0.7.14
resolution: "react-native-quick-crypto@npm:0.7.14"
dependencies:
"@craftzdog/react-native-buffer": "npm:^6.0.5"
events: "npm:^3.3.0"
readable-stream: "npm:^4.5.2"
string_decoder: "npm:^1.3.0"
util: "npm:^0.12.5"
checksum: 10c0/7074fb108f2205a521394128dfe44805fcb56145972ba7e6247e679c51a8b90b7114a400c80a2d9317f3ab317e36787fa89e419fe45549a32db76a41333ca921
languageName: node
linkType: hard

"react-native-safe-area-context@npm:^5.5.1":
version: 5.5.1
resolution: "react-native-safe-area-context@npm:5.5.1"
Expand Down Expand Up @@ -21537,19 +21504,6 @@ __metadata:
languageName: node
linkType: hard

"readable-stream@npm:^4.5.2":
version: 4.7.0
resolution: "readable-stream@npm:4.7.0"
dependencies:
abort-controller: "npm:^3.0.0"
buffer: "npm:^6.0.3"
events: "npm:^3.3.0"
process: "npm:^0.11.10"
string_decoder: "npm:^1.3.0"
checksum: 10c0/fd86d068da21cfdb10f7a4479f2e47d9c0a9b0c862fc0c840a7e5360201580a55ac399c764b12a4f6fa291f8cee74d9c4b7562e0d53b3c4b2769f2c98155d957
languageName: node
linkType: hard

"readdirp@npm:^4.0.1":
version: 4.1.2
resolution: "readdirp@npm:4.1.2"
Expand Down Expand Up @@ -23182,7 +23136,7 @@ __metadata:
languageName: node
linkType: hard

"string_decoder@npm:^1.1.1, string_decoder@npm:^1.3.0":
"string_decoder@npm:^1.1.1":
version: 1.3.0
resolution: "string_decoder@npm:1.3.0"
dependencies:
Expand Down
Loading