Skip to content

Commit f584c42

Browse files
committed
Add uint256 mul elf program. Pass test.
1 parent 9839042 commit f584c42

File tree

12 files changed

+214
-177
lines changed

12 files changed

+214
-177
lines changed

.github/workflows/integration.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ jobs:
110110
RUSTFLAGS: "-C opt-level=3"
111111
run: cargo run --release --package ceno_zkvm --bin e2e -- --platform=ceno examples/target/riscv32im-ceno-zkvm-elf/release/examples/bn254_curve_syscalls
112112

113+
- name: Run uint256_mul_syscall (release)
114+
env:
115+
RUSTFLAGS: "-C opt-level=3"
116+
run: cargo run --release --package ceno_zkvm --bin e2e -- --platform=ceno examples/target/riscv32im-ceno-zkvm-elf/release/examples/uint256_mul_syscall
117+
113118
- name: Install cargo make
114119
run: |
115120
cargo make --version || cargo install cargo-make

Cargo.lock

Lines changed: 0 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,27 @@ repository = "https://github.com/scroll-tech/ceno"
2323
version = "0.1.0"
2424

2525
[workspace.dependencies]
26-
ff_ext = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "ff_ext", rev = "v1.0.0-alpha.9" }
27-
mpcs = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "mpcs", rev = "v1.0.0-alpha.9" }
28-
multilinear_extensions = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "multilinear_extensions", rev = "v1.0.0-alpha.9" }
29-
p3 = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "p3", rev = "v1.0.0-alpha.9" }
30-
poseidon = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "poseidon", rev = "v1.0.0-alpha.9" }
31-
sp1-curves = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "sp1-curves", rev = "v1.0.0-alpha.9" }
32-
sumcheck = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "sumcheck", rev = "v1.0.0-alpha.9" }
33-
transcript = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "transcript", rev = "v1.0.0-alpha.9" }
34-
whir = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "whir", rev = "v1.0.0-alpha.9" }
35-
witness = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "witness", rev = "v1.0.0-alpha.9" }
26+
# ff_ext = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "ff_ext", rev = "v1.0.0-alpha.9" }
27+
# mpcs = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "mpcs", rev = "v1.0.0-alpha.9" }
28+
# multilinear_extensions = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "multilinear_extensions", rev = "v1.0.0-alpha.9" }
29+
# p3 = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "p3", rev = "v1.0.0-alpha.9" }
30+
# poseidon = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "poseidon", rev = "v1.0.0-alpha.9" }
31+
# sp1-curves = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "sp1-curves", rev = "v1.0.0-alpha.9" }
32+
# sumcheck = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "sumcheck", rev = "v1.0.0-alpha.9" }
33+
# transcript = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "transcript", rev = "v1.0.0-alpha.9" }
34+
# whir = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "whir", rev = "v1.0.0-alpha.9" }
35+
# witness = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "witness", rev = "v1.0.0-alpha.9" }
36+
37+
ff_ext = { path = "../gkr-backend/crates/ff_ext", package = "ff_ext" }
38+
mpcs = { path = "../gkr-backend/crates/mpcs", package = "mpcs" }
39+
multilinear_extensions = { path = "../gkr-backend/crates/multilinear_extensions", package = "multilinear_extensions" }
40+
p3 = { path = "../gkr-backend/crates/p3", package = "p3" }
41+
poseidon = { path = "../gkr-backend/crates/poseidon", package = "poseidon" }
42+
sp1-curves = { path = "../gkr-backend/crates/curves", package = "sp1-curves" }
43+
sumcheck = { path = "../gkr-backend/crates/sumcheck", package = "sumcheck" }
44+
transcript = { path = "../gkr-backend/crates/transcript", package = "transcript" }
45+
whir = { path = "../gkr-backend/crates/whir", package = "whir" }
46+
witness = { path = "../gkr-backend/crates/witness", package = "witness" }
3647

3748
alloy-primitives = "1.3"
3849
anyhow = { version = "1.0", default-features = false }
@@ -91,13 +102,14 @@ lto = "thin"
91102
#[patch."ssh://[email protected]/scroll-tech/ceno-gpu.git"]
92103
#ceno_gpu = { path = "../ceno-gpu/cuda_hal", package = "cuda_hal" }
93104

