diff --git a/Cargo.lock b/Cargo.lock index 92269823..bf93d41f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -805,8 +805,8 @@ checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "powdr-riscv-runtime" -version = "0.1.0-alpha.2" -source = "git+https://github.com/powdr-labs/powdr.git?tag=v0.1.1#699b74ac5b032113270a2f419ef192bdb7fc0857" +version = "0.1.3" +source = "git+https://github.com/powdr-labs/powdr.git?branch=main#4f1aa4a5f3879e974f8f668b728a8f7eb656b528" dependencies = [ "getrandom", "powdr-riscv-syscalls", @@ -816,8 +816,8 @@ dependencies = [ [[package]] name = "powdr-riscv-syscalls" -version = "0.1.1" -source = "git+https://github.com/powdr-labs/powdr.git?tag=v0.1.1#699b74ac5b032113270a2f419ef192bdb7fc0857" +version = "0.1.3" +source = "git+https://github.com/powdr-labs/powdr.git?branch=main#4f1aa4a5f3879e974f8f668b728a8f7eb656b528" [[package]] name = "ppv-lite86" diff --git a/k256/Cargo.toml b/k256/Cargo.toml index 721f1d16..dd170eb8 100644 --- a/k256/Cargo.toml +++ b/k256/Cargo.toml @@ -35,7 +35,7 @@ sha2 = { version = "=0.11.0-pre.4", optional = true, default-features = false } signature = { version = "=2.3.0-pre.4", optional = true } [target.'cfg(all(target_os = "zkvm", target_arch = "riscv32"))'.dependencies] -powdr-riscv-runtime = { git = "https://github.com/powdr-labs/powdr.git", tag = "v0.1.1", features = [ +powdr-riscv-runtime = { git = "https://github.com/powdr-labs/powdr.git", branch = "main", features = [ "std", "getrandom", "allow_fake_rand", diff --git a/k256/src/arithmetic/field.rs b/k256/src/arithmetic/field.rs index 43390b0d..cb20b43d 100644 --- a/k256/src/arithmetic/field.rs +++ b/k256/src/arithmetic/field.rs @@ -122,6 +122,11 @@ impl FieldElement { self.0.normalize().to_bytes_le() } + #[cfg(all(target_os = "zkvm", target_arch = "riscv32"))] + pub fn write_bytes_le(&self, out: &mut [u8; 32]) { + self.0.normalize().write_bytes_le(out); + } + /// Convert a `i64` to a field element. /// Returned value may be only weakly normalized. #[cfg(all(target_os = "zkvm", target_arch = "riscv32"))] diff --git a/k256/src/arithmetic/field/field_8x32.rs b/k256/src/arithmetic/field/field_8x32.rs index 3cd040c4..89e262c7 100644 --- a/k256/src/arithmetic/field/field_8x32.rs +++ b/k256/src/arithmetic/field/field_8x32.rs @@ -83,6 +83,11 @@ impl FieldElement8x32 { self.0.to_le_byte_array() } + pub fn write_bytes_le(self, out: &mut [u8; 32]) { + let bytes = self.0.to_le_byte_array(); + out.copy_from_slice(&bytes); + } + /// Checks if the field element is greater or equal to the modulus. fn get_overflow(&self) -> Choice { let (_, carry) = self.0.adc(&MODULUS_CORRECTION, Limb(0)); diff --git a/k256/src/arithmetic/field/field_impl.rs b/k256/src/arithmetic/field/field_impl.rs index 1adc4f2a..8514c535 100644 --- a/k256/src/arithmetic/field/field_impl.rs +++ b/k256/src/arithmetic/field/field_impl.rs @@ -110,6 +110,12 @@ impl FieldElementImpl { self.value.to_bytes_le() } + #[cfg(all(target_os = "zkvm", target_arch = "riscv32"))] + pub fn write_bytes_le(self, out: &mut [u8; 32]) { + debug_assert!(self.normalized); + self.value.write_bytes_le(out) + } + pub fn normalize_weak(&self) -> Self { Self::new_weak_normalized(&self.value.normalize_weak()) } diff --git a/k256/src/arithmetic/projective.rs b/k256/src/arithmetic/projective.rs index e45f53c4..26e7ec23 100644 --- a/k256/src/arithmetic/projective.rs +++ b/k256/src/arithmetic/projective.rs @@ -101,21 +101,46 @@ impl ProjectivePoint { { // call when the values are normalized, into powdr ec operations if self.z == FieldElement::ONE && other.z == FieldElement::ONE { - // z being ONE means value is not identity - let self_x: [u8; 32] = self.x.to_bytes_le().into(); - let self_y: [u8; 32] = self.y.to_bytes_le().into(); - let other_x: [u8; 32] = other.x.to_bytes_le().into(); - let other_y: [u8; 32] = other.y.to_bytes_le().into(); + let mut combined_self: [u8; 64] = [0; 64]; + let mut combined_other: [u8; 64] = [0; 64]; - let (res_x, res_y) = if self_x == other_x && self_y == other_y { - double_u8_le(self_x, self_y) + // z being ONE means value is not identity + self.x.write_bytes_le( + (&mut combined_self[..32]) + .try_into() + .expect("Expected 32 bytes"), + ); + self.y.write_bytes_le( + (&mut combined_self[32..]) + .try_into() + .expect("Expected 32 bytes"), + ); + + other.x.write_bytes_le( + (&mut combined_other[..32]) + .try_into() + .expect("Expected 32 bytes"), + ); + other.y.write_bytes_le( + (&mut combined_other[32..]) + .try_into() + .expect("Expected 32 bytes"), + ); + + let result = if combined_self == combined_other { + double_u8_le(combined_self) } else { - add_u8_le(self_x, self_y, other_x, other_y) + add_u8_le(combined_self, combined_other) }; + let (res_x, res_y) = result.split_at(32); let mut res = *self; - res.x = FieldElement::from_bytes_unchecked_le(&res_x); - res.y = FieldElement::from_bytes_unchecked_le(&res_y); + res.x = FieldElement::from_bytes_unchecked_le( + &res_x.try_into().expect("Expected 32 bytes"), + ); + res.y = FieldElement::from_bytes_unchecked_le( + &res_y.try_into().expect("Expected 32 bytes"), + ); return res; } @@ -203,21 +228,47 @@ impl ProjectivePoint { if other.is_identity().into() { return *self; } else if self.z == FieldElement::ONE { - // z being ONE means value is not identity - let self_x: [u8; 32] = self.x.to_bytes_le().into(); - let self_y: [u8; 32] = self.y.to_bytes_le().into(); - let other_x: [u8; 32] = other.x.to_bytes_le().into(); - let other_y: [u8; 32] = other.y.to_bytes_le().into(); + let mut combined_self: [u8; 64] = [0; 64]; + let mut combined_other: [u8; 64] = [0; 64]; - let (res_x, res_y) = if self_x == other_x && self_y == other_y { - double_u8_le(self_x, self_y) + // z being ONE means value is not identity + self.x.write_bytes_le( + (&mut combined_self[..32]) + .try_into() + .expect("Expected 32 bytes"), + ); + self.y.write_bytes_le( + (&mut combined_self[32..]) + .try_into() + .expect("Expected 32 bytes"), + ); + + other.x.write_bytes_le( + (&mut combined_other[..32]) + .try_into() + .expect("Expected 32 bytes"), + ); + other.y.write_bytes_le( + (&mut combined_other[32..]) + .try_into() + .expect("Expected 32 bytes"), + ); + + let result = if combined_self == combined_other { + double_u8_le(combined_self) } else { - add_u8_le(self_x, self_y, other_x, other_y) + add_u8_le(combined_self, combined_other) }; + let (res_x, res_y) = result.split_at(32); + let mut res = *self; - res.x = FieldElement::from_bytes_unchecked_le(&res_x); - res.y = FieldElement::from_bytes_unchecked_le(&res_y); + res.x = FieldElement::from_bytes_unchecked_le( + &res_x.try_into().expect("Expected 32 bytes"), + ); + res.y = FieldElement::from_bytes_unchecked_le( + &res_y.try_into().expect("Expected 32 bytes"), + ); return res; } } @@ -292,13 +343,30 @@ impl ProjectivePoint { #[cfg(all(target_os = "zkvm", target_arch = "riscv32"))] { if self.z == FieldElement::ONE { + let mut combined_self: [u8; 64] = [0; 64]; + // z being ONE means value is not identity - let self_x: [u8; 32] = self.x.to_bytes_le().into(); - let self_y: [u8; 32] = self.y.to_bytes_le().into(); - let (res_x, res_y) = double_u8_le(self_x, self_y); + self.x.write_bytes_le( + (&mut combined_self[..32]) + .try_into() + .expect("Expected 32 bytes"), + ); + self.y.write_bytes_le( + (&mut combined_self[32..]) + .try_into() + .expect("Expected 32 bytes"), + ); + + let result = double_u8_le(combined_self); + let (res_x, res_y) = result.split_at(32); + let mut res = *self; - res.x = FieldElement::from_bytes_unchecked_le(&res_x); - res.y = FieldElement::from_bytes_unchecked_le(&res_y); + res.x = FieldElement::from_bytes_unchecked_le( + &res_x.try_into().expect("Expected 32 bytes"), + ); + res.y = FieldElement::from_bytes_unchecked_le( + &res_y.try_into().expect("Expected 32 bytes"), + ); return res; }