K256
The K256 guest library uses openvm-ecc-guest
to provide elliptic curve operations over the Secp256k1 curve. It is intended as a patch for the k256
rust crate and can be swapped in for accelerated signature verification usage. Note that signing from a private key is not supported.
Example program
See a working example here.
To use the K256 guest library, add the following dependencies to Cargo.toml
:
openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git" }
openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git" }
openvm-k256 = { git = "https://github.com/openvm-org/openvm.git", package = "k256" }
The guest library provides a Secp256k1Coord
, which represents a field element on the coordinate field of Secp256k1, and a Secp256k1Point
, which represents an Secp256k1 elliptic curve point.
The K256 guest library handles the "Declare" phase described in Optimizing Modular Arithmetic. The consuming guest program is responsible for running the "Init" phase via openvm::init!()
.
use hex_literal::hex;
use openvm_algebra_guest::IntMod;
use openvm_ecc_guest::weierstrass::WeierstrassPoint;
use openvm_k256::{Secp256k1Coord, Secp256k1Point};
openvm::init!();
/* The init! macro will expand to the following
openvm_algebra_guest::moduli_macros::moduli_init! {
"0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F",
"0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141"
}
openvm_ecc_guest::sw_macros::sw_init! {
Secp256k1Point,
}
*/
moduli_init!
is called for both the coordinate and scalar field because they were declared in the k256
module, although we will not be using the scalar field below.
With the above we can start doing elliptic curve operations like adding points:
pub fn main() {
let x1 = Secp256k1Coord::from_u32(1);
let y1 = Secp256k1Coord::from_le_bytes_unchecked(&hex!(
"EEA7767E580D75BC6FDD7F58D2A84C2614FB22586068DB63B346C6E60AF21842"
));
let p1 = Secp256k1Point::from_xy_nonidentity(x1, y1).unwrap();
let x2 = Secp256k1Coord::from_u32(2);
let y2 = Secp256k1Coord::from_le_bytes_unchecked(&hex!(
"D1A847A8F879E0AEE32544DA5BA0B3BD1703A1F52867A5601FF6454DD8180499"
));
let p2 = Secp256k1Point::from_xy_nonidentity(x2, y2).unwrap();
#[allow(clippy::op_ref)]
let _p3 = &p1 + &p2;
}
Config parameters
For the guest program to build successfully, all used moduli and curves must be declared in the .toml
config file in the following format:
[app_vm_config.modular]
supported_moduli = ["115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337"]
[[app_vm_config.ecc.supported_curves]]
struct_name = "Secp256k1Point"
modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663"
scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337"
a = "0"
b = "7"
The supported_moduli
parameter is a list of moduli that the guest program will use. As mentioned in the algebra extension chapter, the order of moduli in [app_vm_config.modular]
must match the order in the moduli_init!
macro.
The ecc.supported_curves
parameter is a list of supported curves that the guest program will use. They must be provided in decimal format in the .toml
file. For multiple curves create multiple [[app_vm_config.ecc.supported_curves]]
sections. The order of curves in [[app_vm_config.ecc.supported_curves]]
must match the order in the sw_init!
macro.
Also, the struct_name
field must be the name of the elliptic curve struct created by sw_declare!
.
In this example, the Secp256k1Point
struct is created in openvm_ecc_guest::k256
.