94-
#[patch."https://github.com/scroll-tech/gkr-backend"]
95-
#ff_ext = { path = "../gkr-backend/crates/ff_ext", package = "ff_ext" }
96-
#mpcs = { path = "../gkr-backend/crates/mpcs", package = "mpcs" }
97-
#multilinear_extensions = { path = "../gkr-backend/crates/multilinear_extensions", package = "multilinear_extensions" }
98-
#p3 = { path = "../gkr-backend/crates/p3", package = "p3" }
99-
#poseidon = { path = "../gkr-backend/crates/poseidon", package = "poseidon" }
100-
#sumcheck = { path = "../gkr-backend/crates/sumcheck", package = "sumcheck" }
101-
#transcript = { path = "../gkr-backend/crates/transcript", package = "transcript" }
102-
#whir = { path = "../gkr-backend/crates/whir", package = "whir" }
103-
#witness = { path = "../gkr-backend/crates/witness", package = "witness" }
105+
# [patch."https://github.com/scroll-tech/gkr-backend"]
106+
# ff_ext = { path = "../gkr-backend/crates/ff_ext", package = "ff_ext" }
107+
# mpcs = { path = "../gkr-backend/crates/mpcs", package = "mpcs" }
108+
# multilinear_extensions = { path = "../gkr-backend/crates/multilinear_extensions", package = "multilinear_extensions" }
109+
# p3 = { path = "../gkr-backend/crates/p3", package = "p3" }
110+
# poseidon = { path = "../gkr-backend/crates/poseidon", package = "poseidon" }
111+
# sp1-curves = { path = "../gkr-backend/crates/p3", package = "sp1-curves" }
112+
# sumcheck = { path = "../gkr-backend/crates/sumcheck", package = "sumcheck" }
113+
# transcript = { path = "../gkr-backend/crates/transcript", package = "transcript" }
114+
# whir = { path = "../gkr-backend/crates/whir", package = "whir" }
115+
# witness = { path = "../gkr-backend/crates/witness", package = "witness" }

