Commit 28920a00 authored by George Hotz's avatar George Hotz

large hash oracle works

parent e4dfa8ab
...@@ -39,16 +39,20 @@ contract MIPSMemory { ...@@ -39,16 +39,20 @@ contract MIPSMemory {
struct LargePreimage { struct LargePreimage {
uint offset; uint offset;
uint len;
uint32 data;
} }
mapping(address => LargePreimage) public largePreimage; mapping(address => LargePreimage) public largePreimage;
// sadly due to soldiity limitations this can't be in the LargePreimage struct // sadly due to soldiity limitations this can't be in the LargePreimage struct
mapping(address => uint64[25]) public largePreimageState; mapping(address => uint64[25]) public largePreimageState;
function AddLargePreimageInit(uint offset) public { function AddLargePreimageInit(uint offset) public {
require(offset & 3 == 0, "offset must be 32-bit aligned");
Lib_Keccak256.CTX memory c; Lib_Keccak256.CTX memory c;
Lib_Keccak256.keccak_init(c); Lib_Keccak256.keccak_init(c);
largePreimageState[msg.sender] = c.A; largePreimageState[msg.sender] = c.A;
largePreimage[msg.sender].offset = offset; largePreimage[msg.sender].offset = offset;
largePreimage[msg.sender].len = 0;
} }
// TODO: input 136 bytes, as many times as you'd like // TODO: input 136 bytes, as many times as you'd like
...@@ -58,30 +62,66 @@ contract MIPSMemory { ...@@ -58,30 +62,66 @@ contract MIPSMemory {
// sha3_process_block // sha3_process_block
Lib_Keccak256.CTX memory c; Lib_Keccak256.CTX memory c;
c.A = largePreimageState[msg.sender]; c.A = largePreimageState[msg.sender];
int offset = int(largePreimage[msg.sender].offset) - int(largePreimage[msg.sender].len);
if (offset >= 0 && offset < 136) {
largePreimage[msg.sender].data =
uint32(uint8(dat[uint256(offset)+0])) << 24 |
uint32(uint8(dat[uint256(offset)+1])) << 16 |
uint32(uint8(dat[uint256(offset)+2])) << 8 |
uint32(uint8(dat[uint256(offset)+3])) << 0;
}
Lib_Keccak256.sha3_xor_input(c, dat); Lib_Keccak256.sha3_xor_input(c, dat);
Lib_Keccak256.sha3_permutation(c); Lib_Keccak256.sha3_permutation(c);
largePreimageState[msg.sender] = c.A; largePreimageState[msg.sender] = c.A;
largePreimage[msg.sender].len += 136;
} }
// TODO: input <136 bytes and do the end of hash | 0x01 / | 0x80 // TODO: input <136 bytes and do the end of hash | 0x01 / | 0x80
function AddLargePreimageFinal(bytes calldata dat) public view returns (bytes32) { function AddLargePreimageFinal(bytes calldata idat) public view returns (bytes32, uint, uint32) {
require(dat.length < 136, "final must be less than 136"); require(idat.length < 136, "final must be less than 136");
int offset = int(largePreimage[msg.sender].offset) - int(largePreimage[msg.sender].len);
require(offset < 136, "offset must be less than 136");
Lib_Keccak256.CTX memory c; Lib_Keccak256.CTX memory c;
c.A = largePreimageState[msg.sender]; c.A = largePreimageState[msg.sender];
bytes memory fdat = new bytes(136); console.log(idat.length);
for (uint i = 0; i < dat.length; i++) {
fdat[i] = dat[i]; bytes memory dat = new bytes(136);
for (uint i = 0; i < idat.length; i++) {
dat[i] = idat[i];
}
uint len = largePreimage[msg.sender].len + idat.length;
uint32 data = largePreimage[msg.sender].data;
if (offset >= 0) {
// comes from this block
data =
uint32(uint8(dat[uint256(offset)+0])) << 24 |
uint32(uint8(dat[uint256(offset)+1])) << 16 |
uint32(uint8(dat[uint256(offset)+2])) << 8 |
uint32(uint8(dat[uint256(offset)+3])) << 0;
} }
fdat[135] = bytes1(uint8(0x80)); dat[135] = bytes1(uint8(0x80));
fdat[dat.length] |= bytes1(uint8(0x1)); dat[idat.length] |= bytes1(uint8(0x1));
Lib_Keccak256.sha3_xor_input(c, fdat); Lib_Keccak256.sha3_xor_input(c, dat);
Lib_Keccak256.sha3_permutation(c); Lib_Keccak256.sha3_permutation(c);
// TODO: do this properly and save the hash bytes32 outhash = Lib_Keccak256.get_hash(c);
// when this is updated, it won't be "view" return (outhash, len, data);
return Lib_Keccak256.get_hash(c); }
function AddLargePreimageFinalSaved(bytes calldata idat) public {
bytes32 outhash;
uint len;
uint32 data;
(outhash, len, data) = AddLargePreimageFinal(idat);
Preimage storage p = preimage[outhash];
require(p.length == 0 || p.length == len, "length is somehow wrong");
require(largePreimage[msg.sender].offset < len, "offset is beyond length");
p.length = len;
p.data[largePreimage[msg.sender].offset] = (1 << 32) | data;
} }
function tb(uint32 dat) internal pure returns (bytes memory) { function tb(uint32 dat) internal pure returns (bytes memory) {
......
...@@ -2,13 +2,12 @@ const { keccak256 } = require("@ethersproject/keccak256"); ...@@ -2,13 +2,12 @@ const { keccak256 } = require("@ethersproject/keccak256");
const { expect } = require("chai"); const { expect } = require("chai");
describe("MIPSMemory contract", function () { describe("MIPSMemory contract", function () {
it("Keccak should work", async function () { beforeEach(async function () {
const [owner] = await ethers.getSigners();
const MIPSMemory = await ethers.getContractFactory("MIPSMemory"); const MIPSMemory = await ethers.getContractFactory("MIPSMemory");
const mm = await MIPSMemory.deploy(); mm = await MIPSMemory.deploy();
console.log("deployed at", mm.address, "by", owner.address); console.log("deployed at", mm.address);
})
it("Keccak should work", async function () {
await mm.AddLargePreimageInit(0); await mm.AddLargePreimageInit(0);
console.log("preimage initted"); console.log("preimage initted");
...@@ -17,7 +16,7 @@ describe("MIPSMemory contract", function () { ...@@ -17,7 +16,7 @@ describe("MIPSMemory contract", function () {
const test = new Uint8Array(n) const test = new Uint8Array(n)
for (var i = 0; i < n; i++) test[i] = 0x62; for (var i = 0; i < n; i++) test[i] = 0x62;
console.log("test size", n) console.log("test size", n)
expect(await mm.AddLargePreimageFinal(test)).to.equal(keccak256(test)); expect((await mm.AddLargePreimageFinal(test))[0]).to.equal(keccak256(test));
} }
await tl(0) await tl(0)
await tl(100) await tl(100)
...@@ -29,7 +28,7 @@ describe("MIPSMemory contract", function () { ...@@ -29,7 +28,7 @@ describe("MIPSMemory contract", function () {
dat[0] = 0x61 dat[0] = 0x61
await mm.AddLargePreimageUpdate(dat); await mm.AddLargePreimageUpdate(dat);
const hash = await mm.AddLargePreimageFinal([]); const hash = (await mm.AddLargePreimageFinal([]))[0];
console.log("preimage updated"); console.log("preimage updated");
const realhash = keccak256(dat); const realhash = keccak256(dat);
...@@ -37,4 +36,16 @@ describe("MIPSMemory contract", function () { ...@@ -37,4 +36,16 @@ describe("MIPSMemory contract", function () {
console.log("real hash is", realhash); console.log("real hash is", realhash);
expect(hash).to.equal(realhash); expect(hash).to.equal(realhash);
}); });
it("oracle save should work", async function () {
await mm.AddLargePreimageInit(4)
let dat = new TextEncoder("utf-8").encode("hello world")
const tst = await mm.AddLargePreimageFinal(dat)
expect(tst[0]).to.equal(keccak256(dat))
expect(tst[1].toNumber()).to.equal(11)
expect(tst[2]).to.equal(0x6f20776f)
console.log(tst)
await mm.AddLargePreimageFinalSaved(dat)
})
}); });
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment