-
Notifications
You must be signed in to change notification settings - Fork 428
Open
Description
Hello dear Vectorize ( @Vectorized ),
Im Alex, solidity dev at @openfort-xyz
Im happy to use with ur impl. of webAuthn. Unfortunately the lib unsupported in all chains who was upgraded to support 7702. The lib callin sha256 precompile and not continue to calll modexp in chains like: BNB
, Base
, Bera
, GNO
, Ink
.
Please could add this functionality for the webAuthn lib π€?
Im attaching hereby tests ive done with ur lib and lib of // @author Coinbase (https://github.com/base-org/webauthn-sol)
// SDPX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {WebAuthn} from "lib/webauthn-sol/src/WebAuthn.sol";
import {Test, console2 as console} from "lib/forge-std/src/test.sol";
import {WebAuthn as WebAuthnVerifierSolady} from "lib/solady/src/utils/WebAuthn.sol";
contract WebAuthnChains is Test {
// @author Coinbase (https://github.com/base-org/webauthn-sol)
Verifier v;
// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/WebAuthn.sol)
VerifierSolady vS;
uint256 forkId;
string public SEPOLIA_RPC;
string public MAINET_RPC;
string public BASE_RPC;
string public BERA_RPC;
string public BNB_RPC;
string public GNO_RPC;
string public INK_RPC;
string public OP_RPC;
bytes32 constant PUBLIC_KEY_X =
hex"f014cc9fb4edba3c439a22423f580ad29cb177dbd5af224e4d068ef6374df083";
bytes32 constant PUBLIC_KEY_Y =
hex"f4c5322095ffa8db8344b7675f82eeadd2a17af4d9db9d4d4c582e8839ca391e";
bytes32 public constant CHALLENGE =
hex"cea3e080968320575bc01fbe2293a690683e321ac28cfb95a234e4b959e4fcfa";
bytes32 public constant SIGNATURE_R =
hex"cf1d727573eee8b3d301ab94aec432c1b7953969dcdf71388d14385630378a80";
bytes32 public constant SIGNATURE_S =
hex"417d9bafa3acecdbba348f851c1efc93c7ed780e2eddc7046767a1998db4f0c8";
bytes public constant AUTHENTICATOR_DATA =
hex"49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97631d00000000";
string public constant CLIENT_DATA_JSON =
"{\"type\":\"webauthn.get\",\"challenge\":\"zqPggJaDIFdbwB--IpOmkGg-MhrCjPuVojTkuVnk_Po\",\"origin\":\"http://localhost:5173\",\"crossOrigin\":false}";
uint256 public constant CHALLENGE_INDEX = 23;
uint256 public constant TYPE_INDEX = 1;
function setUp() public {
SEPOLIA_RPC = "https://eth-sepolia.g.alchemy.com/v2/EIOmdDtOw7ulufI5S27isOfZfW51PQXB";
MAINET_RPC = "https://eth-mainnet.g.alchemy.com/v2/EIOmdDtOw7ulufI5S27isOfZfW51PQXB";
BASE_RPC = "https://base-mainnet.g.alchemy.com/v2/EIOmdDtOw7ulufI5S27isOfZfW51PQXB";
BERA_RPC = "https://berachain-mainnet.g.alchemy.com/v2/EIOmdDtOw7ulufI5S27isOfZfW51PQXB";
BNB_RPC = "https://bnb-testnet.g.alchemy.com/v2/EIOmdDtOw7ulufI5S27isOfZfW51PQXB";
GNO_RPC = "https://gnosis-mainnet.g.alchemy.com/v2/EIOmdDtOw7ulufI5S27isOfZfW51PQXB";
INK_RPC = "https://ink-mainnet.g.alchemy.com/v2/EIOmdDtOw7ulufI5S27isOfZfW51PQXB";
OP_RPC = "https://opt-mainnet.g.alchemy.com/v2/EIOmdDtOw7ulufI5S27isOfZfW51PQXB";
}
function test_Sepolia() public {
forkId = vm.createFork(SEPOLIA_RPC);
vm.selectFork(forkId);
v = new Verifier();
bool isValid = v.verify(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_Mainet() public {
forkId = vm.createFork(MAINET_RPC);
vm.selectFork(forkId);
v = new Verifier();
bool isValid = v.verify(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_Base() public {
forkId = vm.createFork(BASE_RPC);
vm.selectFork(forkId);
v = new Verifier();
bool isValid = v.verify(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_Bera() public {
forkId = vm.createFork(BERA_RPC);
vm.selectFork(forkId);
v = new Verifier();
bool isValid = v.verify(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_BNB() public {
forkId = vm.createFork(BNB_RPC);
vm.selectFork(forkId);
v = new Verifier();
bool isValid = v.verify(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_GNO() public {
forkId = vm.createFork(GNO_RPC);
vm.selectFork(forkId);
v = new Verifier();
bool isValid = v.verify(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_Ink() public {
forkId = vm.createFork(INK_RPC);
vm.selectFork(forkId);
v = new Verifier();
bool isValid = v.verify(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_OP() public {
forkId = vm.createFork(OP_RPC);
vm.selectFork(forkId);
v = new Verifier();
bool isValid = v.verify(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_Sepolia_Solady() public {
forkId = vm.createFork(SEPOLIA_RPC);
vm.selectFork(forkId);
vS = new VerifierSolady();
bool isValid = vS.verifySoladySignature(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_Mainet_Solady() public {
forkId = vm.createFork(MAINET_RPC);
vm.selectFork(forkId);
vS = new VerifierSolady();
bool isValid = vS.verifySoladySignature(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_Base_Solady() public {
forkId = vm.createFork(BASE_RPC);
vm.selectFork(forkId);
vS = new VerifierSolady();
bool isValid = vS.verifySoladySignature(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_Bera_Solady() public {
forkId = vm.createFork(BERA_RPC);
vm.selectFork(forkId);
vS = new VerifierSolady();
bool isValid = vS.verifySoladySignature(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_BNB_Solady() public {
forkId = vm.createFork(BNB_RPC);
vm.selectFork(forkId);
vS = new VerifierSolady();
bool isValid = vS.verifySoladySignature(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_GNO_Solady() public {
forkId = vm.createFork(GNO_RPC);
vm.selectFork(forkId);
vS = new VerifierSolady();
bool isValid = vS.verifySoladySignature(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_Ink_Solady() public {
forkId = vm.createFork(INK_RPC);
vm.selectFork(forkId);
vS = new VerifierSolady();
bool isValid = vS.verifySoladySignature(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
function test_OP_Solady() public {
forkId = vm.createFork(OP_RPC);
vm.selectFork(forkId);
vS = new VerifierSolady();
bool isValid = vS.verifySoladySignature(
CHALLENGE,
true,
AUTHENTICATOR_DATA,
CLIENT_DATA_JSON,
CHALLENGE_INDEX,
TYPE_INDEX,
SIGNATURE_R,
SIGNATURE_S,
PUBLIC_KEY_X,
PUBLIC_KEY_Y
);
assertTrue(isValid);
}
}
contract Verifier {
function verify(
bytes32 challenge,
bool requireUserVerification,
bytes memory authenticatorData,
string memory clientDataJSON,
uint256 challengeIndex,
uint256 typeIndex,
bytes32 r,
bytes32 s,
bytes32 x,
bytes32 y
) public view returns (bool isValid) {
uint256 rUint = uint256(r);
uint256 sUint = uint256(s);
uint256 xUint = uint256(x);
uint256 yUint = uint256(y);
// @audit-info β οΈ: Can be external
WebAuthn.WebAuthnAuth memory auth = WebAuthn.WebAuthnAuth({
authenticatorData: authenticatorData,
clientDataJSON: clientDataJSON,
challengeIndex: challengeIndex,
typeIndex: typeIndex,
r: rUint,
s: sUint
});
// Todo: test of Converting good or not
bytes memory challengeBytes = toBytes(challenge);
isValid = WebAuthn.verify(challengeBytes, requireUserVerification, auth, xUint, yUint);
return isValid;
}
function toBytes(bytes32 data) internal pure returns (bytes memory result) {
result = new bytes(32);
assembly {
mstore(add(result, 32), data)
}
}
}
contract VerifierSolady {
function verifySoladySignature(
bytes32 challenge,
bool requireUserVerification,
bytes memory authenticatorData,
string memory clientDataJSON,
uint256 challengeIndex,
uint256 typeIndex,
bytes32 r,
bytes32 s,
bytes32 x,
bytes32 y
) public view returns (bool isValid) {
// @audit-info β οΈ: Can be external
WebAuthnVerifierSolady.WebAuthnAuth memory auth = WebAuthnVerifierSolady.WebAuthnAuth({
authenticatorData: authenticatorData,
clientDataJSON: clientDataJSON,
challengeIndex: challengeIndex,
typeIndex: typeIndex,
r: r,
s: s
});
// Todo: test of Converting good or not
bytes memory challengeBytes = toBytes(challenge);
isValid = WebAuthnVerifierSolady.verify(challengeBytes, requireUserVerification, auth, x, y);
return isValid;
}
function toBytes(bytes32 data) internal pure returns (bytes memory result) {
result = new bytes(32);
assembly {
mstore(add(result, 32), data)
}
}
}
test of SEPOLIA_RPC, MAINET_RPC and OP_RPC passing as well since it call correct precompile:
β β ββ [1360] PRECOMPILES::modexp(32, 32, 32, 0x417d9bafa3acecdbba348f851c1efc93c7ed780e2eddc7046767a1998db4f0c8, 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f, 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551) [staticcall]
β β β ββ β [Return] 0x0045b25f83a9d65d17382ec31df8a1ba3ce92ed69bb890396c4021dbf4705df4
β β ββ [1360] PRECOMPILES::modexp(32, 32, 32, 0x18cfcde3b8d7575f848fba319ecdfb33045a2d7a175dd9676da62431ae80a333, 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffd, 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff) [staticcall]
β β β ββ β [Return] 0x89257cd9ec83eaf5fa85b2a3c4cf54d70ca4dd6675d7617905b10246a5e90f41
β β ββ β [Return] 0x0000000000000000000000000000000000000000000000000000000000000001
test of the rest chains:
β ββ [120] PRECOMPILES::sha256(0x7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a227a715067674a61444946646277422d2d49704f6d6b47672d4d6872436a5075566f6a546b75566e6b5f506f222c226f726967696e223a22687474703a2f2f6c6f63616c686f73743a35313733222c2263726f73734f726967696e223a66616c73657d) [staticcall]
β β ββ β [Return] 0x219e7c3fe7a11bb2c9a1df45b0edf5fc2643e7391b9e89e6725aa27a4e4f2308
β ββ [96] PRECOMPILES::sha256(0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97631d00000000219e7c3fe7a11bb2c9a1df45b0edf5fc2643e7391b9e89e6725aa27a4e4f2308) [staticcall]
β β ββ β [Return] 0xf8a2ad3bfb24311530aa0157be355d27d57f2f9e3b7f68bce248a729ab95aa75
hope you will have time for this.
Thanks and good day π«°π«°π«°
Metadata
Metadata
Assignees
Labels
No labels