Merge branch 'main' of github.com:mir-protocol/plonky2 into fp381-opcodes

This commit is contained in:
Dmitry Vagner 2023-03-22 18:22:37 -07:00
commit 7ff2122e46
7 changed files with 153 additions and 53 deletions

View File

@ -69,14 +69,14 @@ pub fn miller_loop(p: Curve, q: TwistedCurve) -> Fp12<BN254> {
pub fn tangent(p: Curve, q: TwistedCurve) -> Fp12<BN254> {
let cx = -BN254::new(3) * p.x * p.x;
let cy = BN254::new(2) * p.y;
sparse_embed(p.y * p.y - BN254::new(9), q.x.scale(cx), q.y.scale(cy))
sparse_embed(p.y * p.y - BN254::new(9), q.x * cx, q.y * cy)
}
/// The sloped line function for adding two points
pub fn cord(p1: Curve, p2: Curve, q: TwistedCurve) -> Fp12<BN254> {
let cx = p2.y - p1.y;
let cy = p1.x - p2.x;
sparse_embed(p1.y * p2.x - p2.y * p1.x, q.x.scale(cx), q.y.scale(cy))
sparse_embed(p1.y * p2.x - p2.y * p1.x, q.x * cx, q.y * cy)
}
/// The tangent and cord functions output sparse Fp12 elements.

View File

@ -47,10 +47,10 @@ global sys_create2:
SWAP4
%stack (salt) -> (salt, sys_create2_got_address)
// stack: salt, sys_create2_got_address, value, code_offset, code_len, kexit_info
DUP4 // code_len
DUP4 // code_offset
DUP5 // code_len
DUP5 // code_offset
PUSH @SEGMENT_MAIN_MEMORY
PUSH 0 // context
GET_CONTEXT
KECCAK_GENERAL
// stack: hash, salt, sys_create2_got_address, value, code_offset, code_len, kexit_info
%address

View File

@ -34,15 +34,28 @@ global get_create_address:
// Computes the address for a contract based on the CREATE2 rule, i.e.
// address = KEC(0xff || sender || salt || code_hash)[12:]
//
// Pre stack: sender, salt, code_hash, retdest
// Clobbers @SEGMENT_KERNEL_GENERAL.
// Pre stack: sender, code_hash, salt, retdest
// Post stack: address
global get_create2_address:
// stack: sender, salt, code_hash, retdest
// TODO: Replace with actual implementation.
%pop3
PUSH 123
// stack: sender, code_hash, salt, retdest
PUSH 0xff PUSH 0 %mstore_kernel_general
%stack (sender, code_hash, salt, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 1, sender, 20, get_create2_address_contd, salt, code_hash, retdest)
%jump(mstore_unpacking)
get_create2_address_contd:
POP
%stack (salt, code_hash, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 21, salt, 32, get_create2_address_contd2, code_hash, retdest)
%jump(mstore_unpacking)
get_create2_address_contd2:
POP
%stack (code_hash, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 53, code_hash, 32, get_create2_address_finish, retdest)
%jump(mstore_unpacking)
get_create2_address_finish:
POP
%stack (retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 0, 85, retdest) // context, segment, offset, len
KECCAK_GENERAL
// stack: address, retdest
%mod_const(0x10000000000000000000000000000000000000000) // 2^160
%observe_new_address
SWAP1
JUMP

View File

@ -201,7 +201,7 @@ global sys_basefee:
// stack: old_num_words, num_words, kexit_info
DUP2 DUP2 GT
// stack: old_num_words > num_words, old_num_words, num_words, kexit_info
%jumpi(%%end)
%jumpi(%%no_update)
// stack: old_num_words, num_words, kexit_info
%memory_cost
// stack: old_cost, num_words, kexit_info
@ -214,6 +214,10 @@ global sys_basefee:
SUB
// stack: additional_cost, kexit_info
%charge_gas
%jump(%%end)
%%no_update:
// stack: old_num_words, num_words, kexit_info
%pop2
%%end:
// stack: kexit_info
%endmacro

View File

@ -124,14 +124,14 @@ sys_calldataload_after_mload_packing:
// stack: kexit_info, dest_offset, offset, size
DUP4 %num_bytes_to_num_words %mul_const(@GAS_COPY) %add_const(@GAS_VERYLOW) %charge_gas
%stack (kexit_info, dest_offset, offset, size) -> (dest_offset, size, dest_offset, offset, size, kexit_info)
%stack (kexit_info, dest_offset, offset, size) -> (dest_offset, size, kexit_info, dest_offset, offset, size)
ADD // TODO: check for overflow, see discussion here https://github.com/mir-protocol/plonky2/pull/930/files/a4ea0965d79561c345e2f77836c07949c7e0bc69#r1143630253
// stack: expanded_num_bytes, dest_offset, offset, size, kexit_info
// stack: expanded_num_bytes, kexit_info, dest_offset, offset, size, kexit_info
DUP1 %ensure_reasonable_offset
%update_mem_bytes
GET_CONTEXT
%stack (context, dest_offset, offset, size, kexit_info) ->
%stack (context, kexit_info, dest_offset, offset, size) ->
(context, @SEGMENT_MAIN_MEMORY, dest_offset, context, $segment, offset, size, %%after, kexit_info)
%jump(memcpy)
%%after:

View File

@ -1,6 +1,9 @@
use std::str::FromStr;
use anyhow::Result;
use ethereum_types::U256;
use ethereum_types::{H256, U256};
use hex_literal::hex;
use keccak_hash::keccak;
use crate::cpu::kernel::aggregator::KERNEL;
use crate::cpu::kernel::interpreter::Interpreter;
@ -24,22 +27,89 @@ fn test_get_create_address() -> Result<()> {
Ok(())
}
struct Create2TestCase {
code_hash: H256,
salt: U256,
sender: U256,
expected_addr: U256,
}
/// Taken from https://eips.ethereum.org/EIPS/eip-1014
fn create2_test_cases() -> Vec<Create2TestCase> {
vec![
Create2TestCase {
code_hash: keccak(hex!("00")),
salt: U256::zero(),
sender: U256::zero(),
expected_addr: U256::from_str("0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38").unwrap(),
},
Create2TestCase {
code_hash: keccak(hex!("00")),
salt: U256::zero(),
sender: U256::from_str("0xdeadbeef00000000000000000000000000000000").unwrap(),
expected_addr: U256::from_str("0xB928f69Bb1D91Cd65274e3c79d8986362984fDA3").unwrap(),
},
Create2TestCase {
code_hash: keccak(hex!("00")),
salt: U256::from_str(
"0x000000000000000000000000feed000000000000000000000000000000000000",
)
.unwrap(),
sender: U256::from_str("0xdeadbeef00000000000000000000000000000000").unwrap(),
expected_addr: U256::from_str("0xD04116cDd17beBE565EB2422F2497E06cC1C9833").unwrap(),
},
Create2TestCase {
code_hash: keccak(hex!("deadbeef")),
salt: U256::zero(),
sender: U256::zero(),
expected_addr: U256::from_str("0x70f2b2914A2a4b783FaEFb75f459A580616Fcb5e").unwrap(),
},
Create2TestCase {
code_hash: keccak(hex!("deadbeef")),
salt: U256::from_str(
"0x00000000000000000000000000000000000000000000000000000000cafebabe",
)
.unwrap(),
sender: U256::from_str("0x00000000000000000000000000000000deadbeef").unwrap(),
expected_addr: U256::from_str("0x60f3f640a8508fC6a86d45DF051962668E1e8AC7").unwrap(),
},
Create2TestCase {
code_hash: keccak(hex!("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")),
salt: U256::from_str(
"0x00000000000000000000000000000000000000000000000000000000cafebabe",
)
.unwrap(),
sender: U256::from_str("0x00000000000000000000000000000000deadbeef").unwrap(),
expected_addr: U256::from_str("0x1d8bfDC5D46DC4f61D6b6115972536eBE6A8854C").unwrap(),
},
Create2TestCase {
code_hash: keccak(hex!("")),
salt: U256::zero(),
sender: U256::zero(),
expected_addr: U256::from_str("0xE33C0C7F7df4809055C3ebA6c09CFe4BaF1BD9e0").unwrap(),
},
]
}
#[test]
fn test_get_create2_address() -> Result<()> {
let get_create2_address = KERNEL.global_labels["get_create2_address"];
// TODO: Replace with real data once we have a real implementation.
let retaddr = 0xdeadbeefu32.into();
let code_hash = 0.into();
let salt = 5.into();
let sender = 0.into();
let expected_addr = 123.into();
let initial_stack = vec![retaddr, code_hash, salt, sender];
let mut interpreter = Interpreter::new_with_kernel(get_create2_address, initial_stack);
interpreter.run()?;
for Create2TestCase {
code_hash,
salt,
sender,
expected_addr,
} in create2_test_cases()
{
let initial_stack = vec![retaddr, salt, U256::from(code_hash.0), sender];
let mut interpreter = Interpreter::new_with_kernel(get_create2_address, initial_stack);
interpreter.run()?;
assert_eq!(interpreter.stack(), &[expected_addr]);
assert_eq!(interpreter.stack(), &[expected_addr]);
}
Ok(())
}

View File

@ -6,8 +6,7 @@ use rand::distributions::{Distribution, Standard};
use rand::Rng;
pub trait FieldExt:
Sized
+ Copy
Copy
+ std::ops::Add<Output = Self>
+ std::ops::Neg<Output = Self>
+ std::ops::Sub<Output = Self>
@ -325,15 +324,19 @@ impl<T: FieldExt> Mul for Fp2<T> {
}
}
impl<T: FieldExt> Fp2<T> {
/// This function scalar multiplies an Fp2 by an BN254
pub fn scale(self, x: T) -> Self {
/// This function scalar multiplies an Fp2 by an Fp
impl<T: FieldExt> Mul<T> for Fp2<T> {
type Output = Fp2<T>;
fn mul(self, other: T) -> Self {
Fp2 {
re: x * self.re,
im: x * self.im,
re: other * self.re,
im: other * self.im,
}
}
}
impl<T: FieldExt> Fp2<T> {
/// Return the complex conjugate z' of z: Fp2
/// This also happens to be the frobenius map
/// z -> z^p
@ -365,7 +368,7 @@ impl<T: FieldExt> FieldExt for Fp2<T> {
/// The inverse of z is given by z'/||z||^2 since ||z||^2 = zz'
fn inv(self) -> Fp2<T> {
let norm_sq = self.norm_sq();
self.conj().scale(norm_sq.inv())
self.conj() * norm_sq.inv()
}
}
@ -888,17 +891,19 @@ where
}
}
impl<T> Fp6<T>
/// This function scalar multiplies an Fp6 by an Fp2
impl<T> Mul<Fp2<T>> for Fp6<T>
where
T: FieldExt,
Fp2<T>: Adj,
{
// This function scalar multiplies an Fp6 by an Fp2
fn scale(self, x: Fp2<T>) -> Fp6<T> {
type Output = Fp6<T>;
fn mul(self, other: Fp2<T>) -> Self {
Fp6 {
t0: x * self.t0,
t1: x * self.t1,
t2: x * self.t2,
t0: other * self.t0,
t1: other * self.t1,
t2: other * self.t2,
}
}
}
@ -989,9 +994,9 @@ where
let prod_13 = self.frob(1) * self.frob(3);
let prod_135 = (prod_13 * self.frob(5)).t0;
let phi = prod_135.norm_sq();
let prod_odds_over_phi = prod_135.scale(phi.inv());
let prod_odds_over_phi = prod_135 * phi.inv();
let prod_24 = prod_13.frob(1);
prod_24.scale(prod_odds_over_phi)
prod_24 * prod_odds_over_phi
}
}
@ -1052,10 +1057,10 @@ where
let prod_1379 = prod_17 * prod_17.frob(2);
let prod_odds = (prod_1379 * prod_17.frob(4)).t0;
let phi = prod_odds.norm_sq();
let prod_odds_over_phi = prod_odds.scale(phi.inv());
let prod_odds_over_phi = prod_odds * phi.inv();
let prod_evens_except_six = prod_1379.frob(1);
let prod_except_six = prod_evens_except_six.scale(prod_odds_over_phi);
self.conj().scale(prod_except_six)
let prod_except_six = prod_evens_except_six * prod_odds_over_phi;
self.conj() * prod_except_six
}
}
@ -1134,19 +1139,27 @@ where
}
}
/// This function scalar multiplies an Fp12 by an Fp6
impl<T> Mul<Fp6<T>> for Fp12<T>
where
T: FieldExt,
Fp2<T>: Adj,
{
type Output = Fp12<T>;
fn mul(self, other: Fp6<T>) -> Self {
Fp12 {
z0: other * self.z0,
z1: other * self.z1,
}
}
}
impl<T> Fp12<T>
where
T: FieldExt,
Fp2<T>: Adj,
{
// This function scalar multiplies an Fp12 by an Fp6
fn scale(self, x: Fp6<T>) -> Fp12<T> {
Fp12 {
z0: x * self.z0,
z1: x * self.z1,
}
}
fn conj(self) -> Fp12<T> {
Fp12 {
z0: self.z0,
@ -1169,7 +1182,7 @@ where
let n = n % 12;
Fp12 {
z0: self.z0.frob(n),
z1: self.z1.frob(n).scale(Fp2::<T>::FROB_Z[n]),
z1: self.z1.frob(n) * (Fp2::<T>::FROB_Z[n]),
}
}
}