Skip to content

Commit

Permalink
-\_O?
Browse files Browse the repository at this point in the history
  • Loading branch information
pmerkleplant committed Dec 18, 2023
1 parent c0107f8 commit 434be0a
Show file tree
Hide file tree
Showing 10 changed files with 314 additions and 132 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@

> **Warning**
>
> Still in early development. Don't use yet except you know what your doing!
> Still in early development.
> Don't use yet except you know what your doing!
>
> Expect breaking changes!
`crysol` is a set of Solidity libraries providing **clean** and **well-tested** implementations of cryptographic algorithms.
`crysol` is a collection of pure Solidity libraries providing clean
implementations of cryptographic algorithms for on- and offchain usage.

Differentiating to other projects, `crysol` also provides functionality to create cryptographic objects.

## Installation

Expand Down
19 changes: 13 additions & 6 deletions docs/Intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,26 @@

## What are `vmed` functions?

Traditionally, Solidity has been primarily used for verifying cryptographic objects and rarely for creating them, eg we verify ECDSA signatures in Solidity via `ecrecover` and create them via our non-Solidity based wallet libraries.
Traditionally, Solidity has been primarily used for verifying cryptographic
objects and rarely for creating them, eg we verify ECDSA signatures in Solidity
via `ecrecover` and create them via our non-Solidity based wallet libraries.

`crysol` takes a more comprehensive approach and also provides functionality to create cryptographic objects, allowing developers to test and experiment with cryptographic systems from within their Solidity environment.
`crysol` takes a more comprehensive approach and also provides functionality to
create cryptographic objects, allowing developers to test and research
cryptographic systems in a pure EVM environment.

However, most Solidity code is run on public blockchains - the last place one should perform operations requiring a private key as input.
However, most Solidity code is run on public blockchains - the last place one
should perform operations requiring a secret key as input.

To ensure operations using sensitive data are never run on non-local blockchains such functions are "`vmed`", meaning they revert whenever the blockchain's chain id is not `31337`.
To ensure operations using sensitive data are never run on non-local blockchains
such functions are "`vmed`", meaning they revert whenever the chain id is not `31337`.


## The Prelude

Many libraries include a code block called _prelude_ providing common internal functionality.
It provides the `vmed` modifier which protects certain functions from being called in non-local environments.
Many libraries include a code block called _prelude_ providing common internal
functionality such as the `vmed` modifier which protects certain functions from
being called in non-local environments.

The _prelude_ code is:

Expand Down
85 changes: 47 additions & 38 deletions examples/stealth-addresses/StealthSecp256k1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
pragma solidity ^0.8.16;

import {Script} from "forge-std/Script.sol";
import {StdStyle} from "forge-std/StdStyle.sol";
import {console2 as console} from "forge-std/console2.sol";

import {Secp256k1, SecretKey, PublicKey} from "src/curves/Secp256k1.sol";

