Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: multi_scalar_multiplication #1542

Merged
merged 47 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
58f714b
fix: impl add assign fixes
ratankaliani Sep 25, 2024
fb7b26d
simplify interface
ratankaliani Sep 26, 2024
139e0aa
fix
ratankaliani Sep 26, 2024
72f2ce1
add
ratankaliani Sep 26, 2024
31dd34c
add
ratankaliani Sep 26, 2024
7511026
fix
ratankaliani Sep 26, 2024
5595ce4
add complete_add_assign
ratankaliani Sep 26, 2024
6788449
cool
ratankaliani Sep 26, 2024
8b64f72
secp256k1 new test works
ratankaliani Sep 26, 2024
ceb6046
mostly works test, besides negation
ratankaliani Sep 26, 2024
348e04e
add secp256k1_add tests
ratankaliani Sep 27, 2024
962f21c
negation
ratankaliani Sep 27, 2024
0dd2b0c
add
ratankaliani Sep 27, 2024
1a04984
fix: cleanup test
ratankaliani Sep 27, 2024
e50336c
add new tests
ratankaliani Sep 27, 2024
dddb750
feat: remove from cargo.toml
ratankaliani Sep 30, 2024
47a535d
remove
ratankaliani Sep 30, 2024
9a4cf35
feat: use complete add assign
ratankaliani Sep 30, 2024
c3fe802
fix
ratankaliani Sep 30, 2024
4345cdc
add crates
ratankaliani Sep 30, 2024
5d2ad54
feat: use modulo arithmetic
ratankaliani Oct 1, 2024
c80e28c
patch-testing fixes
ratankaliani Oct 1, 2024
19b90e7
simplify, remove modular negation
ratankaliani Oct 1, 2024
0b9b9e4
feat: add test
ratankaliani Oct 1, 2024
50a6a12
feat: patch-testing
ratankaliani Oct 1, 2024
8c09e2f
feat: add complete add assign
ratankaliani Oct 1, 2024
fca35e9
remove unused deps
ratankaliani Oct 1, 2024
d97973e
reset
ratankaliani Oct 1, 2024
2d407c3
note
ratankaliani Oct 1, 2024
a107f4e
fix
ratankaliani Oct 1, 2024
50a5ca1
update test to avoid negate
ratankaliani Oct 1, 2024
63a56b5
feat: clean up test
ratankaliani Oct 1, 2024
3e30491
fix: docs
ratankaliani Oct 1, 2024
9f30133
add
ratankaliani Oct 1, 2024
1633c88
fix cases
ratankaliani Oct 1, 2024
d2e5cea
impl Weierstrass for secp256k1, and add the infinity point
ratankaliani Oct 2, 2024
c0cb80a
add
ratankaliani Oct 2, 2024
11cce63
spec
ratankaliani Oct 2, 2024
42868ae
wip: update patch testing program
ratankaliani Oct 3, 2024
0d0484c
feat: works with k256
ratankaliani Oct 3, 2024
6eeb466
docs
ratankaliani Oct 3, 2024
5720bfc
refactor
ratankaliani Oct 3, 2024
721cb6e
add
ratankaliani Oct 3, 2024
40cfe8d
add
ratankaliani Oct 3, 2024
b095684
add
ratankaliani Oct 3, 2024
5f113ce
lint
ratankaliani Oct 3, 2024
fec28b4
change to secp256k1point
ratankaliani Oct 3, 2024
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
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
// "tests/secp256k1-add/Cargo.toml",
// "tests/secp256k1-decompress/Cargo.toml",
// "tests/secp256k1-double/Cargo.toml",
// "tests/common/Cargo.toml",
// "tests/sha-compress/Cargo.toml",
// "tests/sha-extend/Cargo.toml",
// "tests/sha2/Cargo.toml",
Expand Down
4 changes: 0 additions & 4 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion crates/zkvm/entrypoint/src/syscalls/secp256k1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use core::arch::asm;
/// ### Safety
///
/// The caller must ensure that `p` and `q` are valid pointers to data that is aligned along a four
/// byte boundary.
/// byte boundary. Additionally, the caller must ensure that `p` and `q` are valid points on the
/// secp256k1 curve, and that `p` and `q` are not equal to each other.
#[allow(unused_variables)]
#[no_mangle]
pub extern "C" fn syscall_secp256k1_add(p: *mut [u32; 16], q: *mut [u32; 16]) {
Expand Down
6 changes: 0 additions & 6 deletions crates/zkvm/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,8 @@ keywords = { workspace = true }
categories = { workspace = true }

[dependencies]
anyhow = "1.0.83"
bincode = "1.3.3"
cfg-if = "1.0.0"
serde = { version = "1.0.204", features = ["derive"] }
amcl = { package = "snowbridge-amcl", version = "1.0.2", default-features = false, features = [
"bls381",
] }
hex = "0.4.3"

[features]
default = []
Expand Down
45 changes: 35 additions & 10 deletions crates/zkvm/lib/src/secp256k1.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
use crate::{syscall_secp256k1_add, syscall_secp256k1_double, utils::AffinePoint};
use crate::{
syscall_secp256k1_add, syscall_secp256k1_double,
utils::{AffinePoint, WeierstrassAffinePoint, WeierstrassPoint},
};

/// The number of limbs in [Secp256k1AffinePoint].
/// The number of limbs in [Secp256k1Point].
pub const N: usize = 16;

/// An affine point on the Secp256k1 curve.
#[derive(Copy, Clone)]
#[repr(align(4))]
pub struct Secp256k1AffinePoint(pub [u32; N]);
pub struct Secp256k1Point(pub WeierstrassPoint<N>);

impl AffinePoint<N> for Secp256k1AffinePoint {
impl WeierstrassAffinePoint<N> for Secp256k1Point {
fn infinity() -> Self {
Self(WeierstrassPoint::Infinity)
}

fn is_infinity(&self) -> bool {
matches!(self.0, WeierstrassPoint::Infinity)
}
}

impl AffinePoint<N> for Secp256k1Point {
/// The values are taken from https://en.bitcoin.it/wiki/Secp256k1.
const GENERATOR: [u32; N] = [
385357720, 1509065051, 768485593, 43777243, 3464956679, 1436574357, 4191992748, 2042521214,
Expand All @@ -17,15 +30,25 @@ impl AffinePoint<N> for Secp256k1AffinePoint {
];

fn new(limbs: [u32; N]) -> Self {
Self(limbs)
Self(WeierstrassPoint::Affine(limbs))
}

fn limbs_ref(&self) -> &[u32; N] {
&self.0
match &self.0 {
WeierstrassPoint::Infinity => panic!("Infinity point has no limbs"),
WeierstrassPoint::Affine(limbs) => limbs,
}
}

fn limbs_mut(&mut self) -> &mut [u32; N] {
&mut self.0
match &mut self.0 {
WeierstrassPoint::Infinity => panic!("Infinity point has no limbs"),
WeierstrassPoint::Affine(limbs) => limbs,
}
}

fn complete_add_assign(&mut self, other: &Self) {
self.weierstrass_add_assign(other);
}

fn add_assign(&mut self, other: &Self) {
Expand All @@ -37,9 +60,11 @@ impl AffinePoint<N> for Secp256k1AffinePoint {
}

fn double(&mut self) {
let a = self.limbs_mut();
unsafe {
syscall_secp256k1_double(a);
match &mut self.0 {
WeierstrassPoint::Infinity => (),
WeierstrassPoint::Affine(limbs) => unsafe {
syscall_secp256k1_double(limbs);
},
}
}
}
77 changes: 74 additions & 3 deletions crates/zkvm/lib/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub trait AffinePoint<const N: usize>: Clone + Sized {
/// Returns a reference to the limbs.
fn limbs_ref(&self) -> &[u32; N];

/// Returns a mutable reference to the limbs.
/// Returns a mutable reference to the limbs. If the point is the infinity point, this will panic.
fn limbs_mut(&mut self) -> &mut [u32; N];

/// Creates a new [`AffinePoint`] from the given x and y coordinates.
Expand Down Expand Up @@ -47,6 +47,12 @@ pub trait AffinePoint<const N: usize>: Clone + Sized {
/// Adds the given [`AffinePoint`] to `self`.
fn add_assign(&mut self, other: &Self);

/// Adds the given [`AffinePoint`] to `self`. Can be optionally overriden to use a different
/// implementation of addition in multi-scalar multiplication, which is used in secp256k1 recovery.
fn complete_add_assign(&mut self, other: &Self) {
self.add_assign(other);
}

/// Doubles `self`.
fn double(&mut self);

Expand Down Expand Up @@ -87,20 +93,23 @@ pub trait AffinePoint<const N: usize>: Clone + Sized {
b_bits_le: &[bool],
b: Self,
) -> Option<Self> {
// The length of the bit vectors must be the same.
debug_assert!(a_bits_le.len() == b_bits_le.len());

let mut res: Option<Self> = None;
let mut temp_a = a.clone();
let mut temp_b = b.clone();
for (a_bit, b_bit) in a_bits_le.iter().zip(b_bits_le.iter()) {
if *a_bit {
match res.as_mut() {
Some(res) => res.add_assign(&temp_a),
Some(res) => res.complete_add_assign(&temp_a),
None => res = Some(temp_a.clone()),
};
}

if *b_bit {
match res.as_mut() {
Some(res) => res.add_assign(&temp_b),
Some(res) => res.complete_add_assign(&temp_b),
None => res = Some(temp_b.clone()),
};
}
Expand Down Expand Up @@ -130,3 +139,65 @@ pub fn bytes_to_words_le(bytes: &[u8]) -> Vec<u32> {
.map(|chunk| u32::from_le_bytes(chunk.try_into().unwrap()))
.collect::<Vec<_>>()
}

#[derive(Copy, Clone)]
/// A representation of a point on a Weierstrass curve.
pub enum WeierstrassPoint<const N: usize> {
Infinity,
Affine([u32; N]),
}

/// A trait for affine points on Weierstrass curves.
pub trait WeierstrassAffinePoint<const N: usize>: AffinePoint<N> {
/// The infinity point representation of the Weierstrass curve. Typically an enum variant.
fn infinity() -> Self;

/// Returns true if the point is the infinity point.
fn is_infinity(&self) -> bool;

/// Performs the complete addition of two [`AffinePoint`]'s on a Weierstrass curve.
/// For an addition of two points P1 and P2, the cases are:
/// 1. P1 is infinity
/// 2. P2 is infinity
/// 3. P1 equals P2
/// 4. P1 is the negation of P2
/// 5. Default addition.
///
/// Implements the complete addition cases according to the
/// [Zcash complete addition spec](https://zcash.github.io/halo2/design/gadgets/ecc/addition.html#complete-addition).
fn weierstrass_add_assign(&mut self, other: &Self) {
// Case 1: p1 is infinity.
if self.is_infinity() {
*self = other.clone();
return;
}

// Case 2: p2 is infinity.
if other.is_infinity() {
return;
}

// Once it's known the points are not infinity, their limbs can be safely used.
let p1 = self.limbs_mut();
let p2 = other.limbs_ref();

// Case 3: p1 equals p2.
if p1 == p2 {
self.double();
return;
}

// Case 4: p1 is the negation of p2.
// Note: If p1 and p2 are valid elliptic curve points, and p1.x == p2.x, that means that
// either p1.y == p2.y or p1.y + p2.y == p. Because we are past Case 4, we know that p1.y !=
// p2.y, so we can just check if p1.x == p2.x. Therefore, this implictly checks that
// p1.x == p2.x AND p1.y + p2.y == p without modular negation.
if p1[..N / 2] == p2[..N / 2] {
*self = Self::infinity();
return;
}

// Case 5: Default addition.
self.add_assign(other);
}
}
57 changes: 44 additions & 13 deletions examples/Cargo.lock

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

6 changes: 5 additions & 1 deletion examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,13 @@ sp1-zkvm = { path = "../crates/zkvm/entrypoint", default-features = false }
[patch.crates-io]
curve25519-dalek = { git = "https://github.com/sp1-patches/curve25519-dalek", branch = "patch-curve25519-v4.1.3" }
curve25519-dalek-ng = { git = "https://github.com/sp1-patches/curve25519-dalek-ng", branch = "patch-v4.1.1" }
ecdsa-core = { git = "https://github.com/sp1-patches/signatures", package = "ecdsa", branch = "patch-ecdsa-v0.16.9" }
# ecdsa-core = { git = "https://github.com/sp1-patches/signatures", package = "ecdsa", branch = "patch-ecdsa-v0.16.8" }
# Note: This branch of ecdsa-core points to SP1 branch ratan/impl-add-assign-fixes
ecdsa-core = { git = "https://github.com/sp1-patches/signatures", package = "ecdsa", branch = "ratan/secp256k1-add-fixes-v0.16.8" }
ed25519-consensus = { git = "https://github.com/sp1-patches/ed25519-consensus", branch = "patch-v2.1.0" }
secp256k1 = { git = "https://github.com/sp1-patches/rust-secp256k1", branch = "patch-secp256k1-v0.29.0" }
sha2-v0-10-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-v0.10.8" }
sha2-v0-10-6 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.10.6" }
sha2-v0-9-9 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.9.9" }
sha2-v0-9-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.9.8" }
tiny-keccak = { git = "https://github.com/sp1-patches/tiny-keccak", branch = "patch-v2.0.2" }
Binary file modified examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf
Binary file not shown.
Loading
Loading