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

Alpha Implementation of Specification #129

Merged
merged 30 commits into from
Apr 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3cddd7e
Remove last references to push and delete caps
JakeOShannessy Mar 26, 2019
5bd56e8
Update proc table and cap formats (no minting)
JakeOShannessy Mar 27, 2019
ee605d0
Test updates for new formats.
JakeOShannessy Mar 27, 2019
a55bde7
Implement maximal caps
JakeOShannessy Mar 28, 2019
beda7f6
Implement subsets
JakeOShannessy Mar 28, 2019
24b911c
Test registration of Call caps
JakeOShannessy Apr 1, 2019
9187bf6
Test registration of Write caps
JakeOShannessy Apr 1, 2019
a1e8dfd
Test registration of Log caps
JakeOShannessy Apr 1, 2019
d636c66
Various test fixes and redesign
JakeOShannessy Apr 1, 2019
bdaf45c
Critical fix for Delete cap
JakeOShannessy Apr 1, 2019
c94beb1
Minor test fixes
JakeOShannessy Apr 1, 2019
68f728b
Remove Procedure struct from registration path
JakeOShannessy Apr 8, 2019
948c040
Add some utility functions for tests
JakeOShannessy Apr 8, 2019
28f61eb
Test procedure re-registration
JakeOShannessy Apr 8, 2019
5601e43
Remove erroneous .only
JakeOShannessy Apr 8, 2019
99bdad1
Correct error code
JakeOShannessy Apr 8, 2019
d890d88
Test zeroing of clists at registration (see #129 for: at deletion).
JakeOShannessy Apr 8, 2019
fba5042
Remove old hack for tests
JakeOShannessy Apr 8, 2019
ae291ac
Fix SetEntry tests
JakeOShannessy Apr 8, 2019
1f6e7b0
Missing changes from last commit
JakeOShannessy Apr 9, 2019
c8dbdcb
Restructure files and inheritance
JakeOShannessy Apr 9, 2019
8626bf5
Update tests to restructure
JakeOShannessy Apr 9, 2019
f3b6ef3
Added missing files
JakeOShannessy Apr 9, 2019
67010c6
Remove deprecated error values
JakeOShannessy Apr 9, 2019
e6c8626
Set the kernel address in preparation for execution guard
JakeOShannessy Apr 9, 2019
8899a4d
Constructor bootstrap proof-of-concept.
JakeOShannessy Apr 9, 2019
4a78d28
Add KernelInstance.sol
JakeOShannessy Apr 9, 2019
e60eeaf
Set the kernel address in the constructor.
JakeOShannessy Apr 9, 2019
10b2650
Address comments
JakeOShannessy Apr 10, 2019
95b30db
Add missing arrow to architecture diagram
JakeOShannessy Apr 10, 2019
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
362 changes: 316 additions & 46 deletions beakerlib/index.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions contracts/BasicEntryProcedure.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ contract BasicEntryProcedure {
// First set up the input data (at memory location 0x0)
// The call call is 0x-03
mstore(add(ins,0x0),0x03)
// The capability index is 0x-02
mstore(add(ins,0x20),0x02)
// The capability index is 0x-00 (the 0th proc call cap)
mstore(add(ins,0x20),0x00)
// The key of the procedure
// mstore(add(ins,0x40),0) // clear
mstore(add(ins,0x40),div(procedureKey,0x10000000000000000))
Expand Down
31 changes: 20 additions & 11 deletions contracts/BeakerContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ pragma solidity ^0.4.17;

import "./Kernel.sol";
import "./ProcedureTable.sol";
import "./KernelStorage.sol";

contract BeakerContract is IKernel {

function this_proc() internal view returns (ProcedureTable.Procedure memory) {
return ProcedureTable._getProcedureByKey(uint192(currentProcedure));
function this_proc() internal view returns (Procedure memory) {
return _getProcedureByKey(_getCurrentProcedure());
}

// TODO: this doesn't actually use caps, just reads raw
Expand Down Expand Up @@ -260,6 +261,15 @@ contract BeakerContract is IKernel {
uint256 retSize = retInput.length;

assembly {
function malloc(size) -> result {
// align to 32-byte words
let rsize := add(size,sub(32,mod(size,32)))
// get the current free mem location
result := mload(0x40)
// Bump the value of 0x40 so that it holds the next
// available memory location.
mstore(0x40,add(result,rsize))
}
let ins := add(input, 0x20)
// First set up the input data (at memory location 0x0)
// The register syscall is 4
Expand All @@ -278,16 +288,15 @@ contract BeakerContract is IKernel {
// "in_offset" is at 31, because we only want the last byte of type
// "in_size" is 97 because it is 1+32+32+32
// we will store the result at 0x80 and it will be 32 bytes
let retLoc := add(retInput, 0x20)
err := 0
if iszero(delegatecall(gas, caller, add(ins,31), inSize, retLoc, retSize)) {
err := add(2200, mload(retLoc))
if nCapKeys {
err := add(77,mul(100,mload(retLoc)))
}
mstore(0xd, err)
revert(0xd,retSize)
let status := delegatecall(gas, caller, add(ins,31), inSize, 0, 0)
let retLoc := malloc(returndatasize)
returndatacopy(retLoc,0,returndatasize)
if iszero(status) {
revert(retLoc,returndatasize)
}
// Here we will just take the first 32 bytes of the return data.
err := mload(retLoc)
}
return err;
}
Expand Down Expand Up @@ -351,7 +360,7 @@ contract BeakerContract is IKernel {
}
return err;
}
function proc_log1(uint8 capIndex, uint32 t1, uint32 value) internal returns (uint32 err) {
function proc_log1(uint8 capIndex, bytes32 t1, bytes32 value) internal returns (uint32 err) {

bytes memory input = new bytes(5 * 0x20);
bytes memory ret = new bytes(0x20);
Expand Down
277 changes: 277 additions & 0 deletions contracts/CapabilityManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
pragma solidity ^0.4.17;

import "./Factory.sol";
import "./ProcedureTable.sol";

contract CapabilityManager is ProcedureTable {

// CAPABILITY_TYPES
uint8 constant CAP_PROC_CALL = 3;
uint8 constant CAP_PROC_REGISTER = 4;
uint8 constant CAP_PROC_DELETE = 5;
uint8 constant CAP_PROC_ENTRY = 6;
uint8 constant CAP_STORE_WRITE = 7;
uint8 constant CAP_LOG = 8;
uint8 constant CAP_ACC_CALL = 9;

function checkRegisterCapability(uint192 currentProcedure, bytes24 procedureKey, uint256 reqCapIndex) internal view returns (bool) {

uint256 capType = CAP_PROC_REGISTER;
// Storage key of the current procedure on the procedure heap
uint256 currentProcPointer = _getPointerProcHeapByName(currentProcedure);
// How many Procedure Call capabilities does the current procedure have?
uint256 nCaps = _get(currentProcPointer | (capType*0x10000));
// If the requested cap is out of the bounds of the cap list, we
// clearly don't have the capability;
if (reqCapIndex+1 > nCaps) {
return false;
}
// A procedure call capabilities stores a single 32-byte value at 0x00.
uint256 value = _get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x00);
// This value has to be destructured to get 2 values, a prefix length
// and a base address.
uint8 prefix;
bytes24 baseKey;
bytes24 clearedBaseKey;
bytes24 clearedReqKey;
assembly {
// Shift the 32-byte value to the right to obtain the first byte only
prefix := div(value,0x100000000000000000000000000000000000000000000000000000000000000)
// Shift the value to get the procedure key left align (as it should
// be for compatibility with bytes24).
baseKey := mul(value,0x10000000000000000)
let q := signextend(1,2)
// h is a large number we will use for arithmetic
let h := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// y is a number with $prefix 1s at the start
let y := mul(h,exp(2,sub(256,prefix)))
clearedBaseKey := and(y,baseKey)
clearedReqKey := and(y,procedureKey)
}
return clearedBaseKey == clearedReqKey;
}

function checkDeleteCapability(uint192 currentProcedure, bytes24 procedureKey, uint256 reqCapIndex) internal view returns (bool) {

uint256 capType = CAP_PROC_DELETE;
// Storage key of the current procedure on the procedure heap
uint256 currentProcPointer = _getPointerProcHeapByName(currentProcedure);
// How many Procedure Call capabilities does the current procedure have?
uint256 nCaps = _get(currentProcPointer | (capType*0x10000));
// If the requested cap is out of the bounds of the cap list, we
// clearly don't have the capability;
if (reqCapIndex+1 > nCaps) {
return false;
}
// A procedure delete capability stores a single 32-byte value at 0x00.
uint256 value = _get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x00);
// This value has to be destructured to get 2 values, a prefix length
// and a base address.
uint8 prefix;
bytes24 baseKey;
bytes24 clearedBaseKey;
bytes24 clearedReqKey;
assembly {
// Shift the 32-byte value to the right to obtain the first byte only
prefix := div(value,0x100000000000000000000000000000000000000000000000000000000000000)
// Shift the value to get the procedure key left align (as it should
// be for compatibility with bytes24).
baseKey := mul(value,0x10000000000000000)
let q := signextend(1,2)
// h is a large number we will use for arithmetic
let h := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// y is a number with $prefix 1s at the start
let y := mul(h,exp(2,sub(256,prefix)))
clearedBaseKey := and(y,baseKey)
clearedReqKey := and(y,procedureKey)
}
return clearedBaseKey == clearedReqKey;
}

function checkSetEntryCapability(uint192 currentProcedure, uint256 reqCapIndex) internal view returns (bool) {
uint256 capType = CAP_PROC_ENTRY;
// Storage key of the current procedure on the procedure heap
uint256 currentProcPointer = _getPointerProcHeapByName(currentProcedure);
// How many Write capabilities does the current procedure have?
uint256 nCaps = _get(currentProcPointer | (capType*0x10000));
// If the requested cap is out of the bounds of the cap list, we
// clearly don't have the capability.
// NB: Even though all set entry caps are identical, if you ask for an
// index that doesn't exist, we will still return false. This implies
// that you should always ask for the cap at index zero to be on the
// safe side.
if (reqCapIndex+1 > nCaps) {
return false;
} else {
return true;
}
// A set entry capability has no values
}

function checkCallCapability(uint192 currentProcedure, bytes24 procedureKey, uint256 reqCapIndex) internal view returns (bool) {

uint256 capType = CAP_PROC_CALL;
// Storage key of the current procedure on the procedure heap
uint256 currentProcPointer = _getPointerProcHeapByName(currentProcedure);
// How many Procedure Call capabilities does the current procedure have?
uint256 nCaps = _get(currentProcPointer | (capType*0x10000));
// If the requested cap is out of the bounds of the cap list, we
// clearly don't have the capability;
if (reqCapIndex+1 > nCaps) {
return false;
}
// A procedure call capabilities stores a single 32-byte value at 0x00.
uint256 value = _get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x00);
// This value has to be destructured to get 2 values, a prefix length
// and a base address.
uint8 prefix;
bytes24 baseKey;
bytes24 clearedBaseKey;
bytes24 clearedReqKey;
assembly {
// Shift the 32-byte value to the right to obtain the first byte only
prefix := div(value,0x100000000000000000000000000000000000000000000000000000000000000)
// Shift the value to get the procedure key left align (as it should
// be for compatibility with bytes24).
baseKey := mul(value,0x10000000000000000)
let q := signextend(1,2)
// h is a large number we will use for arithmetic
let h := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// y is a number with $prefix 1s at the start
let y := mul(h,exp(2,sub(256,prefix)))
clearedBaseKey := and(y,baseKey)
clearedReqKey := and(y,procedureKey)
}
return clearedBaseKey == clearedReqKey;
}

function checkAccCallCapability(uint192 currentProcedure, address account, uint256 amount, uint256 reqCapIndex) internal view returns (bool) {
uint256 capType = CAP_ACC_CALL;
// Storage key of the current procedure on the procedure heap
uint256 currentProcPointer = _getPointerProcHeapByName(currentProcedure);
// How many Write capabilities does the current procedure have?
uint256 nCaps = _get(currentProcPointer | (capType*0x10000));
// If the requested cap is out of the bounds of the cap list, we
// clearly don't have the capability;
if (reqCapIndex+1 > nCaps) {
return false;
}
// A write capability has 2-3 values, callAny: Boolean, sendValue: Boolean,
// and ethAddress: EthereumAddress. ethAddress is only defined if
// callAny is false. These values are packed into a single 32-byte value.
uint256 value = _get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x00);
// This value has to be destructured to get 2 values, a prefix length
// and a base address.
// The two flags, callAny and sendValue are stored in the first byte
// (which we will call the flagByte).
uint8 flagByte;
assembly {
flagByte := byte(0,value)
}

// Select the first bit
// Solidity does not allow conversion of ints to bools, so we do it
// explicitly.
bool callAny;
if ((flagByte & 0x80) > 0) { // 0x80 == 0b100000000;
callAny = true;
}
// Select the second bit
// Solidity does not allow conversion of ints to bools, so we do it
// explicitly.
bool sendValue;
if ((flagByte & 0x40) > 0) { // 0x40 == 0b010000000;
sendValue = true;
}

// We probably don't need to clear these bits, but it is defensive coding.
address ethAddress = address(value & 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff); // clear all but last 20-bytes

// If callAny is false (0) and ethAddress does not match the requested
// account, return false
if (!callAny && (ethAddress != account)) {
return false;
}

// If sendValue is false (0) and amount is non-zero, return false
if (!sendValue && (amount != 0)) {
return false;
}

// Otherwise return true
return true;
}

function checkWriteCapability(uint192 currentProcedure, uint256 toStoreAddress, uint256 reqCapIndex) internal view returns (bool) {
uint256 capType = CAP_STORE_WRITE;
// Storage key of the current procedure on the procedure heap
uint256 currentProcPointer = _getPointerProcHeapByName(currentProcedure);
// How many Write capabilities does the current procedure have?
uint256 nCaps = _get(currentProcPointer | (capType*0x10000));
// If the requested cap is out of the bounds of the cap list, we
// clearly don't have the capability;
if (reqCapIndex+1 > nCaps) {
return false;
}
// A write capability has two values, address and size. Address is at
// 0x00 and size is at 0x01.
uint256 addr = _get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x00);
uint256 size = _get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x01);

// If the store addess is within the range return true, else false
return (toStoreAddress >= addr && toStoreAddress <= (addr + size));
}

function checkLogCapability(uint192 currentProcedure, bytes32[] reqTopics, uint256 reqCapIndex) internal view returns (bool) {
uint256 capType = CAP_LOG;
// Storage key of the current procedure on the procedure heap
uint256 currentProcPointer = _getPointerProcHeapByName(currentProcedure);
// How many Write capabilities does the current procedure have?
uint256 nCaps = _get(currentProcPointer | (capType*0x10000));
// If the requested cap is out of the bounds of the cap list, we
// clearly don't have the capability;
if (reqCapIndex+1 > nCaps) {
return false;
}
// A log capability has 5 values. The first is the number of topics
// specified and must be in the range [0,4]. The next 4 values are the
// values that those log topics are required to be.

uint256 nTopics = _get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x00);
bytes32 topic1 = bytes32(_get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x01));
bytes32 topic2 = bytes32(_get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x02));
bytes32 topic3 = bytes32(_get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x03));
bytes32 topic4 = bytes32(_get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x04));

