diff --git a/evm/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/power.asm b/evm/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/power.asm index 949a42c8..d0cf3bed 100644 --- a/evm/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/power.asm +++ b/evm/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/power.asm @@ -12,7 +12,7 @@ /// y0 = y0^{-1} /// y1 *= y0 * (y2**2) /// y1 = frob_fp12_1(y1) -/// y2 = frob_fp12_2(y2) +/// y2 = frob_fp12_2_(y2) /// return y2 * y1 * y0 global power: @@ -59,7 +59,7 @@ power_return_4: // stack: out, retdest {236: y0, 212: y1, 224: y2} PUSH 224 DUP1 // stack: 224, 224, out, retdest {236: y0, 212: y1, 224: y2} - %frob_fp12_2 + %frob_fp12_2_ // stack: 224, out, retdest {236: y0, 212: y1, 224: y2} POP // stack: out, retdest {236: y0, 212: y1, 224: y2} diff --git a/evm/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/tate_pairing.asm b/evm/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/tate_pairing.asm index 47b1c313..031dc93b 100644 --- a/evm/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/tate_pairing.asm +++ b/evm/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/tate_pairing.asm @@ -5,7 +5,7 @@ /// out = frob_fp12_6(out) /// out = mul_fp12(out, inv) /// -/// acc = frob_fp12_2(out) +/// acc = frob_fp12_2_(out) /// out = mul_fp12(out, acc) /// /// pow = fast_exp(out) @@ -51,7 +51,7 @@ tate_mul1: // stack: 100, out, tate_mul2, out, retdest {100: inv} DUP2 // stack: out, 100, out, tate_mul2, out, retdest {100: inv} - %frob_fp12_2 + %frob_fp12_2_ // stack: out, 100, out, tate_mul2, out, retdest {100: inv} %jump(mul_fp12) tate_mul2: diff --git a/evm/src/cpu/kernel/asm/curve/bn254/field_arithmetic/frobenius.asm b/evm/src/cpu/kernel/asm/curve/bn254/field_arithmetic/frobenius.asm index 7e828784..c343378b 100644 --- a/evm/src/cpu/kernel/asm/curve/bn254/field_arithmetic/frobenius.asm +++ b/evm/src/cpu/kernel/asm/curve/bn254/field_arithmetic/frobenius.asm @@ -1,3 +1,41 @@ +global test_frob_fp12_1: + // stack: ptr, f, ptr + %store_fp12 + // stack: ptr + %frob_fp12_1 + // stack: ptr + %load_fp12 + %jump(0xdeadbeef) + +global test_frob_fp12_2: + // stack: ptr, f, ptr + %store_fp12 + // stack: ptr + DUP1 + // stack: ptr, ptr + %frob_fp12_2_ + // stack: ptr + %load_fp12 + %jump(0xdeadbeef) + +global test_frob_fp12_3: + // stack: ptr, f, ptr + %store_fp12 + // stack: ptr + %frob_fp12_3 + // stack: ptr + %load_fp12 + %jump(0xdeadbeef) + +global test_frob_fp12_6: + // stack: ptr, f, ptr + %store_fp12 + // stack: ptr + %frob_fp12_6 + // stack: ptr + %load_fp12 + %jump(0xdeadbeef) + /// let Z` denote the complex conjugate of Z /// def frob_fp6_n(C0, C1, C2): @@ -91,13 +129,14 @@ // stack: f', ptr %frobz_1 // stack: g', ptr - DUP1 %offset_fp6 + DUP7 %offset_fp6 // stack: ptr', g', ptr %store_fp6 // stack: ptr %endmacro -%macro frob_fp12_2 +// Note: this is the only one with distinct input and output pointers +%macro frob_fp12_2_ // stack: ptr , out DUP1 // stack: ptr, ptr , out @@ -115,7 +154,7 @@ // stack: f', out %frobz_2 // stack: g', out - DUP1 %offset_fp6 + DUP7 %offset_fp6 // stack: out', g', out %store_fp6 // stack: out @@ -139,11 +178,11 @@ // stack: f', ptr %frobz_3 // stack: g', ptr - DUP1 %offset_fp6 + DUP7 %offset_fp6 // stack: ptr', g', ptr %store_fp6 // stack: ptr -%endmacro +%endmacro %macro frob_fp12_6 // stack: ptr diff --git a/evm/src/cpu/kernel/tests/bn254_field.rs b/evm/src/cpu/kernel/tests/bn254_field.rs index 5699b1f4..d2468205 100644 --- a/evm/src/cpu/kernel/tests/bn254_field.rs +++ b/evm/src/cpu/kernel/tests/bn254_field.rs @@ -150,6 +150,10 @@ fn gen_fp6() -> Fp6 { ] } +fn gen_fp12() -> Fp12 { + [gen_fp6(), gen_fp6()] +} + fn gen_fp12_sparse() -> Fp12 { sparse_embed([gen_fp(), gen_fp(), gen_fp(), gen_fp(), gen_fp()]) } @@ -303,16 +307,22 @@ fn frob_fp6(n: usize, c: Fp6) -> Fp6 { let _c1 = conj_fp2(c1); let _c2 = conj_fp2(c2); + let n = n % 6; + let frob_t1 = frob_t1(n); + let frob_t2 = frob_t2(n); + if n % 2 != 0 { - [_c0, mul_fp2(frob_t1(n), _c1), mul_fp2(frob_t2(n), _c2)] + [_c0, mul_fp2(frob_t1, _c1), mul_fp2(frob_t2, _c2)] } else { - [c0, mul_fp2(frob_t1(n), c1), mul_fp2(frob_t2(n), c2)] + [c0, mul_fp2(frob_t1, c1), mul_fp2(frob_t2, c2)] } } + fn frob_fp12(n: usize, f: Fp12) -> Fp12 { let [f0, f1] = f; let zero = U256::from(0); let scale = [frob_z(n), [zero, zero], [zero, zero]]; + [frob_fp6(n, f0), mul_fp6(scale, frob_fp6(n, f1))] } @@ -320,10 +330,8 @@ fn make_mul_stack( in0: usize, in1: usize, out: usize, - f0: Fp6, - f1: Fp6, - g0: Fp6, - g1: Fp6, + f: Fp12, + g: Fp12, mul_label: &str, ) -> Vec { // stack: in0, f, f', in1, g, g', mul_dest, in0, in1, out, ret_stack, out @@ -332,20 +340,16 @@ fn make_mul_stack( let in1 = U256::from(in1); let out = U256::from(out); - let f0: Vec = f0.into_iter().flatten().collect(); - let f1: Vec = f1.into_iter().flatten().collect(); - let g0: Vec = g0.into_iter().flatten().collect(); - let g1: Vec = g1.into_iter().flatten().collect(); + let f: Vec = f.into_iter().flatten().flatten().collect(); + let g: Vec = g.into_iter().flatten().flatten().collect(); let ret_stack = U256::from(KERNEL.global_labels["ret_stack"]); let mul_dest = U256::from(KERNEL.global_labels[mul_label]); let mut input = vec![in0]; - input.extend(f0); - input.extend(f1); + input.extend(f); input.extend(vec![in1]); - input.extend(g0); - input.extend(g1); + input.extend(g); input.extend(vec![mul_dest, in0, in1, out, ret_stack, out]); input.reverse(); @@ -367,25 +371,23 @@ fn test_mul_fp12() -> Result<()> { let in1 = 76; let out = 88; - let f0 = gen_fp6(); - let f1 = gen_fp6(); - let g0 = gen_fp6(); - let g1 = gen_fp6(); - let [h0, h1] = gen_fp12_sparse(); + let f: Fp12 = gen_fp12(); + let g: Fp12 = gen_fp12(); + let h: Fp12 = gen_fp12_sparse(); let test_mul = KERNEL.global_labels["test_mul_fp12"]; - let normal: Vec = make_mul_stack(in0, in1, out, f0, f1, g0, g1, "mul_fp12"); - let sparse: Vec = make_mul_stack(in0, in1, out, f0, f1, h0, h1, "mul_fp12_sparse"); - let square: Vec = make_mul_stack(in0, in1, out, f0, f1, f0, f1, "square_fp12_test"); + let normal: Vec = make_mul_stack(in0, in1, out, f, g, "mul_fp12"); + let sparse: Vec = make_mul_stack(in0, in1, out, f, h, "mul_fp12_sparse"); + let square: Vec = make_mul_stack(in0, in1, out, f, f, "square_fp12_test"); let out_normal: Vec = run_interpreter(test_mul, normal)?.stack().to_vec(); let out_sparse: Vec = run_interpreter(test_mul, sparse)?.stack().to_vec(); let out_square: Vec = run_interpreter(test_mul, square)?.stack().to_vec(); - let exp_normal: Vec = make_mul_expected([f0, f1], [g0, g1]); - let exp_sparse: Vec = make_mul_expected([f0, f1], [h0, h1]); - let exp_square: Vec = make_mul_expected([f0, f1], [f0, f1]); + let exp_normal: Vec = make_mul_expected(f, g); + let exp_sparse: Vec = make_mul_expected(f, h); + let exp_square: Vec = make_mul_expected(f, f); assert_eq!(out_normal, exp_normal); assert_eq!(out_sparse, exp_sparse); @@ -393,3 +395,52 @@ fn test_mul_fp12() -> Result<()> { Ok(()) } + +fn make_frob_stack(f: Fp12) -> Vec { + let ptr = U256::from(100); + let f: Vec = f.into_iter().flatten().flatten().collect(); + let mut input = vec![ptr]; + input.extend(f); + input.extend(vec![ptr]); + input.reverse(); + + input +} + +fn make_frob_expected(n: usize, f: Fp12) -> Vec { + frob_fp12(n, f) + .into_iter() + .flatten() + .flatten() + .rev() + .collect() +} + +#[test] +fn test_frob_fp12() -> Result<()> { + let f: Fp12 = gen_fp12(); + + let test_frob1 = KERNEL.global_labels["test_frob_fp12_1"]; + let test_frob2 = KERNEL.global_labels["test_frob_fp12_2"]; + let test_frob3 = KERNEL.global_labels["test_frob_fp12_3"]; + let test_frob6 = KERNEL.global_labels["test_frob_fp12_6"]; + + let stack = make_frob_stack(f); + + let out_frob1: Vec = run_interpreter(test_frob1, stack.clone())?.stack().to_vec(); + let out_frob2: Vec = run_interpreter(test_frob2, stack.clone())?.stack().to_vec(); + let out_frob3: Vec = run_interpreter(test_frob3, stack.clone())?.stack().to_vec(); + let out_frob6: Vec = run_interpreter(test_frob6, stack)?.stack().to_vec(); + + let exp_frob1: Vec = make_frob_expected(1, f); + let exp_frob2: Vec = make_frob_expected(2, f); + let exp_frob3: Vec = make_frob_expected(3, f); + let exp_frob6: Vec = make_frob_expected(6, f); + + assert_eq!(out_frob1, exp_frob1); + assert_eq!(out_frob2, exp_frob2); + assert_eq!(out_frob3, exp_frob3); + assert_eq!(out_frob6, exp_frob6); + + Ok(()) +}