Skip to content

Commit

Permalink
fix: use builtin to_bits for mul
Browse files Browse the repository at this point in the history
  • Loading branch information
shuklaayush committed May 12, 2023
1 parent 32c62d5 commit a04e78a
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 55 deletions.
42 changes: 16 additions & 26 deletions crates/nargo_cli/tests/test_data/eddsa/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,20 @@ use dep::std;
fn main(msg: pub Field, _priv_key_a: Field, _priv_key_b: Field) {
// Skip this test for non-bn254 backends
if compat::is_bn254() {
// let bjj = baby_jubjub();
let bjj = baby_jubjub();

// let pub_key_a = bjj.curve.mul(priv_key_a, bjj.curve.gen);
let pub_key_a_x = 5958787406588418500595239545974275039455545059833263445973445578199987122248;
let pub_key_a_y = 6291453822075498887551694851992571215511219854100590306020486222643399599966;
// let pub_key_b = bjj.curve.mul(priv_key_b, bjj.curve.gen);
// let pub_key_b_x = 19522885864221102065733517599414632594441624981666469001809339503157461222552;
// let pub_key_b_y = 17652333933129211461240983013989988903130120700742832943186712581416334147739;
let pub_key_a = bjj.curve.mul(_priv_key_a, bjj.curve.gen);
// let pub_key_b = bjj.curve.mul(_priv_key_b, bjj.curve.gen);

// Manually computed as fields can't use modulo. Importantantly the commitment is within
// the subgroup order. Note that choice of hash is flexible for this step.
// let r_a = hash::pedersen([priv_key_a, msg])[0] % bjj.suborder; // modulus computed manually
// let r_a = 161490627844314967434218537112044327531827991364156693670922373984031106453;
// let r_b = hash::pedersen([priv_key_b, msg])[0] % bjj.suborder; // modulus computed manually
// let r_b = 2365791308032549643506220161686150043336029213998559307390193647484103923348;
// let r_a = hash::pedersen([_priv_key_a, msg])[0] % bjj.suborder; // modulus computed manually
let r_a = 1414770703199880747815475415092878800081323795074043628810774576767372531818;
// let r_b = hash::pedersen([_priv_key_b, msg])[0] % bjj.suborder; // modulus computed manually
let r_b = 571799555715456644614141527517766533395606396271089506978608487688924659618;

// let r8_a = bjj.curve.mul(r_a, bjj.base8);
let r8_a_x = 12701037151626467441858303530846040756656970729849074442899237454651294526343;
let r8_a_y = 167159699056112791619442377873552194056131231335147805875057144366514712633;
// let r8_b = bjj.curve.mul(r_b, bjj.base8);
let r8_b_x = 1673844937671191161222451342456048355167330081367086809349241319413342408558;
let r8_b_y = 6202873177260205770199785557298715091502981852957429177245493218486919053107;
let r8_a = bjj.curve.mul(r_a, bjj.base8);
let r8_b = bjj.curve.mul(r_b, bjj.base8);

// let perm_a: [Field; 6] = hash::poseidon::bn254::perm::x5_6([
// 0,
Expand All @@ -39,7 +31,6 @@ fn main(msg: pub Field, _priv_key_a: Field, _priv_key_b: Field) {
// msg,
// ]);
// let h_a = perm_a[0];
// let h_a = 21371027913064755721489810138902574499031056361794273463577587174578008711057;

// let perm_b: [Field; 6] = hash::poseidon::bn254::perm::x5_6([
// 0,
Expand All @@ -50,20 +41,19 @@ fn main(msg: pub Field, _priv_key_a: Field, _priv_key_b: Field) {
// msg,
// ]);
// let h_b = perm_b[0];
// let h_b = 15015879520414293281817167314697737785772315344690416596928480331452621620489;

// let s_a = (r_a + priv_key_a * h_a) % bjj.suborder; // modulus computed manually
let s_a = 960;
// let s_b = (r_b + priv_key_b * h_b) % bjj.suborder; // modulus computed manually
let s_b = 3562;
// let s_a = (r_a + _priv_key_a * h_a) % bjj.suborder; // modulus computed manually
let s_a = 30333430637424319196043722294837632681219980330991241982145549329256671548;
// let s_b = (r_b + _priv_key_b * h_b) % bjj.suborder; // modulus computed manually
let s_b = 1646085314320208098241070054368798527940102577261034947654839408482102287019;

// User A verifies their signature over the message
constrain eddsa_poseidon_verify(pub_key_a_x, pub_key_a_y, s_a, r8_a_x, r8_a_y, msg);
assert(eddsa_poseidon_verify(pub_key_a.x, pub_key_a.y, s_a, r8_a.x, r8_a.y, msg));

// User B's signature over the message can't be used with user A's pub key
constrain !eddsa_poseidon_verify(pub_key_a_x, pub_key_a_y, s_b, r8_b_x, r8_b_y, msg);
assert(!eddsa_poseidon_verify(pub_key_a.x, pub_key_a.y, s_b, r8_b.x, r8_b.y, msg));

// User A's signature over the message can't be used with another message
constrain !eddsa_poseidon_verify(pub_key_a_x, pub_key_a_y, s_a, r8_a_x, r8_a_y, msg + 1);
assert(!eddsa_poseidon_verify(pub_key_a.x, pub_key_a.y, s_a, r8_a.x, r8_a.y, msg + 1));
}
}
16 changes: 1 addition & 15 deletions noir_stdlib/src/ec.nr
Original file line number Diff line number Diff line change
Expand Up @@ -150,20 +150,6 @@ global C5 = 19103219067921713944291392827692070036145651957329286315305642004821
// out
//}

// Converts Field element to little-endian bit array of length N_BITS
// TODO: Fix built-in to_le_bits(., N_BITS), which yields a 128-periodic bit array
fn to_bits(x: Field) -> [u1; N_BITS] {
let mut x = x;
let mut out = [0; N_BITS];
for i in 0..N_BITS {
if x != 0 {
out[i] = x as u1;
x = (x - out[i] as Field)/2;
}
}
out
}

// TODO: Make this built-in.
fn safe_inverse(x: Field) -> Field {
if x == 0 {
Expand All @@ -184,7 +170,7 @@ fn is_square(x: Field) -> bool {
// Adapted from std::field::pow_32.
fn pow(x: Field, y: Field) -> Field { // As in tests with minor modifications
let mut r = 1 as Field;
let b = to_bits(y);
let b = y.to_le_bits(N_BITS as u32);

for i in 0..N_BITS {
r *= r;
Expand Down
7 changes: 4 additions & 3 deletions noir_stdlib/src/ec/consts/te.nr
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ struct BabyJubjub {
}

fn baby_jubjub() -> BabyJubjub {
constrain compat::is_bn254();
assert(compat::is_bn254());

BabyJubjub {
// Baby Jubjub (ERC-2494) parameters in affine representation
curve: TECurve::new(
168700,
168696,
// G
TEPoint::new(
5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203,
995203441582195749578291179787384436505546430278305826713579947235728471134,
5472060717959818805561601436314318772137091100104008585924551046643952123905,
),
),
// [8]G precalculated
Expand Down
15 changes: 12 additions & 3 deletions noir_stdlib/src/ec/swcurve.nr
Original file line number Diff line number Diff line change
Expand Up @@ -344,11 +344,20 @@ mod curvegroup {

// Scalar multiplication (p + ... + p n times)
fn mul(self, n: Field, p: Point) -> Point {
let n_as_bits = crate::ec::to_bits(n); // N_BITS-bit representation
let N_BITS = crate::field::modulus_num_bits();

self.bit_mul(n_as_bits, p)
let mut out = Point::zero();
let n_as_bits = n.to_le_bits(N_BITS as u32); // N_BITS-bit representation

for i in 0..N_BITS {
out = self.add(
self.add(out, out),
if(n_as_bits[N_BITS - i - 1] == 0) {Point::zero()} else {p});
}

out
}

// Multi-scalar multiplication (n[0]*p[0] + ... + n[N]*p[N], where * denotes scalar multiplication)
fn msm<N>(self, n: [Field; N], p: [Point; N]) -> Point {
let mut out = Point::zero();
Expand Down
15 changes: 12 additions & 3 deletions noir_stdlib/src/ec/tecurve.nr
Original file line number Diff line number Diff line change
Expand Up @@ -370,11 +370,20 @@ mod curvegroup {

// Scalar multiplication (p + ... + p n times)
fn mul(self, n: Field, p: Point) -> Point {
let n_as_bits = crate::ec::to_bits(n); // N_BITS-bit representation
let N_BITS = crate::field::modulus_num_bits();

self.bit_mul(n_as_bits, p)
let mut out = Point::zero();
let n_as_bits = n.to_le_bits(N_BITS as u32); // N_BITS-bit representation

for i in 0..N_BITS {
out = self.add(
self.add(out, out),
if(n_as_bits[N_BITS - i - 1] == 0) {Point::zero()} else {p});
}

out
}

// Multi-scalar multiplication (n[0]*p[0] + ... + n[N]*p[N], where * denotes scalar multiplication)
fn msm<N>(self, n: [Field; N], p: [Point; N]) -> Point {
let mut out = Point::zero();
Expand Down
10 changes: 5 additions & 5 deletions noir_stdlib/src/eddsa.nr
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ fn eddsa_poseidon_verify(
let bjj = baby_jubjub();

let pub_key = TEPoint::new(pub_key_x, pub_key_y);
constrain bjj.curve.contains(pub_key);
assert(bjj.curve.contains(pub_key));

let signature_r8 = TEPoint::new(signature_r8_x, signature_r8_y);
constrain bjj.curve.contains(signature_r8);
assert(bjj.curve.contains(signature_r8));

// Ensure S < Subgroup Order
constrain field::lt_bytes32(signature_s, bjj.suborder);
assert(field::lt_bytes32(signature_s, bjj.suborder));

// Calculate the h = H(R,A, msg)
// Calculate the h = H(R, A, msg)
let perm: [Field; 6] = poseidon::bn254::perm::x5_6([
0,
signature_r8_x,
Expand All @@ -44,7 +44,7 @@ fn eddsa_poseidon_verify(
let pub_key_mul_8 = bjj.curve.add(pub_key_mul_4, pub_key_mul_4);

// We check that A8 is not zero.
constrain !pub_key_mul_8.is_zero();
assert(!pub_key_mul_8.is_zero());

// Compute the right side: R8 + h * A8
let right = bjj.curve.add(signature_r8, bjj.curve.mul(hash, pub_key_mul_8));
Expand Down

0 comments on commit a04e78a

Please sign in to comment.