ceno_emul/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub use syscalls::{
2727
BLS12381_ADD, BLS12381_DECOMPRESS, BLS12381_DOUBLE, BN254_ADD, BN254_DOUBLE, BN254_FP_ADD,
2828
BN254_FP_MUL, BN254_FP2_ADD, BN254_FP2_MUL, KECCAK_PERMUTE, SECP256K1_ADD,
2929
SECP256K1_DECOMPRESS, SECP256K1_DOUBLE, SECP256R1_ADD, SECP256R1_DECOMPRESS, SECP256R1_DOUBLE,
30-
SHA_EXTEND, SyscallSpec,
30+
SHA_EXTEND, SyscallSpec, UINT256_MUL,
3131
bn254::{
3232
BN254_FP_WORDS, BN254_FP2_WORDS, BN254_POINT_WORDS, Bn254AddSpec, Bn254DoubleSpec,
3333
Bn254Fp2AddSpec, Bn254Fp2MulSpec, Bn254FpAddSpec, Bn254FpMulSpec,
@@ -38,7 +38,7 @@ pub use syscalls::{
3838
Secp256k1DecompressSpec, Secp256k1DoubleSpec,
3939
},
4040
sha256::{SHA_EXTEND_WORDS, Sha256ExtendSpec},
41-
uint256::UINT256_WORDS_FIELD_ELEMENT,
41+
uint256::{UINT256_WORDS_FIELD_ELEMENT, Uint256MulSpec},
4242
};
4343

4444
pub mod utils;

ceno_emul/src/syscalls/uint256.rs

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,34 @@
11
use crate::{
2-
Change, EmuContext, Platform, SyscallSpec, VMState, Word, WriteOp,
2+
Change, EmuContext, Platform, SyscallSpec, VMState, WriteOp,
33
syscalls::{SyscallEffects, SyscallWitness},
44
utils::MemoryView,
55
};
66

7-
use super::UINT256_MUL;
87
use itertools::Itertools;
98
use num::{BigUint, One, Zero};
10-
use sp1_curves::{params::NumWords, uint256::U256Field};
9+
use sp1_curves::{
10+
params::NumWords,
11+
uint256::U256Field,
12+
utils::{biguint_from_words, biguint_to_words},
13+
};
1114
use typenum::marker_traits::Unsigned;
1215

1316
type WordsFieldElement = <U256Field as NumWords>::WordsFieldElement;
1417
pub const UINT256_WORDS_FIELD_ELEMENT: usize = WordsFieldElement::USIZE;
15-
const WORD_SIZE: usize = 4;
1618

17-
pub(crate) struct Uint256MulSpec;
19+
pub struct Uint256MulSpec;
1820

1921
impl SyscallSpec for Uint256MulSpec {
2022
const NAME: &'static str = "UINT256_MUL";
2123

2224
const REG_OPS_COUNT: usize = 2;
2325
const MEM_OPS_COUNT: usize = 3 * UINT256_WORDS_FIELD_ELEMENT; // x, y, modulus
24-
const CODE: u32 = ceno_rt::syscalls::UINT256_MUL;
26+
const CODE: u32 = ceno_syscall::UINT256_MUL;
2527
}
2628

2729
pub fn uint256_mul(vm: &VMState) -> SyscallEffects {
2830
let x_ptr = vm.peek_register(Platform::reg_arg0());
2931
let y_ptr = vm.peek_register(Platform::reg_arg1());
30-
let mod_ptr = y_ptr + UINT256_WORDS_FIELD_ELEMENT as u32 * WORD_SIZE as u32;
3132

3233
// Read the argument pointers
3334
let reg_ops = vec![
@@ -44,19 +45,13 @@ pub fn uint256_mul(vm: &VMState) -> SyscallEffects {
4445
];
4546

4647
// Memory segments of x, y, and modulus
47-
let [mut x_view, y_view, mod_view] =
48-
[x_ptr, y_ptr, mod_ptr].map(|start| MemoryView::<UINT256_WORDS_FIELD_ELEMENT>::new(vm, start));
48+
let mut x_view = MemoryView::<UINT256_WORDS_FIELD_ELEMENT>::new(vm, x_ptr);
49+
let y_and_modulus_view = MemoryView::<{ UINT256_WORDS_FIELD_ELEMENT * 2 }>::new(vm, y_ptr);
4950

50-
// Read x and y from words via wrapper type
51-
let [x, y, modulus] = [&x_view, &y_view, &mod_view].map(|view| {
52-
BigUint::from_bytes_le(
53-
&view
54-
.words()
55-
.into_iter()
56-
.flat_map(|w| w.to_le_bytes())
57-
.collect_vec(),
58-
)
59-
});
51+
// Read x, y, and modulus from words via wrapper type
52+
let x = biguint_from_words(&x_view.words());
53+
let y = biguint_from_words(&y_and_modulus_view.words()[..UINT256_WORDS_FIELD_ELEMENT]);
54+
let modulus = biguint_from_words(&y_and_modulus_view.words()[UINT256_WORDS_FIELD_ELEMENT..]);
6055

6156
// Perform the multiplication and take the result modulo the modulus.
6257
let result: BigUint = if modulus.is_zero() {
@@ -65,23 +60,17 @@ pub fn uint256_mul(vm: &VMState) -> SyscallEffects {
6560
} else {
6661
(x * y) % modulus
6762
};
68-
let mut result_bytes = result.to_bytes_le();
69-
result_bytes.resize(32, 0u8); // Pad the result to 32 bytes.
7063

7164
// Convert the result to little endian u32 words.
72-
let result: [u32; 8] = {
73-
let mut iter = result_bytes
74-
.chunks_exact(4)
75-
.map(|chunk| u32::from_le_bytes(chunk.try_into().unwrap()));
76-
core::array::from_fn(|_| iter.next().unwrap())
77-
};
78-
x_view.write(result);
65+
let result_words = biguint_to_words(&result, UINT256_WORDS_FIELD_ELEMENT)
66+
.try_into()
67+
.unwrap();
68+
x_view.write(result_words);
7969

8070
let mem_ops = x_view
8171
.mem_ops()
8272
.into_iter()
83-
.chain(y_view.mem_ops())
84-
.chain(mod_view.mem_ops())
73+
.chain(y_and_modulus_view.mem_ops())
8574
.collect_vec();
8675

8776
SyscallEffects {

ceno_host/tests/test_elf.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,9 @@ fn test_bn254_precompile() -> Result<()> {
626626
Ok(())
627627
}
628628

629+
#[test]
629630
fn test_uint256_mul() -> Result<()> {
631+
let program_elf = ceno_examples::uint256_mul_syscall;
630632
let mut state = VMState::new_from_elf(unsafe_platform(), program_elf)?;
631633

632634
let steps = run(&mut state)?;
@@ -647,16 +649,13 @@ fn test_uint256_mul() -> Result<()> {
647649
assert_eq!(b_address, witness.reg_ops[1].value.before);
648650
let b_address: WordAddr = b_address.into();
649651

650-
const A_MUL_B: [u8; 65] = [
651-
4, 188, 11, 115, 232, 35, 63, 79, 186, 163, 11, 207, 165, 64, 247, 109, 81, 125, 56, 83,
652-
131, 221, 140, 154, 19, 186, 109, 173, 9, 127, 142, 169, 219, 108, 17, 216, 218, 125, 37,
653-
30, 87, 86, 194, 151, 20, 122, 64, 118, 123, 210, 29, 60, 209, 138, 131, 11, 247, 157, 212,
654-
209, 123, 162, 111, 197, 70,
652+
let expect: [u32; 8] = [
653+
0xF0D2F44F, 0xF0DC2116, 0x253AB7CD, 0x3089E8F6, 0x803BED8F, 0x969E7A64, 0x610CBFFF,
654+
0x80012A20,
655655
];
656-
let expect = bytes_to_words(A_MUL_B);
657656

658657
assert_eq!(witness.mem_ops.len(), 3 * UINT256_WORDS_FIELD_ELEMENT);
659-
// Expect first half to consist of read/writes on P
658+
// Expect first half to consist of read/writes on x
660659
for (i, write_op) in witness
661660
.mem_ops
662661
.iter()
@@ -667,12 +666,12 @@ fn test_uint256_mul() -> Result<()> {
667666
assert_eq!(write_op.value.after, expect[i]);
668667
}
669668

670-
// Expect second half to consist of reads on Q
669+
// Expect second half to consist of reads on y and modulus
671670
for (i, write_op) in witness
672671
.mem_ops
673672
.iter()
674673
.skip(UINT256_WORDS_FIELD_ELEMENT)
675-
.take(UINT256_WORDS_FIELD_ELEMENT * UINT256_WORDS_FIELD_ELEMENT)
674+
.take(UINT256_WORDS_FIELD_ELEMENT * 2)
676675
.enumerate()
677676
{
678677
assert_eq!(write_op.addr, b_address + i);

ceno_syscall/src/lib.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,27 @@ pub extern "C" fn syscall_bn254_fp2_mulmod(x: &mut [u32; 16], y: &[u32; 16]) {
300300
#[cfg(not(target_os = "zkvm"))]
301301
unreachable!()
302302
}
303+
304+
/// Uint256 multiplication operation.
305+
///
306+
/// The result is written over the first input.
307+
#[allow(unused_variables)]
308+
#[unsafe(no_mangle)]
309+
pub extern "C" fn syscall_uint256_mul(x: &mut [u32; 8], y_and_modulus: &[u32; 16]) {
310+
#[cfg(target_os = "zkvm")]
311+
{
312+
let x = x.as_mut_ptr();
313+
let y = y_and_modulus.as_ptr();
314+
unsafe {
315+
asm!(
316+
"ecall",
317+
in("t0") UINT256_MUL,
318+
in("a0") x,
319+
in("a1") y,
320+
);
321+
}
322+
}
323+
324+
#[cfg(not(target_os = "zkvm"))]
325+
unreachable!()
326+
}

ceno_zkvm/src/instructions/riscv/ecall.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
mod halt;
22
mod keccak;
3+
mod uint256;
34
mod weierstrass_add;
45
mod weierstrass_decompress;
56
mod weierstrass_double;
6-
mod uint256;
77

88
pub use keccak::KeccakInstruction;
9+
pub use uint256::Uint256MulInstruction;
910
pub use weierstrass_add::WeierstrassAddAssignInstruction;
1011
pub use weierstrass_decompress::WeierstrassDecompressInstruction;
1112
pub use weierstrass_double::WeierstrassDoubleAssignInstruction;
12-
pub use uint256::U256MulInstruction;
1313

1414
use ceno_emul::InsnKind;
1515
pub use halt::HaltInstruction;

0 commit comments

Comments
 (0)