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

Improved efficiency in synthesizer EXP placement #2

Open
wants to merge 1 commit into
base: ale-71-build-synthesizer
Choose a base branch
from
Open
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
4 changes: 3 additions & 1 deletion packages/evm/examples/simple.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// DEBUG=ethjs,evm:*,evm:*:* tsx simple.ts

import { hexToBytes } from '@ethereumjs/util'

import { createEVM } from '../src/constructors.js'

const main = async () => {
const evm = await createEVM()
const res = await evm.runCode({ code: hexToBytes('0x6001600201') }) // PUSH1 01 -- simple bytecode to push 1 onto the stack
const res = await evm.runCode({ code: hexToBytes('0x605A60050A610120526101406000F3') }) // PUSH1 01 -- simple bytecode to push 1 onto the stack
console.log(res.executionGasUsed) // 3n
}

Expand Down
2 changes: 1 addition & 1 deletion packages/evm/src/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ export class Interpreter {
console.log(`"memory": ${stringMemory.slice(0, 256)}\n`)
console.log(`"stackPt": ${JSON.stringify(this._runState.stackPt.getStack(), arrToStr, 2)}\n`)
console.log(`"memoryPt": ${JSON.stringify(stringMemoryPt, null, 1)}\n`)
//console.log(`"placements": ${JSON.stringify(stringPlacements, null, 1)}`)
console.log(`"placements": ${JSON.stringify(stringPlacements, null, 1)}`)
if (!(name in this.opDebuggers)) {
this.opDebuggers[name] = debugDefault(`evm:ops:${name}`)
}
Expand Down
6 changes: 3 additions & 3 deletions packages/evm/src/opcodes/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import {

import type { RunState } from '../interpreter.js'
import type { MemoryPtEntry, MemoryPts } from '../tokamak/memoryPt.js'
import type { DataPt } from '../tokamak/synthesizer.js'
import type { DataPt } from '../tokamak/type.js'
import type { Common } from '@ethereumjs/common'

export interface SyncOpHandler {
Expand Down Expand Up @@ -286,8 +286,8 @@ export const handlers: Map<number, OpHandler> = new Map([

// For Synthesizer //
const inPts = runState.stackPt.popN(2)
const outPts = runState.synthesizer.placeArith('EXP', inPts)
runState.stackPt.push(outPts[0])
const outPt = runState.synthesizer.placeEXP(inPts)
runState.stackPt.push(outPt)
},
],
// 0x0b: SIGNEXTEND
Expand Down
29 changes: 28 additions & 1 deletion packages/evm/src/tokamak/arithmetic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ export type ArithmeticOperator =
| 'SAR'
| 'BYTE'
| 'SIGNEXTEND'
| 'DecToBit'
| 'SubEXP'

export type ArithmeticFunction = (...args: bigint[]) => bigint
export type ArithmeticFunction = (...args: bigint[]) => bigint | bigint[]

/**
* Synthesizer 산술 연산을 처리하는 유틸리티 클래스
Expand Down Expand Up @@ -90,6 +92,7 @@ export class ArithmeticOperations {
}

/**
* @deprecated
* 지수 연산
*/
static exp(base: bigint, exponent: bigint): bigint {
Expand Down Expand Up @@ -206,6 +209,28 @@ export class ArithmeticOperations {
return value & mask
}
}

/**
* Decimal to Bit
*/
static decToBit(dec: bigint): bigint[] {
const binaryString = dec.toString(2)
const paddedBinaryString = binaryString.padStart(256, '0')
const bits = Array.from(paddedBinaryString, bit => BigInt(bit))
return bits
}

/**
* Subroutine for EXP
*/
static subEXP(c: bigint, a: bigint, b: bigint): bigint[] {
if (!(b === 0n || b === 1n) ){
throw new Error(`Synthesizer: ArithmeticOperations: subEXP: b is not binary`)
}
const aOut = a ** 2n
const cOut = c * ( b * a + (1n - b) ) // <=> c * (b ? aOut : 1)
return [cOut, aOut]
}
}

// 연산자와 함수 매핑
Expand Down Expand Up @@ -235,4 +260,6 @@ export const OPERATION_MAPPING: Record<ArithmeticOperator, ArithmeticFunction> =
SAR: ArithmeticOperations.sar,
BYTE: ArithmeticOperations.byte,
SIGNEXTEND: ArithmeticOperations.signextend,
DecToBit: ArithmeticOperations.decToBit,
SubEXP: ArithmeticOperations.subEXP,
} as const
16 changes: 16 additions & 0 deletions packages/evm/src/tokamak/subcircuit_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,4 +246,20 @@ export const subcircuits = [
Out_idx: [1, 32],
In_idx: [33, 1],
},
{
id: 30,
opcode: '',
name: 'DecToBit',
Nwires: 0,
Out_idx: [1, 256],
In_idx: [257, 1],
},
{
id: 31,
opcode: '',
name: 'SubEXP',
Nwires: 0,
Out_idx: [1, 2],
In_idx: [3, 3],
},
]
62 changes: 53 additions & 9 deletions packages/evm/src/tokamak/synthesizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { RunState } from '../interpreter.js'
import type { ArithmeticOperator } from './arithmetic.js'
import type { DataAliasInfoEntry, DataAliasInfos } from './memoryPt.js'
import type { DataPt, Placements } from './type.js'
import { BIGINT_0, BIGINT_1 } from '@ethereumjs/util'