import {
StealthSecp256k1,
StealthAddress,
Expand All @@ -15,95 +18,101 @@ import {
ERC5564Announcer
} from "src/stealth-addresses/ERC5564Announcer.sol";

import {Secp256k1, PrivateKey, PublicKey} from "src/curves/Secp256k1.sol";

contract StealthSecp256k1Example is Script {
using StealthSecp256k1 for PrivateKey;
using StealthSecp256k1 for SecretKey;
using StealthSecp256k1 for StealthAddress;
using StealthSecp256k1 for StealthMetaAddress;

using Secp256k1 for PrivateKey;
using Secp256k1 for SecretKey;
using Secp256k1 for PublicKey;

function run() public {
// Sender key pair.
console.log("Sender: Creates key pair");
PrivateKey senderPrivKey = Secp256k1.newPrivateKey();
PublicKey memory senderPubKey = senderPrivKey.toPublicKey();
SecretKey senderSk = Secp256k1.newSecretKey();
PublicKey memory senderPk = senderSk.toPublicKey();
logSender("Created key pair");

// Receiver key pairs consist of spending and viewing key pairs.
console.log("Receiver: Creates key pairs");
PrivateKey receiverSpendingPrivKey = Secp256k1.newPrivateKey();
PublicKey memory receiverSpendingPubKey =
receiverSpendingPrivKey.toPublicKey();
PrivateKey receiverViewPrivKey = Secp256k1.newPrivateKey();
PublicKey memory receiverViewPubKey = receiverViewPrivKey.toPublicKey();
SecretKey receiverSpendSk = Secp256k1.newSecretKey();
PublicKey memory receiverSpendPk = receiverSpendSk.toPublicKey();
SecretKey receiverViewSk = Secp256k1.newSecretKey();
PublicKey memory receiverViewPk = receiverViewSk.toPublicKey();
logReceiver("Created key pair");

// There exists an ERC5564Announcer instance.
IERC5564Announcer announcer = IERC5564Announcer(new ERC5564Announcer());

// Receiver creates their stealth meta address.
// TODO: Note that these addresses need to be published somehow.
console.log("Receiver: Creates stealth meta address");
StealthMetaAddress memory receiverStealthMeta;
receiverStealthMeta = StealthMetaAddress({
spendingPubKey: receiverSpendingPubKey,
viewingPubKey: receiverViewPubKey
StealthMetaAddress memory receiverSma = StealthMetaAddress({
spendPk: receiverSpendPk,
viewPk: receiverViewPk
});
console.log("Stealth Meta Address: ");
console.logBytes(receiverStealthMeta.toBytes("eth"));
logReceiver(
string.concat(
"Created Ethereum stealth meta address: ", receiverSma.toString("eth")
)
);

// Sender creates stealth address from receiver's stealth meta address.
console.log(
"Sender: Creates stealth address based on receiver's meta address"
);
// TODO: receiver's stealh address must be argument for function, not
// an object to call a function on.
StealthAddress memory stealth = receiverStealthMeta.newStealthAddress();
StealthAddress memory stealth = receiverSma.newStealthAddress();
logSender("Created stealth address from receiver's stealth meta address");

// Sender sends ETH to stealth.
console.log("Sender: Sends ETH to receiver's stealth address");
vm.deal(senderPubKey.toAddress(), 1 ether);
vm.prank(senderPubKey.toAddress());
vm.deal(senderPk.toAddress(), 1 ether);
vm.prank(senderPk.toAddress());
(bool ok, ) = stealth.recipient.call{value: 1 ether}("");
require(ok, "Sender: ETH transfer failed");
logSender("Send 1 ETH to stealth address");

// Sender announces tx via ERC5564Announcer.
console.log("Sender: Announces tx via ERC5564Announcer");
vm.prank(senderPubKey.toAddress());
vm.prank(senderPk.toAddress());
announcer.announce({
schemeId: SCHEME_ID,
stealthAddress: stealth.recipient,
ephemeralPubKey: stealth.ephemeralPubKey.toBytes(),
ephemeralPubKey: stealth.ephPk.toBytes(),
// See ERC5564Announcer.sol for more info.
metadata: abi.encodePacked(
stealth.viewTag,
hex"eeeeeeee",
hex"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
uint(1 ether)
)
)
});
logSender("Announced tx via ERC-5564 announcer");

// Receiver checks announces stealth address.
console.log("Receiver: Verifies tx is based on own meta address");
require(
receiverViewPrivKey.checkStealthAddress(
receiverSpendingPubKey, stealth
),
receiverViewSk.checkStealthAddress(receiverSpendPk, stealth),
"Check failed"
);
logReceiver("Verfied tx is based on own stealth meta address");

// Receiver computed stealth's private key.
console.log("Receiver: Computes private key for stealth address");
PrivateKey stealthPrivKey = receiverSpendingPrivKey
.computeStealthPrivateKey(receiverViewPrivKey, stealth);
SecretKey stealthSk = receiverSpendSk
.computeStealthSecretKey(receiverViewSk, stealth);

// Verify computed private key's address matches stealth's recipient
// address.
console.log("Receiver: Verifies access on stealth address");
require(
stealthPrivKey.toPublicKey().toAddress() == stealth.recipient,
stealthSk.toPublicKey().toAddress() == stealth.recipient,
"Private key computation failed"
);
}

function logSender(string memory message) internal {
console.log(
string.concat(StdStyle.yellow("[SENDER] "), message)
);
}

function logReceiver(string memory message) internal {
console.log(
string.concat(StdStyle.blue("[RECEIVER] "), message)
);
}
}
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ffi = true
# Compilation
evm_version = "shanghai"
solc_version = "0.8.23"
via_ir = false
via_ir = true
optimizer = false
extra_output_files = ["irOptimized"]

Expand Down
2 changes: 1 addition & 1 deletion src/curves/Secp256k1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
import {Random} from "../Random.sol";

/**
* @notice Secret key is an secp256k1 secret key
* @notice SecretKey is an secp256k1 secret key
*
* @dev Note that a secret key MUST be a field element, ie sk ∊ [1, Q).
*
Expand Down
Loading

0 comments on commit 434be0a

Please sign in to comment.