Skip to content
Merged
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
55 changes: 50 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions k256/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ serdect = { version = "0.2", optional = true, default-features = false }
sha2 = { version = "0.10", optional = true, default-features = false }
signature = { version = "2", optional = true }

[target.'cfg(all(target_os = "zkvm", target_arch = "riscv32"))'.dependencies]
risc0-bigint2 = { version = "1.2", features = ["unstable"] }
bytemuck = "1"

[dev-dependencies]
blobby = "0.3"
ecdsa-core = { version = "0.16", package = "ecdsa", default-features = false, features = ["dev"] }
Expand Down
59 changes: 59 additions & 0 deletions k256/src/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,65 @@ pub(crate) const CURVE_EQUATION_B: FieldElement = FieldElement::from_bytes_unche
0, 0, 0, 0, 0, 0, 0, CURVE_EQUATION_B_SINGLE as u8,
]);

#[cfg(all(target_os = "zkvm", target_arch = "riscv32"))]
use risc0_bigint2::ec;

#[cfg(all(target_os = "zkvm", target_arch = "riscv32"))]
use ecdsa_core::elliptic_curve::group::prime::PrimeCurveAffine;

#[cfg(all(target_os = "zkvm", target_arch = "riscv32"))]
pub(crate) fn affine_to_bigint2_affine(
affine: &AffinePoint,
) -> ec::AffinePoint<8, ec::Secp256k1Curve> {
if affine.is_identity().into() {
return ec::AffinePoint::IDENTITY;
}
let mut buffer = [[0u32; 8]; 2];
// TODO this could potentially read from internal repr (check risc0 felt endianness)
let mut x_bytes: [u8; 32] = affine.x.to_bytes().into();
let mut y_bytes: [u8; 32] = affine.y.to_bytes().into();
x_bytes.reverse();
y_bytes.reverse();

let x = bytemuck::cast::<_, [u32; 8]>(x_bytes);
let y = bytemuck::cast::<_, [u32; 8]>(y_bytes);
ec::AffinePoint::new_unchecked(x, y)
}

#[cfg(all(target_os = "zkvm", target_arch = "riscv32"))]
pub(crate) fn projective_to_affine(p: &ProjectivePoint) -> ec::AffinePoint<8, ec::Secp256k1Curve> {
let aff = p.to_affine();
affine_to_bigint2_affine(&aff)
}

#[cfg(all(target_os = "zkvm", target_arch = "riscv32"))]
pub(crate) fn affine_to_projective(
affine: &ec::AffinePoint<8, ec::Secp256k1Curve>,
) -> ProjectivePoint {
if let Some(value) = affine.as_u32s() {
let mut x = bytemuck::cast::<_, [u8; 32]>(value[0]);
let mut y = bytemuck::cast::<_, [u8; 32]>(value[1]);
x.reverse();
y.reverse();

crate::AffinePoint::new(
FieldElement::from_bytes_unchecked(&x),
FieldElement::from_bytes_unchecked(&y),
)
.into()
} else {
ProjectivePoint::IDENTITY
}
}

#[cfg(all(target_os = "zkvm", target_arch = "riscv32"))]
pub(crate) fn scalar_to_words(s: &Scalar) -> [u32; 8] {
let mut bytes: [u8; 32] = s.to_bytes().into();
// U256 is big endian, need to flip to little endian.
bytes.reverse();
bytemuck::cast::<_, [u32; 8]>(bytes)
}

#[cfg(test)]
mod tests {
use super::CURVE_EQUATION_B;
Expand Down
38 changes: 38 additions & 0 deletions k256/src/arithmetic/mul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,44 @@ impl LinearCombination<[(ProjectivePoint, Scalar)]> for ProjectivePoint {
}
}

#[cfg(all(target_os = "zkvm", target_arch = "riscv32"))]
use risc0_bigint2::ec;

#[cfg(all(target_os = "zkvm", target_arch = "riscv32"))]
use super::{affine_to_projective, projective_to_affine, scalar_to_words};

#[cfg(all(target_os = "zkvm", target_arch = "riscv32"))]
fn lincomb(
xks: &[(ProjectivePoint, Scalar)],
tables: &mut [(LookupTable, LookupTable)],
digits: &mut [(Radix16Decomposition<33>, Radix16Decomposition<33>)],
) -> ProjectivePoint {
let mut xks_iter = xks
.iter()
.map(|(p, s)| (projective_to_affine(p), scalar_to_words(s)));
let Some((affine, scalar)) = xks_iter.next() else {
return ProjectivePoint::IDENTITY;
};

let mut result = ec::AffinePoint::new_unchecked([0u32; 8], [0u32; 8]);
affine.mul(&scalar, &mut result);
let mut buffer = ec::AffinePoint::new_unchecked([0u32; 8], [0u32; 8]);
let mut mul_buffer = ec::AffinePoint::new_unchecked([0u32; 8], [0u32; 8]);

let mut result_ptr = &mut result;
let mut buffer_ptr = &mut buffer;

for (point, scalar) in xks_iter {
point.mul(&scalar, &mut mul_buffer);
result_ptr.add(&mul_buffer, &mut buffer_ptr);
core::mem::swap(&mut result_ptr, &mut buffer_ptr);
}

// Convert the final result back to projective form
affine_to_projective(result_ptr)
}

#[cfg(not(all(target_os = "zkvm", target_arch = "riscv32")))]
fn lincomb(
xks: &[(ProjectivePoint, Scalar)],
tables: &mut [(LookupTable, LookupTable)],
Expand Down
Loading