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

🔨 deployment script for the standard version #35

Merged
merged 5 commits into from
Jul 27, 2023
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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ before considering this approach.
> [library](https://github.com/0x90d2b2b7fb7599eebb6e7a32980857d8/secp256r1-computation) developed by us for this
> purpose.

### Scripts

This repository includes a [script](./script) directory containing a set of scripts that can be used to deploy the
different implementations on-chain. Each script contains a set of instructions and an example of how to use it. The
scripts are expected to be run using the `forge script` command.

## Gas reports

These gas reports were produced using the `0.8.19` version of the Solidity compiler, specifically for the
Expand Down
11 changes: 9 additions & 2 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ default:
\e[90m$$ \e[0;97;1mmake \e[0;92;1mquality \e[0;90m➔ \e[32;3mrun both the linter and the formatter in read mode \e[0m\n \
\e[90m$$ \e[0;97;1mmake \e[0;92;1mdoc \e[0;90m➔ \e[32;3mgenerate the documentation of the project \e[0m\n \
\e[90m$$ \e[0;97;1mmake \e[0;92;1mtree \e[0;90m➔ \e[32;3mdisplay a tree visualization of the project's dependency graph \e[0m\n \
\e[90m$$ \e[0;97;1mmake \e[0;92;1mcompute \e[0;90m➔ \e[32;3mcompute 256 points on the secp256r1 elliptic curve\e[0m\n \
""" | sed -e 's/^[ \t ]\{1,\}\(.\)/ \1/'


Expand Down Expand Up @@ -111,8 +112,8 @@ lefthok-uninstall:
lint:
@runcmd forge fmt --check && npx solhint "{script,src,test}/**/*.sol"

.PHONY: lint-fix
lint-fix:
.PHONY: linter-fix
linter-fix:
@runcmd forge fmt && npx solhint "{script,src,test}/**/*.sol" --fix

.PHONY: prettier
Expand All @@ -123,6 +124,11 @@ prettier:
prettier-fix:
@runcmd npx prettier --write \"**/*.{json,md,yml}\"

# example: `c0=XXX c1=XXX make compute`
.PHONY: compute-points
compute-points:
@runcmd npx @0x90d2b2b7fb7599eebb6e7a32980857d8/secp256r1-computation $(c0) $(c1)

##########################################
################ ALIASES ################
##########################################
Expand All @@ -146,3 +152,4 @@ format: prettier
format-fix: prettier-fix
quality: lint format
install: install-dependencies lefthok-install
compute: compute-points
18 changes: 18 additions & 0 deletions script/BaseScript.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19 <0.9.0;

import { Script } from "../lib/forge-std/src/Script.sol";

abstract contract BaseScript is Script {
/// @notice this modifier can be used as a generic broadcast solution. It will automatically either:
/// - use the private key provided as an environment variable to broadcast
/// - or starts the hardware wallet flow if the correct flags are provided and the env variable is not set
modifier broadcast() {
uint256 privateKey = vm.envOr("PRIVATE_KEY", uint256(0));
privateKey != 0 ? vm.startBroadcast(privateKey) : vm.startBroadcast();

_;

vm.stopBroadcast();
}
}
36 changes: 36 additions & 0 deletions script/ComputePoints.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19 <0.9.0;

import { Script } from "./BaseScript.sol";
import { ECDSA256r1 } from "src/ECDSA256r1.sol";

/// @notice This script compute the points for ECDSA256r1 verification using the npm package
/// @dev The goal of this script is for composability. We want to allow people that install this project as dep'
/// to be able to use the computed points without having to install the associated npm package.
/// If you are contributing on this project, you should know you can use the npm package directly or
/// use the make command exposed for this purpose `c0=xxx c1=xxx make compute`
contract MyScript is Script {
function run() external returns (bytes memory points) {
uint256 c0 = vm.envUint("c0");
uint256 c1 = vm.envUint("c1");

// Compute a 8 dimensional table for Shamir's trick from c0 and c1
// and return the table as a bytes
string[] memory inputs = new string[](4);
inputs[0] = "npx";
inputs[1] = "@0x90d2b2b7fb7599eebb6e7a32980857d8/secp256r1-computation";
inputs[2] = vm.toString(c0);
inputs[3] = vm.toString(c1);
points = vm.ffi(inputs);
}
}

/*
ℹ️ HOW TO USE THIS SCRIPT:
c0=<C0> c1=<C1> forge script script/ComputePoints.s.sol:MyScript

example:
c0=18614955573315897657680976650685450080931919913269223958732452353593824192568 \
c1=9022311634785988016657019872538756956741425454756992532798853983315057399020 \
forge script script/ComputePoints.s.sol:MyScript
*/
49 changes: 49 additions & 0 deletions script/DeployEcdsa256r1.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19 <0.9.0;

import "./BaseScript.sol";

Check warning on line 4 in script/DeployEcdsa256r1.s.sol

View workflow job for this annotation

GitHub Actions / lint

global import of path ./BaseScript.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)

Check warning on line 4 in script/DeployEcdsa256r1.s.sol

View workflow job for this annotation

GitHub Actions / lint

global import of path ./BaseScript.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)
import { ECDSA256r1 } from "src/ECDSA256r1.sol";

contract LibraryWrapper {
function verify(bytes32 message, uint256 r, uint256 s, uint256 qx, uint256 qy) external returns (bool) {
return ECDSA256r1.verify(message, r, s, qx, qy);
}
}

/// @notice This script deploys the ECDSA256r1 library
contract MyScript is BaseScript {
function run() external broadcast returns (address addr) {
// deploy the library contract and return the address
addr = address(new LibraryWrapper());
}
}

/*

ℹ️ HOW TO USE THIS SCRIPT USING A LEDGER:
forge script script/DeployEcdsa256r1.s.sol:MyScript --rpc-url <RPC_URL> --ledger --sender <ACCOUNT_ADDRESS> \
[--broadcast]


ℹ️ HOW TO USE THIS SCRIPT WITH AN ARBITRARY PRIVATE KEY (NOT RECOMMENDED):
PRIVATE_KEY=<PRIVATE_KEY> forge script script/DeployEcdsa256r1.s.sol:MyScript --rpc-url <RPC_URL> [--broadcast]


ℹ️ HOW TO USE THIS SCRIPT ON ANVIL IN DEFAULT MODE:
forge script script/DeployEcdsa256r1.s.sol:MyScript --rpc-url http://127.0.0.1:8545 --broadcast --sender \
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --mnemonics "test test test test test test test test test test test junk"


ℹ️ HOW TO CALL THE LIBRARY ONCE DEPLOYED:
cast call <CONTRACT_ADDRESS> verify(bytes32,uint256,uint256,uint256,uint256)" <MESSAGE> <R> <S> <QX> <QY>

example:
cast call 0x5fbdb2315678afecb367f032d93f642f64180aa3 \
"verify(bytes32,uint256,uint256,uint256,uint256)" \
0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023 \
19738613187745101558623338726804762177711919211234071563652772152683725073944 \
34753961278895633991577816754222591531863837041401341770838584739693604822390 \
18614955573315897657680976650685450080931919913269223958732452353593824192568 \
90223116347859880166570198725387569567414254547569925327988539833150573990206

*/
56 changes: 56 additions & 0 deletions script/DeployEcdsa256r1Precompute.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19 <0.9.0;

import { BaseScript } from "./BaseScript.sol";
import { ECDSA256r1Precompute } from "src/ECDSA256r1Precompute.sol";

contract LibraryWrapper {
function verify(bytes32 message, uint256 r, uint256 s, address precomputedTable) external returns (bool) {
return ECDSA256r1Precompute.verify(message, r, s, precomputedTable);
}
}

/// @notice This script deploys the ECDSA256r1Precompute library
/// @dev The private key of the deployer is used to sign the transaction.
/// Favor using an hardware wallet instead of passing the private key as an environment variable
contract MyScript is BaseScript {
function run() external broadcast returns (address addr) {
// deploy the library contract and push the address in the stack
addr = address(new LibraryWrapper());
}
}

/*

ℹ️ HOW TO USE THIS SCRIPT USING A LEDGER:
forge script script/DeployEcdsa256r1Precompute.s.sol:MyScript --rpc-url <RPC_URL> --ledger \
--sender <ACCOUNT_ADDRESS> [--broadcast]


ℹ️ HOW TO USE THIS SCRIPT WITH AN ARBITRARY PRIVATE KEY (NOT RECOMMENDED):
PRIVATE_KEY=<PRIVATE_KEY> forge script script/DeployEcdsa256r1Precompute.s.sol:MyScript \
--rpc-url <RPC_URL> [--broadcast]


ℹ️ HOW TO USE THIS SCRIPT ON ANVIL IN DEFAULT MODE:
forge script script/DeployEcdsa256r1Precompute.s.sol:MyScript --rpc-url http://127.0.0.1:8545 --broadcast \
--sender 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 \
--mnemonics "test test test test test test test test test test test junk"


ℹ️ HOW TO CALL THE LIBRARY ONCE DEPLOYED:
cast call <CONTRACT_ADDRESS> verify(bytes32,uint256,uint256,address)" <MESSAGE> <R> <S> <PRECOMPILE_ADDRESS>

example:
cast call 0x2924909a71195b5d15de8c14ad676be369bfcbc3 \
"verify(bytes32,uint256,uint256,address)" \
0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023 \
19738613187745101558623338726804762177711919211234071563652772152683725073944 \
34753961278895633991577816754222591531863837041401341770838584739693604822390 \
0x5a0b3ddeb4deb241f7c2ee92ac5705d4d96a9cf3

Note: Use the `script/PrecomputePoints.s.sol` script, the npm script or the make command to
generate the precomputed points then deploy them using the `script/DeployPrecomputePoints.s.sol`
forge script to get the address of the contrat to pass as the last argument of the verify function.

*/
70 changes: 70 additions & 0 deletions script/DeployPrecomputePoints.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19 <0.9.0;

import { BaseScript } from "./BaseScript.sol";

error FailedToDeployPrecompiled();

/// @notice This script deploys the precomputed points on-chain
contract MyScript is BaseScript {
//---------------------------------------------------------------------------------------------------------------//
// Opcode | Opcode + Arguments | Description | Stack View //
//---------------------------------------------------------------------------------------------------------------//
// 0x60 | 0x600B | PUSH1 11 | codeOffset //
// 0x59 | 0x59 | MSIZE | 0 codeOffset //
// 0x81 | 0x81 | DUP2 | codeOffset 0 codeOffset //
// 0x38 | 0x38 | CODESIZE | codeSize codeOffset 0 codeOffset //
// 0x03 | 0x03 | SUB | (codeSize - codeOffset) 0 codeOffset //
// 0x80 | 0x80 | DUP | (codeSize - codeOffset) (codeSize - codeOffset) 0 codeOffset //
// 0x92 | 0x92 | SWAP3 | codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) //
// 0x59 | 0x59 | MSIZE | 0 codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) //
// 0x39 | 0x39 | CODECOPY | 0 (codeSize - codeOffset) //
// 0xf3 | 0xf3 | RETURN | //
//---------------------------------------------------------------------------------------------------------------//
bytes private constant CONSTRUCTION_CODE = hex"600B5981380380925939F3";

function run() external broadcast returns (address precompiledAddress) {
// Precompiled points calculated off-chain. See the `@0x90d2b2b7fb7599eebb6e7a32980857d8/secp256r1-computation`
// npm package
bytes memory precomputedPoints = vm.envBytes("PRECOMPUTED_POINTS");

// append the construction code to the precomputed points and deploy the creation code
bytes memory creationCode = abi.encodePacked(
CONSTRUCTION_CODE, // Returns all code in the contract except for the first 11 (0B in hex) bytes.
precomputedPoints // The runtime code. Capped at the code size limit.
);

uint256 precomputedCode;
assembly ("memory-safe") {

Check warning on line 38 in script/DeployPrecomputePoints.s.sol

View workflow job for this annotation

GitHub Actions / lint

Avoid to use inline assembly. It is acceptable only in rare cases

Check warning on line 38 in script/DeployPrecomputePoints.s.sol

View workflow job for this annotation

GitHub Actions / lint

Avoid to use inline assembly. It is acceptable only in rare cases
// Deploy a new contract with the generated creation code.
precompiledAddress := create(0, add(creationCode, 32), mload(creationCode))
precomputedCode := extcodesize(precompiledAddress)
}

// Check that the precompiled contract was deployed correctly
if (precomputedCode == 0) revert FailedToDeployPrecompiled();
}
}

/*

ℹ️ HOW TO USE THIS SCRIPT USING A LEDGER:
PRECOMPUTED_POINTS=<VALUE> forge script script/DeployPrecomputePoints.s.sol:MyScript --rpc-url <RPC_URL> --ledger \
--sender <ACCOUNT_ADDRESS> [--broadcast]


ℹ️ HOW TO USE THIS SCRIPT WITH AN ARBITRARY PRIVATE KEY (NOT RECOMMENDED):
PRECOMPUTED_POINTS=<VALUE> PRIVATE_KEY=<PRIVATE_KEY> forge script script/DeployPrecomputePoints.s.sol:MyScript \
--rpc-url <RPC_URL> [--broadcast]


ℹ️ HOW TO USE THIS SCRIPT ON ANVIL IN DEFAULT MODE:
PRECOMPUTED_POINTS=<VALUE> forge script script/DeployPrecomputePoints.s.sol:MyScript --rpc-url \
http://127.0.0.1:8545 --broadcast --sender 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 \
--mnemonics "test test test test test test test test test test test junk"


ℹ️ HOW TO CHECK THE DEPLOYED CODE:
cast code <CONTRACT_ADDRESS> --rpc-url <RPC_URL>

*/
Loading