// Check that all of the topics required by the cap are satisfied. That
// is, for every topic in the capability, the corresponding exists in
// the system call and is set to that exact value. First we check that
// there are enough topics in the request.
if (reqTopics.length < nTopics) {
// The system call specifies an insufficient number of topics
return false;
}

if (nTopics >= 1) {
if (reqTopics[0] != topic1) {
return false;
}
}
if (nTopics >= 2) {
if (reqTopics[1] != topic2) {
return false;
}
}
if (nTopics >= 3) {
if (reqTopics[2] != topic3) {
return false;
}
}
if (nTopics >= 4) {
if (reqTopics[3] != topic4) {
return false;
}
}
return true;
}
}
6 changes: 3 additions & 3 deletions contracts/Factory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ contract Factory {
if((ins == 0x20)){continue;} // SHA3
if((ins >= 0x30 && ins <= 0x3e)){continue;} // Environmental Informatio
if((ins >= 0x40 && ins <= 0x45)){continue;} // Block Information
if((ins >= 0x50 && ins <= 0x53)){continue;} // Stack, Memory, Storage and Flow Operation
if((ins >= 0x50 && ins <= 0x53)){continue;} // Stack, Memory, Storage and Flow Operation
if((ins >= 0x56 && ins <= 0x5b)){continue;} // Stack, Memory, Storage and Flow Operation
if((ins >= 0x80 && ins <= 0x8f)){continue;} // Duplication Operations
if((ins >= 0x90 && ins <= 0x9f)){continue;} // Exchange Operations
Expand Down Expand Up @@ -74,10 +74,10 @@ contract Factory {
if (ins == 0xf5) {return 12;} // CREATE2
if (ins == 0xff) {return 13;} // SELFDESTRUCT



return 100; // UNKNOWN OPCODE

}
return 0;
}
Expand Down
Loading