/**
* @TODO
Expand Down Expand Up @@ -331,11 +332,14 @@ export class Synthesizer {
}

// 기본값(2)과 다른 입력 개수를 가진 연산들만 정의
// To do: subcircuit_info.ts 에서 입출력 갯수 가져오기
private static readonly REQUIRED_INPUTS: Partial<Record<string, number>> = {
ADDMOD: 3,
MULMOD: 3,
ISZERO: 1,
NOT: 1,
DecToBit: 1,
SubEXP: 3,
} as const

private validateOperation(name: ArithmeticOperator, inPts: DataPt[]): void {
Expand All @@ -345,18 +349,32 @@ export class Synthesizer {
SynthesizerValidator.validateInputs(inPts)
}

private executeOperation(name: ArithmeticOperator, values: bigint[]): bigint {
private executeOperation(name: ArithmeticOperator, values: bigint[]): bigint | bigint[] {
const operation = OPERATION_MAPPING[name]
return operation(...values)
}

private createOutputPoint(value: bigint): DataPt {
return this.createNewDataPoint({
sourceId: this.placementIndex,
sourceIndex: 0,
value,
sourceSize: 32,
})
private createOutputPoints(value: bigint | bigint[]): DataPt[] {
if (Array.isArray(value)) {
const outPts: DataPt[] = []
for (let ind = 0; ind < value.length; ind++){
outPts.push( this.createNewDataPoint({
sourceId: this.placementIndex,
sourceIndex: ind,
value: value[ind],
sourceSize: 32,
}))
}
return outPts

} else {
return [this.createNewDataPoint({
sourceId: this.placementIndex,
sourceIndex: 0,
value,
sourceSize: 32,
})]
}
}

private handleBinaryOp(name: ArithmeticOperator, inPts: DataPt[]): DataPt[] {
Expand All @@ -369,7 +387,7 @@ export class Synthesizer {
const outValue = this.executeOperation(name, values)

// 3. 출력값 생성
const outPts = [this.createOutputPoint(outValue)]
const outPts = this.createOutputPoints(outValue)

// 4. 배치 추가
this._place(name, inPts, outPts)
Expand Down Expand Up @@ -401,6 +419,32 @@ export class Synthesizer {
return this.handleBinaryOp(name, inPts)
}

public placeEXP(inPts: DataPt[]): DataPt {
SynthesizerValidator.validateSubcircuitName('EXP', this.subcircuitNames)
// a^b
const aPt = inPts[0]
const bPt = inPts[1]
const bNum = Number(bPt.value)
const k = Math.floor(Math.log2(bNum)) + 1 //bit length of b

const bitifyOutPts = this.placeArith('DecToBit', [bPt]).reverse()
// LSB at index 0

const chPts: DataPt[] = []
const ahPts: DataPt[] = []
chPts.push(this.loadAuxin(BIGINT_1))
ahPts.push(aPt)

for ( let i = 1; i <= k; i++ ){
const _inPts = [chPts[i-1], ahPts[i-1], bitifyOutPts[i-1]]
const _outPts = this.placeArith('SubEXP', _inPts)
chPts.push(_outPts[0])
ahPts.push(_outPts[1])
}

return chPts[chPts.length-1]
}

/**
* MLOAD는 고정적으로 32바이트를 읽지만, offset이 1바이트 단위이기 때문에 데이터 변형이 발생할 수 있습니다.
* 데이터 변형을 추적하기 위해 데이터 변형 여부를 확인하는 함수를 구현합니다.
Expand Down